[ {"url": "https://pingcap.com/cases-cn/user-case-xiaomi/", "title": "TiDB 在小米的应用实践", "content": " 作者:张良,小米 DBA 负责人;潘友飞,小米 DBA;王必文,小米开发工程师。 一、应用场景介绍 MIUI 是小米公司旗下基于 Android 系统深度优化、定制、开发的第三方手机操作系统,也是小米的第一个产品。MIUI 在 Android 系统基础上,针对中国用户进行了深度定制,在此之上孕育出了一系列的应用,比如主题商店、小米音乐、应用商店、小米阅读等。图 1 MIUI Android 系统界面图目前 TiDB 主要应用在: 小米手机桌面负一屏的快递业务 商业广告交易平台素材抽审平台 这两个业务场景每天读写量均达到上亿级,上线之后,整个服务稳定运行;接下来我们计划逐步上线更多的业务场景,小米阅读目前正在积极的针对订单系统做迁移测试。二、TiDB 特点 TiDB 结合了传统的 RDBMS 和 NoSQL 的最佳特性,兼容 MySQL 协议,支持无限的水平扩展,具备强一致性和高可用性。具有如下的特性: 高度兼容 MySQL,大多数情况下无需修改代码即可从 MySQL 轻松迁移至 TiDB,即使已经分库分表的 MySQL 集群亦可通过 TiDB 提供的迁移工具进行实时迁移。 水平弹性扩展,通过简单地增加新节点即可实现 TiDB 的水平扩展,按需扩展吞吐或存储,轻松应对高并发、海量数据场景。 分布式事务,TiDB 100% 支持标准的 ACID 事务。 真正金融级高可用,相比于传统主从(M-S)复制方案,基于 Raft 的多数派选举协议可以提供金融级的 100% 数据强一致性保证,且在不丢失大多数副本的前提下,可以实现故障的自动恢复(auto-failover),无需人工介入。 TiDB 的架构及原理在 官网 里有详细介绍,这里不再赘述。图 2 TiDB 基础架构图三、背景 跟绝大数互联网公司一样,小米关系型存储数据库首选 MySQL,单机 2.6T 磁盘。由于小米手机销量的快速上升和 MIUI 负一屏用户量的快速增加,导致负一屏快递业务数据的数据量增长非常快, 每天的读写量级均分别达到上亿级别,数据快速增长导致单机出现瓶颈,比如性能明显下降、可用存储空间不断降低、大表 DDL 无法执行等,不得不面临数据库扩展的问题。 比如,我们有一个业务场景(智能终端),需要定时从几千万级的智能终端高频的向数据库写入各种监控及采集数据,MySQL 基于 Binlog 的单线程复制模式,很容易造成从库延迟,并且堆积越来越严重。对于 MySQL 来讲,最直接的方案就是采用分库分表的水平扩展方式,综合来看并不是最优的方案,比如对于业务来讲,对业务代码的侵入性较大;对于 DBA 来讲提升管理成本,后续需要不断的拆分扩容,即使有中间件也有一定的局限性。 同样是上面的智能终端业务场景,从业务需求看,需要从多个业务维度进行查询,并且业务维度可能随时进行扩展,分表的方案基本不能满足业务的需求。了解到 TiDB 特点之后,DBA 与业务开发沟通确认当前 MySQL 的使用方式,并与 TiDB 的兼容性做了详细对比,经过业务压测之后,根据压测的结果,决定尝试将数据存储从 MySQL 迁移到 TiDB。经过几个月的线上考验,TiDB 的表现达到预期。四、兼容性对比 TiDB 支持包括跨行事务、JOIN、子查询在内的绝大多数 MySQL 的语法,可以直接使用 MySQL 客户端连接;对于已用 MySQL 的业务来讲,基本可以无缝切换到 TiDB。二者简单对比如下几方面: 功能支持 TiDB 尚不支持如下几项: 增加、删除主键 非 UTF8 字符集 视图(即将支持)、存储过程、触发器、部分内置函数 Event 全文索引、空间索引 默认设置 字符集、排序规则、sql_mode、lower_case_table_names 几项默认值不同。 事务 TiDB 使用乐观事务模型,提交后注意检查返回值。 TiDB 限制单个事务大小,保持事务尽可能的小。 TiDB 支持绝大多数的 Online DDL。 另,一些 MySQL 语法在 TiDB 中可以解析通过,不会产生任何作用,例如: create table 语句中 engine、partition 选项都是在解析后忽略。 详细信息可以访问官网:https://pingcap.com/docs-cn/sql/mysql-compatibility/ 。 五、压测 5.1 目的 通过压测 TiDB 了解一下其 OLTP 性能,看是否满足业务要求。5.2 机器配置 组件 实例数量 CPU 型号 内存 磁盘 版本 操作系统 TiDB 3 Intel® Xeon® CPU E5-2620 v3 @ 2.40GHz 128G SSD Raid 5 2.0.3 CentOS Linux release 7.3.1611 PD 3 Intel® Xeon® CPU E5-2620 v3 @ 2.40GHz 128G SSD Raid 5 2.0.3 CentOS Linux release 7.3.1611 TiKV 4 Intel® Xeon® CPU E5-2620 v3 @ 2.40GHz 128G SSD Raid 5 2.0.3 CentOS Linux release 7.3.1611 5.3 压测内容以及结果 5.3.1 标准 Select 压测 Threads QPS Latency (avg / .95 / max) 8 12650.81 0.63 / 0.90 / 15.62 16 21956.21 0.73 / 1.50 / 15.71 32 31534.8 1.01 / 2.61 / 25.16 64 38217 1.67 / 5.37 / 49.80 128 39943.05 3.20 / 8.43 / 58.60 256 40920.64 6.25 / 13.70 / 95.13 图 3 标准 Select 压测图5.3.2 标准 OLTP 压测 Threads TPS QPS Latency (avg / .95 / max) 8 428.9 8578.09 18.65 / 21.89 / 116.06 16 731.67 14633.35 21.86 / 25.28 / 120.59 32 1006.43 20128.59 31.79 / 38.25 / 334.92 64 1155.44 23108.9 55.38 / 71.83 / 367.53 128 1121.55 22431 114.12 / 161.51 / 459.03 256 941.26 18825.1 271.94 / 369.77 / 572.88 图 4 标准 OLTP 压测图5.3.3 标准 Insert 压测 | Threads | QPS | Latency (avg / .95 / max) | |:—|:—|:—————| | 8 | 3625.75 | 2.20 / 2.71 / 337.94 | | 16 | 6527.24 | 2.45 / 3.55 / 160.84 | | 32 | 10307.66 | 3.10 / 4.91 / 332.41 | | 64 | 13662.83 | 4.68 / 7.84 / 467.56 | | 128 | 15100.44 | 8.47 / 16.41 / 278.23 | | 256 | 17286.86 | 14.81 / 25.74 / 3146.52 |图 5 标准 Insert 压测图通过压测发现 TiDB 稳定性上与预期稍有差别,不过压测的 Load 会明显高于生产中的业务 Load,参考低 Threads 时 TiDB 的表现,基本可以满足业务对 DB 的性能要求,决定灰度一部分 MySQL 从库读流量体验一下实际效果。六、迁移过程 整个迁移分为 2 大块:数据迁移、流量迁移。6.1 数据迁移 数据迁移分为增量数据、存量数据两部分。 对于存量数据,可以使用逻辑备份、导入的方式,除了传统的逻辑导入外,官方还提供一款物理导入的工具 TiDB Lightning。 对于增量备份可以使用 TiDB 提供的 Syncer (新版已经更名为 DM - Data Migration)来保证数据同步。 Syncer 结构如图 6,主要依靠各种 Rule 来实现不同的过滤、合并效果,一个同步源对应一个 Syncer 进程,同步 Sharding 数据时则要多个 Syncer 进程。图 6 Syncer 结构图使用 Syncer 需要注意: 做好同步前检查,包含 server-id、log_bin、binlog_format 是否为 ROW、binlog_row_image 是否为 FULL、同步相关用户权限、Binlog 信息等。 使用严格数据检查模式,数据不合法则会停止。数据迁移之前最好针对数据、表结构做检查。 做好监控,TiDB 提供现成的监控方案。 对于已经分片的表同步到同一个 TiDB 集群,要做好预先检查。确认同步场景是否可以用 route-rules 表达,检查分表的唯一键、主键在数据合并后是否冲突等。 6.2 流量迁移 流量切换到 TiDB 分为两部分:读、写流量迁移。每次切换保证灰度过程,观察周期为 1~2 周,做好回滚措施。 读流量切换到 TiDB,这个过程中回滚比较简单,灰度无问题,则全量切换。 再将写入切换到 TiDB,需要考虑好数据回滚方案或者采用双写的方式(需要断掉 Syncer)。 七、集群状况 7.1 配置 集群配置采用官方推荐的 7 节点配置,3 个 TiDB 节点,3 个 PD 节点,4 个 TiKV 节点,其中每个 TiDB 与 PD 为一组,共用一台物理机。后续随着业务增长或者新业务接入,再按需添加 TiKV 节点。7.2 监控 监控采用了 TiDB 的提供的监控方案,并且也接入了公司开源的 Falcon,目前整个集群运行比较稳定,监控如图 7。 图 7 监控图八、遇到的问题、原因及解决办法 问题 原因及解决办法 在一个 DDL 里不能对多个列或者多个索引做操作。 ADD/DROP INDEX/COLUMN 操作目前不支持同时创建或删除多个索引或列,需要拆分单独执行,官方表示 3.0 版本有计划改进。 部分操作符查询优化器支持不够好,比如 or 操作符会使用 TableScan,改写成 union all 可避免。 官方表示目前使用 or 操作符确实在执行计划上有可能不准确,已经在改进计划中,后续 3.0 版本会有优化。 重启一个 PD 节点的时候,业务能捕捉到 PD 不可用的异常,会报 PD server timeout 。 因为重启的是 Leader 节点,所以重启之前需要手动切换 Leader,然后进行重启。官方建议这里可以通过重启前做 Leader 迁移来减缓,另外后续 TiDB 也会对网络通讯相关参数进行梳理和优化。 建表语句执行速度相比 MySQL 较慢 多台 TiDB 的时候,Owner 和接收 create table 语句的 TiDB Server 不在一台 Server 上时,可能比 MySQL 慢一些,每次操作耗时在 0.5s 左右,官方表示会在后续的版本中不断完善。 pd-ctl 命令行参数解析严格,多一个空格会提示语法错误。 官方表示低版本中可能会有这个问题,在 2.0.8 及以上版本已经改进。 tikv-ctl 命令手动 compact region 失败。 在低版本中通常是因为 tikv-ctl 与集群版本不一致导致的,需要更换版本一致的 tikv-ctl,官方表示在 2.1 中已经修复。 大表建索引时对业务有影响 官方建议在业务低峰期操作,在 2.1 版本中已经增加了操作优先级以及并发读的控制,情况有改善。 存储空间放大问题 该问题属于 RocksDB,RocksDB 的空间放大系数最理想的值为 1.111,官方建议在某些场景下通过 TiKV 开启 RocksDB 的 dynamic-level-bytes 以减少空间放大。 九、后续和展望 目前 TiDB 在小米主要提供 OLTP 服务,小米手机负一屏快递业务为使用 TiDB 做了一个良好的开端,而后商业广告也有接入,2 个业务均已上线数月,TiDB 的稳定性经受住了考验,带来了很棒的体验,对于后续大体的规划如下: MIUI 生态业务中存在大量的类似场景的业务,后续将会与业务开发积极沟通,从 MySQL 迁移到 TiDB。 针对某些业务场景,以资源合理利用为目标,推出归档集群,利用 Syncer 实现数据归档的功能。 数据分析,结合 TiDB 提供的工具,将支持离线、实时数据分析支持。 将 TiDB 的监控融合到小米公司开源的监控系统 Falcon 中。 十、致谢 非常感谢 TiDB 官方在迁移及业务上线期间给予我们的支持,为每一个 TiDB 人专业的精神、及时负责的响应点赞。"}, {"url": "https://pingcap.com/cases-cn/user-case-xishanju/", "title": "TiDB 在西山居实时舆情监控系统中的应用", "content": " 公司简介 西山居创建 1995 年初夏,在美丽的海滨小城珠海,西山居工作室孕育而生,一群西山居居士们十年如一日尅勊业业的奋斗。”创造快乐,传递快乐!” 一直是西山居居士们的创作宗旨。西山居以领先的技术作为坚实的基础以独特的本土化产品为玩家提供时尚化服务。在未来,西山居仍以娱乐软件为主导产品,不断进行研发和市场活动,逐步发展成为国内最优秀的集制作、发行于一体的数字化互动娱乐公司。业务背景 由于公司产品的社交属性都非常强,对相关舆情进行分析与了解就显得很有必要,在此背景下,舆情监控系统应运而生。该系统利用算法组提供的分词算法,对文本进行解析与分类,打上各类标记后再通过计算产生中间结果。舆情系统直接查询这些中间结果,产生各类报表与趋势图,为及时掌握各类舆情趋势提供便利。用户可以自由组合舆情关注点,从而对平台有很严格的实时交互性查询要求,是典型的实时 HTAP 类业务。存储技术选型 舆情系统之前我们曾经实现过一个客服系统,这个系统要求能实时查询,但面对是海量的玩家行为记录。在当时情况下(2016 年),可以选择的对象只有 MyCAT 这类数据库中间件,通过综合压力测试后,我们选定了 KingShard 这一款由公司前同事开发的中间件,KingShard 虽然没有 MyCAT 丰富的周边功能,但它在满足我们业务需求的核心功能上有更快的表现。但正因为有了这一次中间件的使用,我们对中间件有了比较全面的了解,它们在查询优化上有着天生的弱点,无法满足更复杂的查询或者表现极不友好,为此我们还不得不砍掉了客服系统的部分业务功能,所以在那时我已开始寻找更优的技术方案,其中分布式数据库是我们考察的重点方向。BigTable、GFS、MapReduce 是谷歌在分布式存储与查询领域的探索成果,他们没有公开具体实现代码,但却发布了相应论文,对分布式文件系统、大数据挖掘和 NoSQL 发展起了重大促进作用。开源界根据这一成果开发出对应产品是 HBase、HDFS、Hadoop,这三个产品红极一时,相关周边产品更是百花齐放,很多细分领域都同时出现了多个产品竞争,让整个生态非常繁荣但也变得复杂,提高了我们的学习与使用成本。那么,在一些领域中有没有更加简单、直接、具有较强融合能力的解决方案呢?此时距谷歌这三篇论文发表已近 10 年,谷歌内部早已在尝试融合 NoSQL 和 SQL,并对它们进行了多次更新换代,Spanner、F1 两篇论文便是谷歌在这一方向的探索成果。开源分布式数据库 TiDB 便是受论文启发而设计的 HTAP (Hybrid Transactional and Analytical Processing) 数据库,结合了传统的 RDBMS 和 NoSQL 的最佳特性,兼容 MySQL,具有支持分布式事务、无限的水平扩展、数据强一致性保证等核心 NewSQL 特性。当时,舆情系统接入的第一个游戏平均每天入库数据量就已达到 8500 万条,并且还需要支持各种实时交互性查询,显然中间件已不能满足要求,传统的关系型数据库则更加不可能了。考虑到以后还会有其它游戏接入,我们果断选择了分布式数据库。 随着互联网经济的发展,数据量跟并发数也在飞速增长,单机数据库已越来越不能满足要求了,为此谷歌、阿里等大厂都有了自研的分布式数据库,但都没有开源,而 MySQL 的 MGR 及相关功能进展的步子太小,TiDB 的出现很好的弥补了市场空白,成为我们的唯一选择。服务器配置 舆情系统是内部孵化项目,服务器具体如下:新购物理机器 6 台:旧物理机 4 台:我们将对资源使用相对较小的 PD、监控服务分别放在旧物理机上,TiDB、TiKV 和 TiSpark 则分配在新机器上,详细如下:其中每个 TiKV 分配 CPU 10C / 内存 64G / 硬盘 2T,每个 TiSpark 分配 CPU 20C / 内存 64G。在资源有限情况下,结合数据量及舆情系统的 AP 业务属性,我们设计了这样相对复杂的架构,目的是为了充分利用好服务器资源,让它们能承担更极限的压力,事后有多次历史数据的导入也证明了我们这样设计的必要性,多谢 TiDB 的兄弟全程耐心指导及帮助。项目开发过程 得出中间结果是一个非常大的计算过程,所以我们使用了 TiSpark。TiSpark 是 PingCAP 为解决用户复杂 OLAP 需求而推出的产品,它是将 Spark SQL 直接运行在分布式存储引擎 TiKV 上的 OLAP 解决方案。有了 TiSpark 我们可以方便地使用 Spark,而不需要再单独搭建一套 Spark 集群。从 TiDB 的 1.0 RC 3 版本开始,我们就在金山云上搭建集群来试用与压测。期间经历了多次版本热更,集群也一直很稳定,功能与性能越来越强,所以在舆情系统开始开发时我们果断使用了 TiDB。并且 TiDB 有强烈的市场需求,他们的版本更新非常迅速,在试用期间时发现了一些功能不能满足需要,往往在下一个版本就解决了,这让人非常惊叹。当前版本未加入实时计算业务,再加上使用了 TiSpark,所以整个架构相对简单,详细如下图:项目上线及使用情况 舆情系统目前总数据量数 T,已正式上线三个月,期间从未出现过异常,系统平稳、使用效果也非常好。现在每天原始文本数据在 2500 万条以上,通过算法分词后产生的中间结果则每天有 6000 万条左右(日均入库 8500 万条),高峰时段的平均 QPS 在 3K 以上,闲时的平均 QPS 为 300 多一点。根据这样的量级,在一开始评估时设定的目标是:支持最近一个星期的实时交互性查询,但现在已经远远超过我们的预期。目前所有一个月内的时间跨度查询都在 1 秒左右完成,个别复杂的 3 个月的实时交互性查询则需要 2 秒多一点。可以说 TiDB 给我们的体验远超预期,这样的数据量级及响应,单机版数据库是不可能达到要求的。 作者介绍:邹学,舆情监控系统技术负责人,珠海金山网络游戏科技有限公司(西山居)数据中心架构师,2015 年加入西山居,具有 10 年游戏行业软件开发经验,主要参与了公司的游戏网关设计,数据分析框架底层架构建设等,现专注于实时计算、爬虫、分布式系统方向。 "}, {"url": "https://pingcap.com/cases-cn/user-case-beijing-bank/", "title": "北京银行企业级 NewSQL 数据库赋能金融科技建设", "content": " 近年来,国家不断提高对信息技术安全可控的战略要求,银行业希望在快速发展业务的同时不断降低经营成本。这不仅促使商业银行积极提升自主掌控能力,也促使商业银行对基础软件的服务能力、软硬件升级成本控制提出新的要求。与此同时,面对互联网金融带来的交易复杂度及交易频次的大幅提升,商业银行信息系统采用的传统数据库一体化解决方案,在应对此类场景时遇到了明显的性能瓶颈,而提升系统性能只靠替换式的硬件升级,成本昂贵。在这种背景下,引入一种高性能、可弹性扩展、能够支持OLTP场景的数据库成为我行系统建设的优先选择方案。一、 分布式数据库的价值与应用场景 分布式事务数据库采用多种模式实现数据的分散存储,将数据库压力分散到不同服务器上。与集中式数据库相比,分布式数据库可以均衡交易负载,并采用高并发的架构提升系统的交易处理能力,而其统一的资源管理机制也使得数据库的性能扩展不再是设备的替换式升级,而是通过增加存储或计算节点来实现弹性升级,极大地节约了升级成本。虽然分布式事务数据库在互联网应用场景下的探索取得了良好的成效和大量的实战经验,积累了很多成熟的技术,但相比互联网企业,金融行业对风险控制的要求更高,所以在面对高复杂度交易场景、业务实时一致性等方面的需求时,需要更为完善的技术方案支持。目前绝大部分分布式数据库解决方案都是基于 MySQL 主从复制结合分库分表中间件方式进行改造和集成,无法提供商业银行交易场景中的强一致性和完整的分布式事务要求,对业务和应用有侵入性,需要做一定的技术调整和事务妥协,并且此类架构离银行业务场景中的高可用和多中心容灾及多活的高级别安全要求也有一定距离。所以,我行在选型前先确定了六个需要特别关注的特性:ACID 特性、横向扩展能力、可用性、可维护性、透明性、兼容性。需要特别说明的是透明性和兼容性,区域银行等体量的金融机构相比互联网企业来说科技资源有限,所以希望新的分布式数据库对架构、开发、运维的影响能够降到最低,同时能够支持传统系统的迁移。新一代分布式 NewSQL 数据库对应用透明,像一个单机数据库一样使用,支持水平扩展的同时保证分布式事务和数据的强一致性,从而避免传统分库分表、事务补偿等方案对上层应用及业务流程的影响,另一方面如果能兼容传统单机数据库,传统应用平移时不需要人工改写代码,就能极大减少迁移成本。二、具有北京银行特色的选型方案 由于金融行业对风险控制的严格要求,以及在交易复杂度、业务实时一致性等方面诉求不同于互联网企业。所以,我行对于分布式数据库的选择也比较谨慎,利用两轮专项POC评测来探索分布式数据库的适用场景及性能指标,稳步推进由传统数据库向分布式数据库的迁移。在第一轮 POC 测试中,主要进行了多场景的性能测试。由于 Sysbench 等开源测试工具对 OLTP 的性能测试存在较大的局限性,于是我行提出了“标准化交易组”的概念,用银行真实交易逻辑,模拟多表跨节点事务,最大程度的还原银行实际应用场景,检验数据库产品的实际交易性能。第二轮 POC 测试关注更为全面的数据库产品特性。在当前数据库主流评测指标的基础上,结合银行的关注要点,我行自主提出了一套“分布式事务数据库评测指标”(见图),将分布式事务数据库能力进行了分解,形成具体的指标项,使得评测标准更加标准化,评测结果更加客观。图1:分布式事务数据库评测指标选型过程中,从多维度考察了多家厂商的产品,包括 TPS、QPS 等性能指标,和算法性能、可靠性、安全备份、数据库兼容性、产品化程度等功能指标。同时,我行也得到了 Intel 实验室的大力支持,提供最新架构的计算和存储设备进行对比测试。结合两轮 POC 结果,TiDB 分布式数据库产品表现出了架构的先进性和高效的性能,水平扩展能力、交易处理能力和功能指标均符合我行对分布式数据库产品的要求。其采用的 Raft 算法保证了数据的强一致性,同时可以实现两地三中心多活的部署方式,以上特性在应用中具备较大优势。除了优秀的开源社区环境,其背后的团队在开发支持、技术培训、运维服务、成本控制等方面也表现出了优秀的素质。三、NewSQL 数据库平台的建设进展 我行在进行分布式事务数据库选型之初,就将目标定为可以承载银行核心系统与核心业务,所以选型过程和应用迁移都是基于这一目标,在数据库投产后将首先应用于互联网支付业务,之后迁移部分核心系统功能模块,并进一步扩展到其他场景的使用。其他感兴趣的用户也可以从非核心业务用起,或先作为备份数据系统。为了更好满足应用端的需求以及业务的扩展,对业务的交易量和数据量进行了预估。结合预估结果以及行内系统建设要求,北京银行率先采用了两地三中心五副本的高可用部署架构方案,支持同城两中心多活,并具备服务器级、机柜级、数据中心级容灾能力。随着业务不断发展,客户数量、账户数量、业务交易量都会上升,这对我行信息系统的数据存储能力、运算能力等方面提出了更高的要求。我行也对系统架构进行了长远规划,利用分布式 NewSQL 数据库集群的横向水平扩展能力,通过增加存储或计算节点来实现弹性升级,节约成本与实施难度。2018 年 3 月 22 日,北京银行分布式 NewSQL 数据库集群正式投产,成为国内首家采用同类方案应用于核心交易场景的银行。在数据库投产后,将进行生产环境多活和灾备的验证,并开始应用切换。四、对开源软件的一些理解 银行在开展技术能力转型建设的过程中,必然会应用越来越多的开源技术。开源软件是当前软件发展的趋势,互联网企业的大规模应用和快速迭代使开源软件成为先进技术事实上的代表。传统银行业使用开源软件的初衷是希望快速获得互联网企业同样的能力,但是否存在困难与阻碍呢?第一、大部分银行的科技资源状况使之不具备源代码级的掌控能力和基于开源组件的架构设计能力。大多选择采用由国外社区控制的软件或是直接购买国内互联网公司封装好的全家桶解决方案,很难做到真正意义的自主、安全、可控。第二、开源软件变化快、分支多、依赖“试错”的创新,跟银行追求稳健、长期的内部机制存在差异甚至冲突,反映在选型、测试、变更、运维等各个环节。第三、开源软件的极客思维更多面向开发者,而非使用者,灾备、监控、审计等企业级功能经常落后于核心功能,在培训、ISV 持、维保服务上跟传统企业的需求还有差距。所以银行业采用开源软件并取得成功的成本可能会比原有模式更高。值得欣慰的是,随着多年的技术积累,国内越来越多的类似 PingCAP 这样专注于底层核心基础软件研发的团队开始崭露头角,通过全球开源协作的方式极大的提升软件的迭代速度和成熟度,且愿意倾听传统行业的客户需求,有一颗做好产品与服务的诚心。不同于部分银行在新兴业务上采用互联网公司提供的整体外包解决方案,北京银行寻求自主可控能力,主动在模式和管理上创新,与互联网思维和技术不断切磋、碰撞、融合。通过研究、评测、应用、部署等工作,在实践中做到了自主掌控。双方在合作中互惠互利,利用双方优势,实现了信息系统服务能力的快速提升,打造出具有北京银行特色的创新驱动力。五、结语 今后我行会尝试将更多高频高并发、对可扩展性和可用性有较高要求的业务场景迁移到分布式系统上。充分发挥分布式数据库的优势,探索和开辟创新发展的新路径。同时也希望我行在分布式数据库建设过程中的经验可以分享给更多的金融机构。借此北京银行愿与各同业机构和互联网企业携手并进,为推动银行数据库应用升级贡献自己的一份力量! 作者简介于振华,北京银行软件开发部,核心系统架构管理,长期从事银行核心系统研发、规划,当前主要研发方向集中在构建先进、高效、面向OLTP的银行交易系统,提升银行信息系统服务能力。张小龙,北京银行软件开发部,核心系统架构设计,长期从事银行核心系统对公业务、中间业务模型研发、规划,软件项目管理。参与构建新型面向OLTP的银行交易系统架构设计。 "}, {"url": "https://pingcap.com/cases-cn/user-case-ekingtech/", "title": "TiDB 在海航易建科技与香港航空研发收益支持系统过程中的实践", "content": " 背景介绍 收益支持系统(Revenue Support System,简称 RSS)是海航易建科技与香港航空共同研发的基于大数据实时分析处理的航空业务支持和决策系统。RSS 的目标在于根据顾客需求进行市场细分和定价,在科学分析的基础上通过价格和座位库存控制手段平衡需求和供给的关系,将产品销售给合适的旅客,其核心价值在于支撑和帮助航空公司业务人员和决策者进行业务管理和科学决策。 RSS 在航空公司角色和定位,决定了该系统对 OLAP 和 OLTP 的操作在准确性和实时性方面具有很高的要求,并且由于航空公司每天产生海量的订票、值机、离港和财务数据,使得要求系统在数据存储方面要有很好的水平扩展能力。前期方案 前期我们主要使用 MySQL 数据库,但是单表记录大于 2000 万行时,现有的业务报表查询和导出操作明显变慢,通过各种 sql 调优和代码优化手段,也无法继续满足服务等级协议,只能通过分库分表来解决,但是这会增加的后续业务逻辑开发复杂度与数据库运维困难。后来,随着业务的深入和数据的积累,代理人在全球各个全球分销系统(Global Distribution System,GDS)中的订座数据数据(Marketing Information Data Tapes,MIDT)就近2年的数据就超过 3.8 亿行,后续会同步近 10 年的数据,初步预估单表数据量将突破10亿条数据,并且后续每年的正常量可能会突破 2 亿条,如果继续使用 MySQL,必然面临着更细粒度分库、分表的难题,而且当前业界很多分表分库的中间件对 OLAP 支持的并不完美,而且很难满足复杂的 OLAP 需求,并且需要进行分表策略的额外配置。这样必然加大了开发和运维的难度和降低了开发的灵活性。在这个过程中,我们曾经使用 HDFS + Hive + Spark + Kylin 作为大数据解决方案,但是这个方案对于实时的OLTP却满足不了。为了满足两者的需求,我们需要把一份大数据存储两份,MySQL + 分表中间件做 OLTP 操作,HDFS + Hive + Spark + Kylin 做 OLAP 分析。茅塞顿开 在业务遇到不可妥协的技术瓶颈后,我们重新评估业务模型,发现对于数据库的选型必须满足: 支持业务弹性的水平扩容与缩容; 支持 MySQL 便捷稳定的迁移,不影响线上业务; 支持 SQL 和复杂的查询,尽量少的改动代码; 满足业务故障自恢复的高可用,且易维护; 强一致的分布式事务处理; 为了解决上述问题,我们发现了 TiDB、CockroachDB 与 oceanbase 这三款分布式的数据库。由于 CockroachDB 是支持 Postgresql 数据库,我们是 MySQL 的协议,oceanbase 发布在阿里云,我们的数据属于收益核心数据需要发布在集团内部,这样一来 TiDB 成了我们选择。TiDB 数据库完美的支持了 MySQL 的 SQL 语法,它可是让我们不改变平时用 MySQL 的操作习惯。并且能够很好的满足我们的 OLTP 需求和复杂的 OLAP 的需求。另外 TiSpark 是建立在 Spark 引擎之上的,Spark 在机器学习领域上还是比较成熟的。考虑到收益系统未来会涉及到一些预测分析,会需要用到机器学习。综合这些考虑,TiDB + TiSpark 成为了我们首选的技术解决方案。后续我们了解到饿了么的80%的核心流程都跑在tidb的高性能集群上面,还有新一代的互联网代表企业摩拜、今日头条,以及机票行业的qunar都有tidb的深度应用。TiDB简介 TiDB项目在世界上最流行的开源代码托管平台 GitHub 上共计已获得 10000+ Star,项目集合了 150 多位来自全球的 Contributors (代码贡献者)。TiDB是 PingCAP 公司受 Google Spanner / F1论文启发而设计的开源分布式 NewSQL 数据库。TiDB 具备如下NewSQL 核心特性: SQL 支持(TiDB 是 MySQL 兼容的) 水平线性弹性扩展 分布式事务 跨数据中心数据强一致性保证 故障自恢复的高可用 TiDB 适用于 100% 的 OLTP 场景和 80% 的 OLAP 场景。对业务没有任何侵入性,能优雅的替换传统的数据库中间件、数据库分库分表等 Sharding 方案。同时它也让开发运维人员不用关注数据库 Scale 的细节问题,专注于业务开发,极大的提升研发的生产力。参考:https://pingcap.github.io/docs-cn/overviewTiDB的架构 TiDB 集群主要分为三个组件:TiDB Server、TiKVServer、PD Server,整体实现架构如下:TiDB 整体架构图TiDB Server TiDB Server 主要负责接收 SQL 请求,处理 SQL 相关的逻辑,并通过 PD 找到存储计算所需数据的 TiKV 地址,与 TiKV 交互获取数据,最终返回结果。 TiDB Server 是无状态的,其本身并不存储数据,只负责计算,可以无限水平扩展,可以通过负载均衡组件(如 LVS、HAProxy 或 F5)对外提供统一的接入地址。PD Server PlacementDriver (简称 PD) 是整个集群的管理模块,其主要工作有三个: 存储集群的元信息(某个 Key 存储在哪个 TiKV 节点); 对TiKV 集群进行调度和负载均衡(如数据迁移、Raft group leader 迁移等); 分配全局唯一且递增的事务 ID; TiKV Server TiKV Server 负责存储数据,从外部看 TiKV 是一个分布式的提供事务的 Key-Value 存储引擎。存储数据的基本单位是 Region,每个 Region 负责存储一个 Key Range 的数据,每个 TiKV 节点会负责多个 Region 。TiKV 使用 Raft 协议做复制,保持数据的一致性和容灾。副本以 Region 为单位进行管理,不同节点上的多个 Region 构成一个 Raft Group,互为副本。数据在多个 TiKV 之间的负载均衡由 PD 调度,以 Region 为单位进行调度。参考:https://pingcap.github.io/docs-cn/overviewTiDB在易建 RSS 系统的架构如下:RSS 系统的架构图我们的 TiDB 集群共有 5 台高性能的海航云服务器来提供服务,经过测试 write 性能可以稳定的做到 1 万 TPS,同时,read 性能可以做到 0.5 万 TPS,后续升级到 SSD 硬盘将能够提高更高的读写性能。使用了 TiDB 后,我们不需要再考虑分表分库的问题,因为数据在一起,也不用考虑数据同步的问题。近 10 亿行数据都可以复用以前的 MySQL 代码,进行 OLAP 分析也比上一代收益系统提速近 20 倍,同时,免去了数据同步的可能存在的问题。而且也能很好的满足我们 OLTP 操作的需求,懂得 MySQL 的开发人员都可以轻松的进行大数据开发,没有学习门槛,既节省了开发成本,又降低了数据运维成本。后记 部署 TiDB 近 3 个月来,收益系统的数据量已经增长近 1 倍达到 5 亿的数据量,近 10 张千万级别的中间表数据,期间我们做过 TiDB 的扩容与版本升级,这些操作对业务来讲都是完全透明的,而且扩容与升级简单。我们可以更加专注业务程序的开发与优化,无需了解数据库分片的规则,对于快速变化的业务来说是非常重要的。同时,由于 TiSpark 的整合可以再同一个集群里面分析海量的数据并将结果无缝共享,对于核心业务的应用的开发来讲是非常方便的,由于能够快速响应业务的需求对于当前激烈竞争的航空业来说,提升了航空公司自身的核心竞争力。"}, {"url": "https://pingcap.com/cases-cn/user-case-meituan/", "title": "美团点评携手 PingCAP 开启新一代数据库深度实践之旅", "content": " 一、背景和现状 在美团,基于 MySQL 构建的传统关系型数据库服务已经难于支撑公司业务的爆发式增长,促使我们去探索更合理的数据存储方案和实践新的运维方式。随着近一两年来分布式数据库大放异彩,美团 DBA 团队联合架构存储团队,于 2018 年初启动了分布式数据库项目。图 1 美团点评产品展示图立项之初,我们进行了大量解决方案的对比,深入了解了业界多种 scale-out、scale-up 方案,考虑到技术架构的前瞻性、发展潜力、社区活跃度、以及服务本身与 MySQL 的兼容性,最终敲定了基于 TiDB 数据库进行二次开发的整体方案,并与 PingCAP 官方和开源社区进行深入合作的开发模式。美团业务线众多,我们根据业务特点及重要程度逐步推进上线,到截稿为止,已经上线 10 个集群,近 200 个物理节点,大部分是 OLTP 类型的应用,除了上线初期遇到了一些小问题,目前均已稳定运行。初期上线的集群,已经分别服务于配送、出行、闪付、酒旅等业务。TiDB 架构分层清晰,服务平稳流畅,但在美团当前的数据量规模和已有稳定的存储体系的基础上,推广新的存储服务体系,需要对周边工具和系统进行一系列改造和适配,从初期探索到整合落地需要走很远的路。下面从几个方面分别介绍: 一是从 0 到 1 的突破,重点考虑做哪些事情; 二是如何规划实施不同业务场景的接入和已有业务的迁移; 三是上线后遇到的一些典型问题介绍; 四是后续规划和对未来的展望。 二、前期调研测试 2.1 对 TiDB 的定位 我们对于 TiDB 的定位,前期在于重点解决 MySQL 的单机性能和容量无法线性和灵活扩展的问题,与 MySQL 形成互补。业界分布式方案很多,我们为何选择了 TiDB 呢?考虑到公司业务规模的快速增长,以及公司内关系数据库以 MySQL 为主的现状,因此我们在调研阶段,对以下技术特性进行了重点考虑: 协议兼容 MySQL:这个是必要项。 可在线扩展:数据通常要有分片,分片要支持分裂和自动迁移,并且迁移过程要尽量对业务无感知。 强一致的分布式事务:事务可以跨分片、跨节点执行,并且强一致。 支持二级索引:为兼容 MySQL 的业务,这个是必须的。 性能:MySQL 的业务特性,高并发的 OLTP 性能必须满足。 跨机房服务:需要保证任何一个机房宕机,服务能自动切换。 跨机房双写:支持跨机房双写是数据库领域一大难题,是我们对分布式数据库的一个重要期待,也是美团下一阶段重要的需求。 业界的一些传统方案虽然支持分片,但无法自动分裂、迁移,不支持分布式事务,还有一些在传统 MySQL 上开发一致性协议的方案,但它无法实现线性扩展,最终我们选择了与我们的需求最为接近的 TiDB。与 MySQL 语法和特性高度兼容,具有灵活的在线扩容缩容特性,支持 ACID 的强一致性事务,可以跨机房部署实现跨机房容灾,支持多节点写入,对业务又能像单机 MySQL 一样使用。2.2 测试 针对官方声称的以上优点,我们进行了大量的研究、测试和验证。首先,我们需要知道扩容、Region 分裂转移的细节、Schema 到 kv 的映射、分布式事务的实现原理。而 TiDB 的方案,参考了较多的 Google 论文,我们进行了阅读,这有助于我们理解 TiDB 的存储结构、事务算法、安全性等,包括: Spanner: Google’s Globally-Distributed Database Large-scale Incremental Processing Using Distributed Transactions and Notifications In Search of an Understandable Consensus Algorithm Online, Asynchronous Schema Change in F1 我们也进行了常规的性能和功能测试,用来与 MySQL 的指标进行对比,其中一个比较特别的测试,是证明 3 副本跨机房部署,确实能保证每个机房分布一个副本,从而保证任何一个机房宕机不会导致丢失超过半数副本。从以下几个点进行测试: Raft 扩容时是否支持 learner 节点,从而保证单机房宕机不会丢失 2⁄3 的副本。 TiKV 上的标签优先级是否可靠,保证当机房的机器不平均时,能否保证每个机房的副本数依然是绝对平均的。 实际测试,单机房宕机,TiDB 在高并发下,QPS、响应时间、报错数量,以及最终数据是否有丢失。 手动 Balance 一个 Region 到其他机房,是否会自动回来。 从测试结果来看,一切都符合预期。三、存储生态建设 美团的产品线丰富,业务体量大,业务对在线存储的服务质量要求也非常高。因此,从早期做好服务体系的规划非常重要。下面从业务接入层、监控报警、服务部署,来分别介绍一下我们所做的工作。3.1 业务接入层 当前 MySQL 的业务接入方式主要有两种,DNS 接入和 Zebra 客户端接入。在前期调研阶段,我们选择了 DNS + 负载均衡组件的接入方式,TiDB-Server 节点宕机,15s 可以被负载均衡识别到,简单有效。业务架构如图 2。图 2 业务架构图后面我们会逐渐过渡到当前大量使用的 Zebra 接入方式来访问 TiDB,从而保持与访问 MySQL 的方式一致,一方面减少业务改造的成本,另一方面尽量实现从 MySQL 到 TiDB 的透明迁移。3.2 监控报警 美团目前使用 Mt-Falcon 平台负责监控报警,通过在 Mt-Falcon 上配置不同的插件,可以实现对多种组件的自定义监控。另外也会结合 Puppet 识别不同用户的权限、文件的下发。这样,只要我们编写好插件脚本、需要的文件,装机和权限控制就可以完成了。监控架构如图 3。图 3 监控架构图而 TiDB 有丰富的监控指标,使用流行的 Prometheus + Grafana,一套集群有 700+ 的 Metric。从官方的架构图可以看出,每个组件会推送自己的 Metric 给 PushGateWay,Prometheus 会直接到 PushGateWay 去抓数据。由于我们需要组件收敛,原生的 TiDB 每个集群一套 Prometheus 的方式不利于监控的汇总、分析、配置,而报警已经在 Mt-Falcon 上实现的比较好了,在 AlertManager 上再造一个也没有必要。因此我们需要想办法把监控和报警汇总到 Mt-Falcon 上面,有如下几种方式: 方案一:修改源代码,将 Metric 直接推送到 Falcon,由于 Metric 散落在代码的不同位置,而且 TiDB 代码迭代太快,把精力消耗在不停调整监控埋点上不太合适。 方案二:在 PushGateWay 是汇总后的,可以直接抓取,但 PushGateWay 是个单点,不好维护。 方案三:通过各个组件(TiDB、PD、TiKV)的本地 API 直接抓取,优点是组件宕机不会影响其他组件,实现也比较简单。 我们最终选择了方案三。该方案的难点是需要把 Prometheus 的数据格式转化为 Mt-Falcon 可识别的格式,因为 Prometheus 支持 Counter、Gauge、Histogram、Summary 四种数据类型,而 Mt-Falcon 只支持基本的 Counter 和 Gauge,同时 Mt-Falcon 的计算表达式比较少,因此需要在监控脚本中进行转换和计算。3.3 批量部署 TiDB 使用 Ansible 实现自动化部署。迭代快,是 TiDB 的一个特点,有问题快速解决,但也造成 Ansible 工程、TiDB 版本更新过快,我们对 Ansible 的改动,也只会增加新的代码,不会改动已有的代码。因此线上可能同时需要部署、维护多个版本的集群。如果每个集群一个 Ansible 目录,造成空间的浪费。我们采用的维护方式是,在中控机中,每个版本一个 Ansible 目录,每个版本中通过不同 inventory 文件来维护。这里需要跟 PingCAP 提出的是,Ansible 只考虑了单集群部署,大量部署会有些麻烦,像一些依赖的配置文件,都不能根据集群单独配置(咨询官方得知,PingCAP 目前正在基于 Cloud TiDB 打造一站式 HTAP 平台,会提供批量部署、多租户等功能,能比较好的解决这个问题)。3.4 自动化运维平台 随着线上集群数量的增加,打造运维平台提上了日程,而美团对 TiDB 和 MySQL 的使用方式基本相同,因此 MySQL 平台上具有的大部分组件,TiDB 平台也需要建设。典型的底层组件和方案:SQL 审核模块、DTS、数据备份方案等。自动化运维平台展示如图 4。图 4 自动化运维平台展示图3.5 上下游异构数据同步 TiDB 是在线存储体系中的一环,它同时也需要融入到公司现有的数据流中,因此需要一些工具来做衔接。PingCAP 官方标配了相关的组件。公司目前 MySQL 和 Hive 结合的比较重,而 TiDB 要代替 MySQL 的部分功能,需要解决 2 个问题: MySQL to TiDB MySQL 到 TiDB 的迁移,需要解决数据迁移以及增量的实时同步,也就是 DTS,Mydumper + Loader 解决存量数据的同步,官方提供了 DM 工具可以很好的解决增量同步问题。 MySQL 大量使用了自增 ID 作为主键。分库分表 MySQL 合并到 TiDB 时,需要解决自增 ID 冲突的问题。这个通过在 TiDB 端去掉自增 ID 建立自己的唯一主键来解决。新版 DM 也提供分表合并过程主键自动处理的功能。 Hive to TiDB & TiDB to Hive Hive to TiDB 比较好解决,这体现了 TiDB 和 MySQL 高度兼容的好处,insert 语句可以不用调整,基于 Hive to MySQL 简单改造即可。 TiDB to Hive 则需要基于官方 Pump + Drainer 组件,Drainer 可以消费到 Kafka、MySQL、TiDB,我们初步考虑用下图 5 中的方案通过使用 Drainer 的 Kafka 输出模式同步到 Hive。 图 5 TiDB to Hive 方案图四、线上使用磨合 对于初期上线的业务,我们比较谨慎,基本的原则是:离线业务 -> 非核心业务 -> 核心业务。TiDB 已经发布两年多,且前期经历了大量的测试,我们也深入了解了其它公司的测试和使用情况,可以预期的是 TiDB 上线会比较稳定,但依然遇到了一些小问题。总体来看,在安全性、数据一致性等关键点上没有出现问题。其他一些性能抖动问题,参数调优的问题,也都得到了快速妥善的解决。这里给 PingCAP 的同学点个大大的赞,问题响应速度非常快,与我们内部研发的合作也非常融洽。4.1 写入量大、读 QPS 高的离线业务 我们上线的最大的一个业务,每天有数百 G 的写入量,前期遇到了较多的问题,我们重点说说。业务场景: 稳定的写入,每个事务操作 100~200 行不等,每秒 6w 的数据写入。 每天的写入量超过 500G,以后会逐步提量到每天 3T。 每 15 分钟的定时读 job,5000 QPS(高频量小)。 不定时的查询(低频量大)。 之前使用 MySQL 作为存储,但 MySQL 到达了容量和性能瓶颈,而业务的容量未来会 10 倍的增长。初期调研测试了 ClickHouse,满足了容量的需求,测试发现运行低频 SQL 没有问题,但高频 SQL 的大并发查询无法满足需求,只在 ClickHouse 跑全量的低频 SQL 又会 overkill,最终选择使用 TiDB。测试期间模拟写入了一天的真实数据,非常稳定,高频低频两种查询也都满足需求,定向优化后 OLAP 的 SQL 比 MySQL 性能提高四倍。但上线后,陆续发现了一些问题,典型的如下:4.1.1 TiKV 发生 Write Stall TiKV 底层有 2 个 RocksDB 作为存储。新写的数据写入 L0 层,当 RocksDB 的 L0 层数量达到一定数量,就会发生减速,更高则发生 Stall,用来自我保护。TiKV 的默认配置: level0-slowdown-writes-trigger = 20 level0-stop-writes-trigger = 36 遇到过的,发生 L0 文件过多可能的原因有 2 个: 写入量大,Compact 完不成。 Snapshot 一直创建不完,导致堆积的副本一下释放,rocksdb-raft 创建大量的 L0 文件,监控展示如图 6。 图 6 TiKV 发生 Write Stall 监控展示图我们通过以下措施,解决了 Write Stall 的问题: 减缓 Raft Log Compact 频率(增大 raft-log-gc-size-limit、raft-log-gc-count-limit) 加快 Snapshot 速度(整体性能、包括硬件性能) max-sub-compactions 调整为 3 max-background-jobs 调整为 12 level 0 的 3 个 Trigger 调整为 16、32、64 4.1.2 Delete 大量数据,GC 跟不上 现在 TiDB 的 GC 对于每个 kv-instance 是单线程的,当业务删除数据的量非常大时,会导致 GC 速度较慢,很可能 GC 的速度跟不上写入。目前可以通过增多 TiKV 个数来解决,长期需要靠 GC 改为多线程执行,官方对此已经实现,即将发布。4.1.3 Insert 响应时间越来越慢 业务上线初期,insert 的响应时间 80 线(Duration 80 By Instance)在 20ms 左右,随着运行时间增加,发现响应时间逐步增加到 200ms+。期间排查了多种可能原因,定位在由于 Region 数量快速上涨,Raftstore 里面要做的事情变多了,而它又是单线程工作,每个 Region 定期都要 heartbeat,带来了性能消耗。tikv-raft propose wait duration 指标持续增长。解决问题的办法: 临时解决 增加 Heartbeat 的周期,从 1s 改为 2s,效果比较明显,监控展示如图 7。 图 7 insert 响应时间优化前后对比图 彻底解决 需要减少 Region 个数,Merge 掉空 Region,官方在 2.1 版本中已经实现了 Region Merge 功能,我们在升级到 2.1 后,得到了彻底解决。 另外,等待 Raftstore 改为多线程,能进一步优化。(官方回复相关开发已基本接近尾声,将于 2.1 的下一个版本发布。) 4.1.4 Truncate Table 空间无法完全回收 DBA Truncate 一张大表后,发现 2 个现象,一是空间回收较慢,二是最终也没有完全回收。 由于底层 RocksDB 的机制,很多数据落在 level 6 上,有可能清不掉。这个需要打开 cdynamic-level-bytes 会优化 Compaction 的策略,提高 Compact 回收空间的速度。 由于 Truncate 使用 delete_files_in_range 接口,发给 TiKV 去删 SST 文件,这里只删除不相交的部分,而之前判断是否相交的粒度是 Region,因此导致了大量 SST 无法及时删除掉。 考虑 Region 独立 SST 可以解决交叉问题,但是随之带来的是磁盘占用问题和 Split 延时问题。 考虑使用 RocksDB 的 DeleteRange 接口,但需要等该接口稳定。 目前最新的 2.1 版本优化为直接使用 DeleteFilesInRange 接口删除整个表占用的空间,然后清理少量残留数据,已经解决。 4.1.5 开启 Region Merge 功能 为了解决 region 过多的问题,我们在升级 2.1 版本后,开启了 region merge 功能,但是 TiDB 的响应时间 80 线(Duration 80 By Instance)依然没有恢复到当初,保持在 50ms 左右,排查发现 KV 层返回的响应时间还很快,和最初接近,那么就定位了问题出现在 TiDB 层。研发人员和 PingCAP 定位在产生执行计划时行为和 2.0 版本不一致了,目前已经优化。4.2 在线 OLTP,对响应时间敏感的业务 除了分析查询量大的离线业务场景,美团还有很多分库分表的场景,虽然业界有很多分库分表的方案,解决了单机性能、存储瓶颈,但是对于业务还是有些不友好的地方: 业务无法友好的执行分布式事务。 跨库的查询,需要在中间层上组合,是比较重的方案。 单库如果容量不足,需要再次拆分,无论怎样做,都很痛苦。 业务需要关注数据分布的规则,即使用了中间层,业务心里还是没底。 因此很多分库分表的业务,以及即将无法在单机承载而正在设计分库分表方案的业务,主动找到了我们,这和我们对于 TiDB 的定位是相符的。这些业务的特点是 SQL 语句小而频繁,对一致性要求高,通常部分数据有时间属性。在测试及上线后也遇到了一些问题,不过目前基本都有了解决办法。4.2.1 SQL 执行超时后,JDBC 报错 业务偶尔报出 privilege check fail。是由于业务在 JDBC 设置了 QueryTimeout,SQL 运行超过这个时间,会发行一个 “kill query” 命令,而 TiDB 执行这个命令需要 Super 权限,业务是没有权限的。其实 kill 自己的查询,并不需要额外的权限,目前已经解决了这个问题,不再需要 Super 权限,已在 2.0.5 上线。4.2.2 执行计划偶尔不准 TiDB 的物理优化阶段需要依靠统计信息。在 2.0 版本统计信息的收集从手动执行,优化为在达到一定条件时可以自动触发: 数据修改比例达到 tidb_auto_analyze_ratio 表一分钟没有变更(目前版本已经去掉这个条件) 但是在没有达到这些条件之前统计信息是不准的,这样就会导致物理优化出现偏差,在测试阶段(2.0 版本)就出现了这样一个案例:业务数据是有时间属性的,业务的查询有 2 个条件,比如:时间+商家 ID,但每天上午统计信息可能不准,当天的数据已经有了,但统计信息认为没有。这时优化器就会建议使用时间列的索引,但实际上商家 ID 列的索引更优化。这个问题可以通过增加 Hint 解决。在 2.1 版本对统计信息和执行计划的计算做了大量的优化,也稳定了基于 Query Feedback 更新统计信息,也用于更新直方图和 Count-Min Sketch,非常期待 2.1 的 GA。五、总结展望 经过前期的测试、各方的沟通协调,以及近半年对 TiDB 的使用,我们看好 TiDB 的发展,也对未来基于 TiDB 的合作充满信心。接下来,我们会加速推进 TiDB 在更多业务系统中的使用,同时也将 TiDB 纳入了美团新一代数据库的战略选型中。当前,我们已经全职投入了 3 位 DBA 同学和多 …"}, {"url": "https://pingcap.com/cases-cn/user-case-weiruida/", "title": "TiDB 在威锐达 WindRDS 远程诊断及运维中心的应用", "content": " 公司简介 西安锐益达风电技术有限公司成立于 2012 年 1 月 4 日,是一家专业化的工业测量仪器系统、机电产品和计算机软件研发、设计和制造公司,是北京威锐达测控系统有限公司在西安成立的全资子公司。依托大学的科研实力,矢志不渝地从事仪器仪表及测量系统的研究和应用开发,积累了丰富的专业知识和实践经验,具备自主开发高端仪器系统和工程实施的完整技术能力。为了适应我国大型风电运营商设备维护管理的需求,破解风电监测技术难题,经过多年艰苦研发,研制了一种具有完全自主知识产权的网络化、模块化、集成化的风电机组状态监测与故障诊断系统,为风电机组全生命周期的运行维护管理提供一套完整的解决方案。业务描述 威锐达 WindRDS 远程诊断与运维中心,是以设备健康监测为核心,实现企业设备全生命周期的健康监测和基于状态的预知性设备运营维护的管理平台。本平台以多维、丰富的数据为基础,结合传统的诊断分析方法,并充分发挥利用大数据智能化的技术手段,快速及时的发现、分析定位设备运转及企业运维过程中的问题,并以流程化、自动化的软件系统辅助用户高效的跟踪、处理问题,目标提升企业设备运维管理的能力,节约运维成本,为企业创造价值。图 1:WindRDS 系统交互图痛点、选型指标 痛点 WindRDS 的数据平台,对于数据的存储当前选用流行的 MySQL 数据库,面对每年 T 级的数据增长量,以及随着数据量的快速增长导致访问性能的急剧下降,目前也只是通过传统的分表、分库等解决方案进行优化,但性能提升未达到预期,且后续维护升级复杂麻烦,不能很好的满足存储和性能弹性水平扩展的需求。 本项目同时具有 OLTP 和 OLAP 应用需求,也曾设计构建混合型的数据存储方案(MySQL+ HDFS + Hive + Kylin + HBase + Spark),功能上可同时满足 OLTP 和 OLAP 应用需求,但问题也很明显,如: 要满足一定程度的实时在线分析,还需要做一些数据迁移同步工作,需要开发实时同步 ETL 中间件,实时从存储事务数据的关系数据库向存储面向分析的 Hive、HBase 数据库同步数据,实时性及可靠性不能保证; 对于基于 SQL 数据访问的应用程序的切换到该数据平台构成很大挑战,应用程序的数据访问层都需要进行修改适配,工作量大,切换成本高; 对于面向大数据的的分布式数据库产品(Hive、HBase 等)投入成本高且维护复杂,容易出错,可维护性差。 选型指标 支持容量及性能的水平弹性扩缩; 支持对使用 MySQL 协议的应用程序的便捷稳定的迁移,无需修改程序; 满足业务故障自恢复的高可用,且易维护; 强一致的分布式事务处理; 支持 Spark,可支撑机器学习应用; 集群状态可视化监控,方便运行维护。 我们大部分应用程序数据访问用的是 MySQL 的协议,TiDB 数据库完美的支持了 MySQL 的 SQL 语法,我们现有的应用程序几乎不用做任何修改,就可直接切换到 TiDB 上使用,并且能够很好的满足我们的 OLTP 需求和复杂 OLAP 的需求。另外,TiSpark 是建立在 Spark 引擎之上的,Spark 在机器学习领域上还是比较成熟的。考虑到未来我们的平台也会用到机器学习的一些业务应用,综合上述方面,TiDB + TiSpark 成为了我们首选的技术解决方案。TiDB 上线前测试 TiDB 在我司的数据中心部署的应用情况如下:部署架构 改造之前,主要用 MySQL 多实例的方式承载 WindRDS 所有的业务数据存储和应用,随着数据增长,存储容量接近单机的磁盘极限,单机的磁盘 IO 繁忙且易阻塞,查询性能难以满足业务增长的需求。数据量大了以后,传统的 MySQL 水平扩展能力弱,性能和稳定性容易产生问题,现有传统关系数据库已不能满足业务的扩展和应用,已成为制约业务发展的瓶颈。而为了满足大数据可视化 BI 分析、机器学习的 OLAP 场景,选用了多种数据中间件产品 HBase、Hive、Kylin 及 Spark 进行组合,形成一个复杂的多种数据中间件产品混合型集群,一定程度满足了 OLAP 的需求,但不同的产品之间存在资源争抢和制约,集群非常难于维护,非一步到位的最佳方案。图 2:改造前 WindRDS 系统架构改造之后,TiDB + TiSpark 的解决方案,解决了之前方案的不足,系统数据中间件产品种类简化,OLTP + OLAP 一揽子解决方案,系统数据存储和查询计算集群结构简单,较少人工参与系统节点维护,降低运维复杂度,是一个比较理想的解决方案。图 3:改造后 WindRDS 部署架构测试集群配置 TiDB 测试集群总体配置如下: TiSpark 测试集群总体配置如下: 测试数据查询性能对比 我们使用 TiDB 1.0 版本搭建测试集群,然后我们进行了简单的查询性能测试,我们对 WindRDS 的 5 种类型的数据进行查询测试,从业务应用中选择了针对每种数据类型的耗时、复杂的关联 SQL 语句,分别在 MySQL 上和 TiDB 上进行执行,多次执行取平均值,如下图所示,明显的,TiDB 的响应时间要小于 MySQL,可见 TiDB 的查询性在我们业务模型中表现明显优于 MySQL 。图 4:测试数据关键操作对比 MySQL vs TiDB图 5:测试数据关键操作 MySQL vs TiDB 耗时对比 (越低越好)TiDB 上线 从 1 月初测试环境搭建完成到上线,TiDB 稳定运行四个多月,平均 QPS 稳定在数千。TiDB 在性能、可用性、稳定性上完全超出了我们的预期。测试及上线过程中的一些问题 由于前期我们对 TiDB 的了解还不深,在此迁移期间碰到的一些兼容性的问题,简单列举如下: 比如 TiDB 的自增 ID 的机制; 表外键级联机制; 排序的时候需要使用字段名等。 以上问题咨询 TiDB 的工程师后,很快的得到了解决,非常感谢 TiDB 团队的支持以及快速响应。另外,在使用 TiDB 1.0 版本的过程中我们也遇到过如下问题: 集群中某个 TiKV 节点的 SSD 满了,但是集群不认为满了,继续要求该节点写入数据,导致进程宕机。 集群中任何一个节点 IO 能力下降,都会导致整个集群若依赖他的操作都受到影响,因此,该分布式的数据库等组件,虽然提高了性能和扩展性,但是维护也一样比较棘手,任何瓶颈,都有可能拉低整个集群的性能。 以上问题再升级到 TiDB 2.0 版本后解决,咨询 TiDB 官方团队答复如下: 第一个问题,在 TiDB 2.0 版本有对应的优化,TiDB 在空间不足时会根据剩余空间进行调度,降低此问题发生的概率。 第二个问题,TiDB 2.0 版本会充分考虑机器负载,响应时间等维度进行调度,尽可能避免单点成为整个系统的瓶颈。 后续和展望 我们对 TiDB 越来越了解,后续我们计划对 TiDB 进行大规模推广使用,具体包括: 公司后续关于风电领域大数据中心的开发建设,考虑选型 TiDB 作为数据存储,并推荐给我们的合作客户。 公司 WindRDS、WindCMS 等既有应用系统将考虑逐步切换到 TiDB 上来。 WindRDS 后续关于大数据多维度可视化分析、专家系统及机器学习等应用功能的开发,对于数据的存储和查询应用,计划选用 TiDB + TiSpark 进行底层中间件的支持。 最终通过 TiDB 形成一个同时兼容分析型和事务型(HTAP)的统一数据库平台解决方案。 作者介绍:郭凯乐,应用软件工程师,从公司成立入职工作至今共 6 年半时间,起初主要负责公司的应用系统的服务器端程序的设计开发,对于公司的核心业务及系统架构非常熟悉。2015 年到 2016 年,主持开发了基于规则的智能诊断系统(专家系统),该系统的开发,使自身对于专家系统有了深刻的了解和认识,并积累了丰富的经验,成为该领域的资深工程师。2016 年第至今,参与公司大数据平台项目的研发,该项目主要是围绕着大数据、工业物联网及分布式系统进行一些方法、中间件及解决方案的一些研究,而作者本身参与该项目关于数据的接入及治理方法及方案的研究工作,过程中对于数据接入融合及数据治理所面临的问题、痛点深有体会,积累了丰富经验及心得。 "}, {"url": "https://pingcap.com/cases-cn/user-case-ping++/", "title": "TiDB 在 Ping++ 金融聚合支付业务中的实践", "content": " Ping++ 介绍 Ping++ 是国内领先的支付解决方案 SaaS 服务商。自 2014 年正式推出聚合支付产品,Ping++ 便凭借“7 行代码接入支付”的极致产品体验获得了广大企业客户的认可。如今,Ping++ 在持续拓展泛支付领域的服务范围,旗下拥有聚合支付、账户系统、商户系统三大核心产品,已累计为近 25000 家企业客户解决支付难题,遍布零售、电商、企业服务、O2O、游戏、直播、教育、旅游、交通、金融、房产等等 70 多个细分领域。Ping++ 连续两年入选毕马威中国领先金融科技 50 强,并于 2017 成功上榜 CB Insights 全球 Fintech 250 强。从支付接入、交易处理、业务分析到业务运营,Ping++ 以定制化全流程的解决方案来帮助企业应对在商业变现环节可能面临的诸多问题。TiDB 在 Ping++ 的应用场景 - 数据仓库整合优化 Ping++ 数据支撑系统主要由流计算类、报表统计类、日志类、数据挖掘类组成。其中报表统计类对应的数据仓库系统,承载着数亿交易数据的实时汇总、分析统计、流水下载等重要业务:随着业务和需求的扩展,数仓系统历经了多次发展迭代过程: 由于业务需求中关联维度大部分是灵活多变的,所以起初直接沿用了关系型数据库 RDS 作为数据支撑,数据由自研的数据订阅平台从 OLTP 系统订阅而来。 随着业务扩大,过大的单表已不足以支撑复杂的查询场景,因此引入了两个方案同时提供数据服务:ADS,阿里云的 OLAP 解决方案,用来解决复杂关系型多维分析场景。ES,用分布式解决海量数据的搜索场景。 以上两个方案基本满足业务需求,但是都仍存在一些问题: ADS:一是数据服务稳定性,阿里云官方会不定期进行版本升级,升级过程会导致数据数小时滞后,实时业务根本无法保证。二是扩容成本,ADS 为按计算核数付费,如果扩容就必须购买对应的核数,成本不是那么灵活可控。 ES:单业务搜索能力较强,但是不适合对复杂多变的场景查询。且研发运维代价相对较高,没有关系型数据库兼容各类新业务的优势。 所以需要做出进一步的迭代整合,我们属于金融数据类业务,重要性安全性不能忽视、性能也得要有保障,经过我们漫长的调研过程,最终,由 PingCAP 研发的 TiDB 数据库成为我们的目标选型。TiDB 具备的以下核心特征是我们选择其作为实时数仓的主要原因: 高度兼容 MySQL 语法; 水平弹性扩展能力强; 海量数据的处理性能; 故障自恢复的高可用服务; 金融安全级别的架构体系。 并追踪形成了以下数据支撑系统架构:新的方案给我们的业务和管理带来了以下的提升和改变: 兼容:整合了现有多个数据源,对新业务上线可快速响应; 性能:提供了可靠的交易分析场景性能; 稳定:更高的稳定性,方便集群运维; 成本:资源成本和运维成本都有所降低。 TiDB 架构解析及上线情况 TiDB 是 PingCAP 公司受 Google Spanner / F1 论文启发而设计的开源分布式 NewSQL 数据库。从下图 Google Spanner 的理念模型可以看出,其设想出数据库系统把数据分片并分布到多个物理 Zone 中、由 Placement Driver 进行数据片调度、借助 TrueTime 服务实现原子模式变更事务,从而对外 Clients 可以提供一致性的事务服务。因此,一个真正全球性的 OLTP & OLAP 数据库系统是可以实现的。我们再通过下图分析 TiDB 整体架构:可以看出 TiDB 是 Spanner 理念的一个完美实践,一个 TiDB 集群由 TiDB、PD、TiKV 三个组件构成。 TiKV Server:负责数据存储,是一个提供事务的分布式 Key-Value 存储引擎; PD Server:负责管理调度,如数据和 TiKV 位置的路由信息维护、TiKV 数据均衡等; TiDB Server:负责 SQL 逻辑,通过 PD 寻址到实际数据的 TiKV 位置,进行 SQL 操作。 生产集群部署情况:现已稳定运行数月,对应的复杂报表分析性能得到了大幅提升,替换 ADS、ES 后降低了大量运维成本。TiDB 在 Ping++ 的未来规划 TiSpark 的体验TiSpark 是将 Spark SQL 直接运行在分布式存储引擎 TiKV 上的 OLAP 解决方案。下一步将结合 TiSpark 评估更加复杂、更高性能要求的场景中。 OLTP 场景目前数仓 TiDB 的数据是由订阅平台订阅 RDS、DRDS 数据而来,系统复杂度较高。TiDB 具备了出色的分布式事务能力,完全达到了 HTAP 的级别。TiKV 基于 Raft 协议做复制,保证多副本数据的一致性,可以秒杀当前主流的 MyCat、DRDS 分布式架构。且数据库的可用性更高,比如我们对生产 TiDB 集群所有主机升级过磁盘(Case 记录),涉及到各个节点的数据迁移、重启,但做到了相关业务零感知,且操作简单,过程可控,这在传统数据库架构里是无法轻易实现的。我们计划让 TiDB 逐渐承载一些 OLTP 业务。 对 TiDB 的建议及官方回复 DDL 优化:目前 TiDB 实现了无阻塞的 online DDL,但在实际使用中发现,DDL 时生成大量 index KV,会引起当前主机负载上升,会对当前集群增加一定的性能风险。其实大部分情况下对大表 DDL 并不是很频繁,且时效要求并不是特别强烈,考虑安全性。建议优化点: 是否可以通过将源码中固定数值的 defaultTaskHandleCnt、defaultWorkers 变量做成配置项解决; 是否可以像 pt-osc 工具的一样增加 DDL 过程中暂停功能。 DML 优化:业务端难免会有使用不当的 sql 出现,如导致全表扫描,这种情况可能会使整个集群性能会受到影响,对于这种情况,是否能增加一个自我保护机制,如资源隔离、熔断之类的策略。 针对以上问题,我们也咨询了 TiDB 官方技术人员,官方的回复如下: 正在优化 Add Index 操作的流程,降低 Add Index 操作的优先级,优先保证在线业务的操作稳定进行。 计划在 1.2 版本中增加动态调节 Add Index 操作并发度的功能。 计划在后续版本中增加 DDL 暂停功能。 对于全表扫描,默认采用低优先级,尽量减少对于点查的影响。后续计划引入 User 级别的优先级,将不同用户的 Query 的优先级分开,减少离线业务对在线业务的影响。 最后,特此感谢 PingCAP 所有团队成员对 Ping++ 上线 TiDB 各方面的支持!✎ 作者:宋涛,Ping++ DBA"}, {"url": "https://pingcap.com/cases-cn/user-case-youzu/", "title": "TiDB 在游族网络平台部的深度应用", "content": " 公司介绍 游族网络股份有限公司(SZ.002174)成立于 2009 年,是全球领先的互动娱乐供应商。公司以“大数据”、“全球化”、“精品化”为战略方向,立足全球化游戏研发与发行,知名 IP 管理,大数据与智能化,泛娱乐产业投资四大业务板块全面发展。背景 2017 年初的时候,游族的用户中心体系面临迭代和重构,当时数据库有数亿多的核心数据,通过 hash key 分为了 1024 张表在 64 个数据库中来存储,使用自研的代码框架来进行对应 hash key 的 seek 操作。这时,非 hash key 的查询、DDL 变更等业务需求,分表分库逻辑代码框架的局限,让研发和运维都面临较高的数据库使用成本,数据库不能灵活高效的支撑业务需求。图 1:分库分表方案架构图为了解决上述问题,游族的技术团队急需一套同时满足如下的条件的数据库分布式集群: 能够提供实时的 OLTP 的一致性数据存储服务; 弹性的分布式架构; 配套的监控备份方案; 稳定的高可用性; 较低的迁移重构成本。 前期选择 最开始先考察了几个方案,但都有相对来说的不足: 方案一,将整个分表分库逻辑剥离到开源分表分库中间件上: 基于 2PC 的 XA 弱事务的一致性保证不尽如人意; 高可用架构更加复杂,单分片的局部不可用会对全局产生影响; 备份恢复的复杂度高; 这些方案引入了新的 sharding key 和 join key 的设计问题,整体的迁移难度不降反升。 方案二,官方的 MySQL cluster 集群: ndb 引擎不同于 InnoDB,需要修改表引擎,且实际使用效果未知; ndb 的高可用有脑裂风险; 监控备份的方案需要另作整理; 国内生产用例不多,资料缺乏,非企业版运维流程复杂。 探索 机缘巧合下,与 TiDB 的技术团队做了一次技术交流,了解到 TiDB 是 PingCAP 受 Google Spanner 的论文启发设计而来的开源分布式 NewSQL 数据库,具备如下 NewSQL 特性: SQL支持 (TiDB 是 MySQL 兼容的); 水平线性弹性扩展; 分布式事务; 跨数据中心数据强一致性保证; 故障自恢复的高可用; 海量数据高并发写入及实时查询(HTAP 混合负载)。 上述的特点非常契合目前我们在数据库应用设计上碰到的问题,于是在与 TiDB 的技术团队沟通了解后,就开始着手安排部署和测试 TiDB: TiDB 的备份目前采用的是逻辑备份,官方提供了一套基于 mydumper 和 myloader 的工具套件; 监控用的是应用内置上报 Prometheus 的方案,可以写脚本与自有的监控系统对接; 有状态的 KV 层采用的是 Raft 协议来保证,Leader 的选举机制满足了故障自恢复的需求; KV 层的 Region 分裂保证了集群无感知的扩展。 测试之后发现数据库运维中比较重要的几项都已经闭环的解决了,实测结论是: TiDB 是分布式结构,有网络以及多副本开销,导致 Sysbench OLTP 测试中 TiDB 单 server 的读性能不如 MySQL,但写优于 MySQL,且弹性扩展能力评估后可以满足业务的峰值需求; TiDB 的 OLAP 能力在大数据量下远优于 MySQL,且能看到持续的大幅提升; 由于 TiDB-Server 是无状态的,后续可以添加 Load Balance 来扩展 Server 层的支撑。 持续引入 在性能和需求满足前提下,就开始着手业务层的接入和改造: MySQL 协议的兼容这时候极大的降低了迁移到 TiDB 的成本,官方的 TiDB 同步 MySQL 的 Syncer 工具也给了接入和改造有力的支持,部分迁移在业务层就是一次 MySQL 的主从切换。于是,用户积分系统的扩展便不再采用分表分库的方案,分表逻辑回归到多个独立的单表,数亿的数据在 OLTP 的业务场景下表现十分出色,没有 sharding key 的约束后,整个使用逻辑在上层看来和 MySQL 单表没有不同,更加灵活的索引也提供了一部分低开销的 OLAP 的查询能力,整体的迁移改造流程比较顺利,业务契合度很高。随着上述系统的成功应用后,后面符合场景的 OLTP 项目也逐渐开始使用 TiDB: 登录态系统:原先的在 MySQL 采用 Replace 保留最后一条数据,迁移到 TiDB 的模式后,由于表的伸缩能力获得了很大的提升,故将 Replace 改为了 Insert 保留了所有的登录情况,单表数据量十亿以上,业务上支持了更多维度的记录,没有碰到性能和扩展性问题; 礼包码系统:礼包码的主流程为复杂度 O(1) 的 hash seek OLTP业务,经过 TiDB 的改造后,将原来的 100 个表的分表模式集中成单表管理,单表数据预计会达到 20 亿+; 用户轨迹项目:数据库弹性能力增长后的新需求,一些重要的用户行为数据的记录。 同时,在 kv 存储层没有瓶颈的时候,采用复用了集群的 kv 层的策略,在无状态的 Server 层做了业务隔离,间接的提升了整个集群的使用率,类似一个 DBaaS 的服务(图 2)。图 2:多套业务系统 TiDB 部署图RC2.2 -> GA1.0 -> GA1.1 从 RC2.2 版本到 GA1.0,游族平台部的生产环境已经有 3 套 TiDB 集群在运行,共计支撑了 6 个 OLTP 业务的稳定运行快一年的时间。 期间 PingCAP 团队提供了非常多的技术支持:集群部署策略、BUG 响应和修复、升级方案协助、迁移工具支持等,厂商和开源社区都非常活跃。从 RC2.2 开始,从性能优化到细小的 SQL 兼容性 BUG 修复,每个版本都能看到开发团队对 roadmap 的细致规划和态度。TiDB 也在厂商和社区打磨下,性能和稳定性逐渐提升,兼容性也越来越好。现在官方已经发布 GA1.1 的 alpha 版本,重构了 TiDB 的优化器,我们也在第一时间做了详细的测试,目前大部分 OLAP 性能比 GA1.0 要提升 1~2 倍,不得不感慨 TiDB 的演进速度,也期待 1.1 的正式发布。计划和期望 我们与 TiDB 团队的沟通中了解到补充 TiDB-Server 的重 OLAP 需求的 TiSpark 计算层已经比较成熟了,后面计划分析型的需求也会尝试使用 TiSpark 来进行计算。同时我们与 TiDB 团队在交流的时候也得知分区表,视图等功能都已经在计划中,后续 TiDB 的数据存储方式将会越来越灵活。经过内部的实际使用后,后续已经有数个符合业务场景在评估或计划使用 TiDB 作为 OLTP 存储层的支撑。TiDB 给了大库大表业务的一个全新的选择方向,相信 TiDB 以后能在更多的业务选型和设计方案上给出新的方向和思路。 作者:陶政,游族网络平台部 MySQL DBA 负责人。曾任同程旅游系统架构组 DBA,现负责游族网络数据库整体的运维规划和设计。熟悉各类业务的数据库设计、缓存设计、离线数据分析等解决方案。 "}, {"url": "https://pingcap.com/cases-cn/user-case-iqiyi/", "title": "TiDB 在爱奇艺的应用及实践", "content": " 背景介绍 爱奇艺,中国高品质视频娱乐服务提供者,2010 年 4 月 22 日正式上线,推崇品质、青春、时尚的品牌内涵如今已深入人心,网罗了全球广大的年轻用户群体,积极推动产品、技术、内容、营销等全方位创新。企业愿景为做一家以科技创新为驱动的伟大娱乐公司。我们在前沿技术领域也保持一定的关注度。随着公司业务的快速发展,原来普遍使用的 MySQL 集群遇到了很多瓶颈,比如单机 MySQL 实例支撑的数据量有限,只能通过不停删除较旧的数据来维持数据库的运转。同时单表的数据行数不断增大导致查询速度变慢。急需一种可扩展、高可用同时又兼容 MySQL 访问方式的数据库来支撑业务的高速发展。我司从 2017 年年中开始调研 TiDB,并且在数据库云部门内部系统中使用了 TiDB 集群。从今年 TiDB 推出 2.0 之后,TiDB 愈发成熟,稳定性与查询效率都有很大提升。今年陆续接入了边控中心、视频转码、用户登录信息等几个业务,这几个业务背景和接入方式如下详述。项目介绍 1. 边控中心 边控中心存储的是机器的安全统计信息,包括根据 DC、IP、PORT 等不同维度统计的流量信息。上层业务会不定期做统计查询,其业务页面如下:图 1 边控中心上层业务页面(一)图 2 边控中心上层业务页面(二)在选型过程中,也考虑过时序型数据库 Apache Druid(http://druid.io),但是 Druid 聚合查询不够灵活,最终放弃 Druid 选择了 TiDB 数据库。TiDB 几乎完全兼容 MySQL 的访问协议,可以使用现有的 MySQL 连接池组件访问 TiDB,业务迁移成本低,开发效率高。边控中心是爱奇艺第一个在线业务使用 TiDB 的项目,所以我们制定了详细的上线计划。 第一,部署单独的 TiDB 集群。然后,为了数据安全,部署了 TokuDB 集群,用作 TiDB 集群的备份数据库。 第二,我们通过 TiDB-Binlog 将 TiDB 集群的数据变更实时同步到 TokuDB 集群中,作为 TiDB 的灾备方案。 第三,前端部署了自研的负载均衡中间件,以最大化利用多个 TiDB 节点的计算能力,同时保证 TiDB 节点的高可用。 第四,部署 Prometheus 和 Grafana 监控 TiDB 集群健康状况,同时 Grafana 接入了公司的告警平台,会及时将告警信息通过短信、邮件等方式通知到运维值班同事。 边控中心上线过程中,也遇到了一些问题,都比较顺利的解决了: 最常见的问题是连接超时。经过仔细排查发现是统计信息严重过时导致执行计划无法选择最优解造成的,这个问题其实是关系型数据库普遍存在的问题,普遍的解决思路是手工进行统计信息收集,或者通过 hint 的方式来固定执行计划,这两种方式对使用者都有一定的要求,而最新版本的 TiDB 完善了统计信息收集策略,比如增加了自动分析功能,目前这个问题已经解决。 还遇到了加索引时间较长的问题。这一方面是由于 DDL 执行信息更新不及时,造成查询 DDL 进度时看到的是滞后的信息。另一方面是由于有时会存在 size 过大的 Region,导致加索引时间变长。这个问题反馈给 PingCAP 官方后得到比较积极的响应,大 Region 已经通过增加 Batch split 等功能在新版的 TiDB 中修复了。 边控中心上线以后,在不中断业务的情况下成功做过版本升级,修改 TiKV 节点内部参数等操作,基本对业务没有影响。在升级 TiKV 节点过程中会有少量报错,如“region is unvailable[try again later]、tikv server timeout”等。这是由于缓存信息滞后性造成的,在分布式系统中是不可避免的,只要业务端有重试机制就不会造成影响。边控中心上线以后,数据量一直在稳定增长,但查询性能保持稳定,响应时间基本保持不变,能做到这点殊为不易,我个人的理解,这个主要依赖 TiDB 底层自动分片的策略,TiDB 会根据表数据量,按照等长大小的策略(默认 96M)自动分裂出一个分片,然后通过一系列复杂的调度算法打散到各个分布式存储节点上,对一个特定的查询,不管原表数据量多大,都能通过很快定位到某一个具体分片进行数据查询,保证了查询响应时间的稳定。边控中心数据量增长情况如下:图 3 边控中心数据量增长情况TiDB 底层自动分片策略:图 4 TiDB 底层自动分片策略2. 视频转码 视频转码业务是很早就接入 TiDB 集群的一个业务。视频转码数据库中主要存储的是转码生产过程中的历史数据,这些数据在生产完成后还需要进一步分析处理,使用 MySQL 集群时因为容量问题只好保留最近几个月的数据,较早的数据都会删掉,失去了做分析处理的机会。针对业务痛点,在 2017 年年底部署了 TiDB 独立集群,并全量+增量导入数据,保证原有 MySQL 集群和新建 TiDB 集群的数据一致性。在全量同步数据过程中,起初采用 Mydumper+Loader 方式。Loader 是 PingCAP 开发的全量导入工具,但是导入过程总遇到导入过慢的问题,为解决这个问题,PingCAP 研发了 TiDB-Lightning 作为全量同步工具。TiDB-Lightning 会直接将导出的数据直接转化为 sst 格式的文件导入到 TiKV 节点中,极大的提高了效率,1T 数据量在 5-6 个小时内就能完成,在稳定运行一段时间后将流量迁移到了 TiDB 集群,并且扩充了业务功能,迄今稳定运行。TiDB-Lightning 实现架构图:图 5 TiDB-Lightning 实现架构图3. 用户登录信息用户登录信息项目的数据量一直在稳定增长,MySQL 主备集群在不久的将来不能满足存储容量的需求。另外,由于单表数据量巨大,不得不在业务上进行分表处理,业务数据访问层代码变得复杂和缺乏扩展性。在迁移到 TiDB 后,直接去掉了分库分表,简化了业务的使用方式。另外,在 MySQL 中存在双散表并进行双写。在 TiDB 中进一步合并成了一种表,利用 TiDB 的索引支持多种快速查询,进一步简化了业务代码。在部署增量同步的过程中使用了官方的 Syncer 工具。Syncer 支持通过通配符的方式将多源多表数据汇聚到一个表当中,是个实用的功能,大大简化了我们的增量同步工作。目前的 Syncer 工具还不支持在 Grafana 中展示实时延迟信息,这对同步延迟敏感的业务是个缺点,据官方的消息称已经在改进中,同时 PingCAP 他们重构了整个 Syncer,能自动处理分表主键冲突,多源同时 DDL 自动过滤等功能,总之通过这套工具,可以快速部署 TiDB “实时”同步多个 MySQL,数据迁移体验超赞。图 6 Syncer 架构在我们公司业务对数据库高可用有两个需求:一个是机房宕机了,服务仍然可用。另一个是,多机房的业务,提供本机房的只读从库,提升响应速度。针对这些不同的需求,TiDB 集群采用了多机房部署的方式,保证其中任一个机房不可用时仍然正常对外提供服务(如下图)。对每个 TiKV 节点设置 label 后,TiDB 集群在每个机房都有一份数据的副本,PD 集群会自动调度到合适的副本进行读操作,也可以满足第二个要求。为了满足迁移过程中的高可用性,会在流量迁移完成后部署 TiDB 到 MySQL 的实时同步。Drainer 支持指定同步开始的时间戳,有力支持了反向同步功能。图 7 TiDB 集群多机房部署形式在整个运维过程中,PingCAP 的小伙伴们提供了及时的帮助,帮助我们定位问题并提出建议,保证了业务的有序运行。在此表示由衷的感谢!适用范围 在实践过程中感受到 TiDB 解决的痛点主要是横向扩展和高可用。单机数据库支撑的数据量有限,如果采用分库分表 + proxy 的方式,无论 proxy 是在客户端还是服务端都增加了运维的成本。同时 proxy 的查询效率在很多场景下不能满足要求。另外,proxy 对事务的支持都比较弱,不能满足数据强一致性的要求。TiDB 可以直接替代 proxy+MySQL 的架构,服务高可用性、数据高可用性、横向扩展性都由 TiDB 集群完成,完美解决了数据量增量情况下出现的很多问题。而且,TiDB 在数据量越大的情况下性能表现得比 MySQL 越惊艳。一些改进建议 统计信息的收集期望更加的智能化,选择更好的时机自动完成而且不影响线上业务。 OLTP 和 OLAP 混合场景下相互间的隔离和尽量互不影响还有许多工作值得推进。 一些外围工具还需要提供高可用特性。 未来计划 我司仍有其它业务在接入 TiDB 服务,目前正在评估测试中。一些业务场景是 OLTP+OLAP 混合的场景,TiSpark 正好可以大展身手。目前在测试集群发现 TiSpark 查询时对 OLTP 业务的影响还是比较大的,必须限制 TiSpark 对 TiDB 集群造成的压力。还部署了单独 TiDB 集群做 OLAP 场景的测试,对内部参数做了针对性的优化。未来计划会继续加大对 TiDB 的投入,贡献一些 PR 到社区,其中很大的一部分工作是增强 TiDB-Binlog 的功能,和现有的一些数据同步组件整合起来,支持 TiDB 到 Kudu、HBase 等的同步。 作者:朱博帅,爱奇艺资深数据库架构师 "}, {"url": "https://pingcap.com/cases-cn/user-case-wanda/", "title": "TiDB 帮助万达网络科技集团实现高性能高质量的实时风控平台", "content": "万达网络科技集团 是中国唯一的实业+互联网大型开放型平台公司,拥有飞凡信息、快钱支付、征信、网络信贷、大数据等公司,运用大数据、云计算、人工智能、场景应用等技术为实体产业实现数字化升级,为消费者提供生活圈的全新消费服务。万达网络科技集团的技术团队,建设和维护着一套实时风控平台。这套实时风控平台,承担着各种关键交易的在线风控数据的写入和查询服务。实时风控平台后端的数据库系统在高性能,可靠性,可扩展性上有很高的要求,并且需要满足如下核心功能和业务要求: 风控相关业务数据实时入库 实时风控规则计算 通过 BI 工具分析风控历史数据 ETL 入库到 Hadoop 数据仓库 应用开发侧需要兼容 MySQL,降低应用改造门槛 为实现上述业务目标,万达网络科技集团的技术团队在实时风控数据库选型的早期阶段,首先选择了 MySQL Galera Cluster 作为数据库集群的技术架构。这套 MySQL 数据库架构通过不同于 MySQL 主流复制技术的复制机制,实现在多个 MySQL 节点间建立强同步关系,实现数据的副本和高可用。但经过业务实践,发现这套方案有诸多问题,其中比较突出的有以下几点: MySQL Galera Cluster 自身的强同步机制以大幅度降低集群整体性能为代价,集群整体性能比单节点 MySQL 还差。所以不能很好的满足“风控相关业务数据实时入库”的业务需求。 同时,MySQL Galera Cluster 的 JOIN 支持非常弱,不足以支持 BI 相关的复杂分析。 集群整体性能的短板加上对 JOIN 支持的薄弱,使得要在业务上实现大并发高性能的风控规则计算变的很困难。 万达的技术团队还考察了市场上用的比较多的 MySQL 主从复制以及通过 MySQL Proxy 中间件实现分库分表的方案。但这些方案,无论是高可用安全性,强一致性,还是对业务应用所需要的复杂事务/JOIN 操作以及横向扩展能力上,都无法满足实时风控平台的业务要求。这些问题集中反映在以下几个方面: 基于 MySQL 主从复制方式的高可用方案,容易出现诸如接入层脑裂和数据不一致的风险。 基于 MySQL Proxy 中间件的方案,缺少对分库分表后的跨库跨表的分布式事务支持以及对复杂 JOIN 的良好支持,因此也无法满足业务上风控规则实时计算和复杂查询的需求以及对业务团队的 BI 需求的支持。 基于 MySQL Proxy 中间件的方案需要业务代码的开发妥协,需要显式设计和指定分库分表的切分规则和路由配置,开发改造和运维成本显著增高。 在实时风控平台的高并发高性能的对外服务过程中,在线灵活扩容的相关工作在 MySQL Proxy 中间件架构中无法高效和可靠的实施。 最终万达的技术团队,通过评估验证,选择了 TiDB 帮助他们实现一个高性能,高可靠性和高扩展能力的实时风控平台后台数据库系统。TiDB 产品和技术方案对业务需求的支持和助力效果,集中表现在: 借助 TiDB 的分布式计算和存储引擎,集群对外服务的处理能力大大增强,高并发实时的风控规则计算能够轻松的处理完,相比较原来的 MySQL Galera Cluster 方案,单位处理性能提升了数倍。并且数据库集群获得了线性提升和扩展的能力。 集群整体 QPS(万级起)和 Latency (毫秒级) 对风控的实时性要求做出了技术保证。 无需考虑分库分表,对业务应用透明无侵入,应用开发和维护变得直观且简单。业务相关数据量规模和请求即便高速增长,也无需担心应用的复杂调整和运维的风险。 TiDB 针对分布式事务和强一致性的完善设计以及对各种 JOIN 模式的支持,使得实时风控类和 BI 分析类的业务应用能够高效运行。 这套实时风控平台,借助于 TiDB 的可靠性架构和高性能分布式处理能力,在业务生产环境已经稳定运行超过半年,期间经历过环境问题导致的故障,经历过诸如“618”高并发、大流量活动的严格考验。万达网络科技集团大数据中心技术专家陈新江表示:”TiDB 的表现让万达的技术团队有了信心,接下来将在 TiDB 的基础上,根据业务特点,拓展应用规模,增加诸如 TiSpark 复杂计算组件,整合 CDC 工具以提升 ETL 实时性以及增强 TiDB 运维管理能力等多项架构和技术演进工作,继续在万达的核心业务架构中发挥重要作用。” 作者:陈新江,万达网络科技集团大数据中心 "}, {"url": "https://pingcap.com/cases-cn/user-case-gaea-ad/", "title": "盖娅互娱 | 日均数据量千万级,MySQL、TiDB 两种存储方案的落地对比", "content": " 背景介绍 盖娅广告匹配系统(GaeaAD)用于支撑盖娅互娱全平台实时广告投放系统,需要将广告数据和游戏 SDK 上报的信息进行近实时匹配,本质上来说需要实时的根据各个渠道的广告投放与相应渠道带来的游戏玩家数据进行计算,实现广告转化效果分钟级别的展现及优化。初期的 MySQL 存储方案 在系统设计之初,基于对数据量的预估以及简化实现方案考虑,我们选用了高可用的 MySQL RDS 存储方案,当时的匹配逻辑主要通过 SQL 语句来实现,包含了很多联表查询和聚合操作。当数据量在千万级别左右,系统运行良好,基本响应还在一分钟内。图 1 MySQL RDS 存储方案架构图遭遇瓶颈,寻找解决方案 然而随着业务的发展,越来越多游戏的接入,盖娅广告系统系统接收数据很快突破千万/日,高峰期每次参与匹配的数据量更是需要翻几个番,数据库成为了业务的瓶颈。由于此时,整个技术架构出现了一些问题:1. 单次匹配耗时已从原本的 10 秒左右增加到 2 分钟以上,最慢的聚合查询甚至达到 20 分钟,时效性受到严重挑战。而且 MySQL 的问题是查询的时间随着数据量的增长而增长,以至于数据量越大的情况下查询越慢。2. 随着历史数据的积累,单表数据很快达到亿级别,此时单表的读写压力已经接近极限。3. 由于第一点提到的查询性能问题以及单机的容量限制,需要定时删除数据,对于一些时间跨度较长的业务查询需求没法满足。根据数据量的增长情况来看,分布式数据库会是很好的解决方案。首先考虑的是业务的垂直及水平拆分或者基于 MySQL 的数据库中间件方案和一些主流的 NoSQL 方案。但是仔细评估后,最先排除掉的是业务水平拆分的方案,因为业务逻辑中包含大量的关联查询和子查询,如果拆表后这些查询逻辑就没有办法透明的兼容,而且是比较核心的业务系统,时间精力的关系也不允许整体做大的重构。中间件的问题和分库分表的问题类似,虽然解决了大容量存储和实时写入的问题,但是查询的灵活度受限,而且多个 MySQL 实例的维护成本也需要考虑。第二个方案就是采用 NoSQL,因为此系统需要接收业务端并发的实时写入和实时查询,所以使用类似 Greenplum,Hive 或者 SparkSQL 这样的系统不太合适,因为这几个系统并不是针对实时写入设计的, MongoDB 的问题是文档型的查询访问接口对业务的修改太大,而且 MongoDB 是否能满足在这么大数据量下高效的聚合分析可能是一个问题。所以很明显,我们当时的诉求就是能有一款数据库既能像 MySQL 一样便于使用,最好能让业务几乎不用做任何修改,又能满足分布式的存储需求,还要保证很高的复杂查询性能。当时调研了一下社区的分布式数据库解决方案,找到了 TiDB 这个项目,因为协议层兼容 MySQL,而且对于复杂查询的支持不错,业务代码完全不用修改直接就能使用,使迁移使用成本降到极低。技术转身,使用 TiDB 在部署测试的过程中,我们使用 TiDB 提供的 Syncer 工具将 TiDB 作为 MySQL Slave 接在原业务的 MySQL 主库后边观察,确保读写的兼容性以及稳定性,经过一段时间观察后,确认读写没有任何问题,业务层的读请求切换至 TiDB,随后把写的流量也切换至 TiDB 集群,完成平滑的上线。图 2 TiDB 方案架构图GaeaAD 系统从 2016 年 10 月上线以来,已经稳定运行了一季度多,结合实际的使用体验,我们总结了 TiDB 带来的收益,主要有以下几点: 用 3 个节点组成的 TiDB 集群替换了原先的高可用 MySQL RDS 后,同样数据量级下,单次匹配平均耗时从 2 分钟以上降到了 30 秒左右,后续随着 TiDB 工程师的持续优化,达到了10 秒左右。另外,我们发现,TiDB 在数据规模越大的情况下,对比 MySQL 的优势就越明显,应该是 TiDB 自研的分布式 SQL 优化器带来的优势。不过在数据量比较轻量的情况下,因内部通信成本,优势相比 MySQL 并不明显。 图 3 TiDB 与 MySQL 在不同数据量下的查询时间对比 TiDB 支持自动 Sharding,业务端不用切表操作,TiDB 也不需要像传统的数据库中间件产品设定 Sharding key 或者分区表什么的,底层的存储会自动根据数据的分布,均匀的分散在集群中,存储空间和性能可以通过增加机器实现快速的水平扩展,极大地降低了运维成本。 TiDB 支持在线不中断的滚动升级,至今直接在线升级已有 10 余次左右,没出现过一起导致线上服务中断的情况,在可用性上体验不错。 TiDB 支持和 MySQL 的互备,这个功能很好的解决了我们业务迁移时候的过渡问题。 当前我们正在着手把 storm 集群上的 BI 系统的实时计算业务的数据存储系统从 MongoDB 替换成 TiDB(因 MongoDB 的使用门槛相对较高,运维成本大,查询方式不如传统的 SQL 灵活),后续也计划把实时性要求高、数据存储量大且存储周期较长的业务都迁移到 TiDB 上来,看上去是一个比较合适的场景。TiDB 工程师点评 盖娅的业务使用 TiDB 做了如下优化:1. 支持更多表达式下推,充分利用 TiKV 多实例的计算资源,加快计算速度;同时也尽可能将不需要用到的数据过滤掉,减小网络传输。2. TiDB 默认支持 HashJoin,将算子尽可能并行化,能够利用整个集群的计算资源。3. TiDB 采用流水线的方式读取数据,并且优化过 IndexScan 算子,降低整个流程的启动时间。 作者简介:刘玄,盖娅互娱数据平台高级开发工程师,主要负责实时数据业务和数据流方向。毕业于湖南大学软件工程系,曾任百度高级运维工程师,负责大搜建库运维。 "}, {"url": "https://pingcap.com/cases-cn/user-case-zhuanzhuan/", "title": "TiDB 分布式数据库在转转公司的应用实践", "content": " 公司及业务架构介绍 转转二手交易网 —— 把家里不用的东西卖了变成钱,一个帮你赚钱的网站。由腾讯与 58 集团共同投资。为海量用户提供一个有担保、便捷的二手交易平台。转转是 2015 年 11 月 12 日正式推出的 APP,遵循“用户第一”的核心价值观,以“让资源重新配置,让人与人更信任”为企业愿景,提倡真实个人交易。转转二手交易涵盖手机、3C 数码、母婴用品等三十余个品类。在系统设计上,转转整体架构采用微服务架构,首先按照业务领域模型垂直拆分成用户、商品、交易、搜索、推荐微服务。对每一个功能单元(商品等),继续进行水平拆分,分为商品网关层、商品业务逻辑层、商品数据访问层、商品 DB / Cache,如下图所示: 项目背景 1. 面临的问题 转转后端业务现阶段主要使用 MySQL 数据库存储数据,还有少部分业务使用 MongoDB。虽然目前情况下使用这两种存储基本可以满足我们的需求,但随着业务的增长,公司的数据规模逐渐变大,为了应对大数据量下业务服务访问的性能问题,MySQL 数据库常用的分库、分表方案会随着 MySQL Sharding(分片)的增多,业务访问数据库逻辑会越来越复杂。而且对于某些有多维度查询需求的表,我们总需要引入额外的存储或牺牲性能来满足我们的查询需求,这样会使业务逻辑越来越重,不利于产品的快速迭代。从数据库运维角度讲,大数据量的情况下,MySQL 数据库在每次 DDL 都会对运维人员造成很大的工作量,当节点故障后,由于数据量较大,恢复时间较长。但这种 M - S 架构只能通过主从切换并且需要额外的高可用组件来保障高可用,同时在切换过程由于需要确定主库状态、新主库选举、新路由下发等原因,还是会存在短暂的业务访问中断的情况。 综上所述,我们面临的主要问题可归纳为: 数据量大,如何快速水平扩展存储; 大数据量下,如何快速 DDL; 分库分表造成业务逻辑非常复杂; 常规 MySQL 主从故障转移会导致业务访问短暂不可用。 2. 为什么选择 TiDB 针对上章提到的问题,转转基础架构部和 DBA 团队考虑转转业务数据增速,定位简化业务团队数据库使用方案,更好的助力业务发展,决定启动新型存储服务(NewSQL)的选型调研工作。 TiDB 数据库,结合了关系库与 KV 存储的优点,对于使用方,完全可以当做 MySQL 来用,而且不用考虑数据量大了后的分库分表以及为了支持分库分表后的多维度查询而建立的 Mapping 表,可以把精力全部放在业务需求上。所以我们把 TiDB 作为选型的首选对象展开了测试和试用。TiDB 测试 1. 功能测试 TiDB 支持绝大多数 MySQL 语法,业务可以将基于 MySQL 的开发,无缝迁移至 TiDB。不过目前 TiDB 不支持部分 MySQL 特性,如:存储过程、自定义函数、触发器等。2. TiDB 压力测试 通过测试工具模拟不同的场景的请求,对 TiDB 数据库进行压力测试,通过压力测试结果的对比,可以提供 RD 使用 TiDB 的合适业务场景以及 TiDB 的使用建议。 此次压力测试,总共使用 6 台物理服务器,其中 3 台 CPU 密集型服务器,用于启动 TiDB - Server、PD 服务;另外 3 台为 IO / CPU 密集型的PCIE 服务器,用于启动 TiKV 服务。 使用 sysbench - 1.0.11 测试数据大小为 200G 的 TiDB 集群,在不同场景下 TiDB 的响应时间(95th per):3. 结果整理 顺序扫描的效率是比较高的,连续的行大概率会存储在同一台机器的邻近位置,每次批量的读取和写入的效率会高; 控制并发运行的线程数,会减少请求响应时间,提高数据库的处理性能。 4. 场景建议 适合线上业务混合读写场景; 适合顺序写的场景,比如:数据归档、操作日志、摊销流水。 5. TiDB 预上线 将 TiDB 挂载到线上 MySQL,作为 MySQL 从库同步线上数据,然后业务将部分线上读流量切换到 TiDB,可以对 TiDB 集群是否满足业务访问做好预判。业务接入 1. 迁移过程 我们第一个接入 TiDB 的业务线是转转消息服务。消息作为转转最重要的基础服务之一,是保证平台上买卖双方有效沟通、促进交易达成的重要组件,其数据量和访问量都非常大。起初我们使用的是 MySQL 数据库,对其所有的业务都做了库的垂直拆分以及表的水平拆分。目前线上有几十 TB 的数据,记录数据达到了几百亿。虽对 MySQL 做了分库分表,但实例已经开始又有偶发的性能问题,需要马上对数据进行二次拆分,而二次拆分的执行成本也比较高,这也是我们首先迁移消息数据库的原因之一。消息服务有几个核心业务表:联系人列表、消息表、系统消息表等等。联系人列表作为整个消息系统的枢纽,承载着巨大的访问压力。业务场景相对其他表最复杂的,也是这个表的实例出现了性能问题,所以我们决定先迁移联系人列表。整个迁移过程分三步:测试(判断 TiDB 是否满足业务场景,性能是否 OK)、同步数据、切流量。(1)测试:首先我们模拟线上的数据和请求对“联系人列表”做了大量功能和性能的验证,而且还将线上的数据和流量引到线下,对数据库做了真实流量的验证,测试结果证明 TiDB 完全满足消息业务的需求。引流工作,我们是通过转转自研的消息队列,将线上数据库的流量引一份到测试环境。测试环境消费消息队列的数据,转换成数据库访问请求发送到 TiDB 测试集群。通过分析线上和测试环境两个数据访问模块的日志可以初步判断 TiDB 数据库是否可以正常处理业务请求。当然仅仅这样是不够的,DBA 同学还需要校验 TiDB 数据的正确性(是否与线上 MySQL 库一致)。验证思路是抽样验证 MySQL 库表记录和 TiDB 的记录 Checksum 值是否一致。(2)同步数据:DBA 同学部署 TiDB 集群作为 MySQL 实例的从库,将 MySQL 实例中的联系人列表(单实例分了 1024 个表)的数据同步到 TiDB 的一张大表中。(3)切流量:切流量分为三步,每两步之间都有一周左右的观察期。 第一步将读流量灰度切到 TiDB 上; 第二步断开 TiDB 与 MySQL 的主从同步,业务开双写(同时写 MySQL 和 TiDB,保证两库数据一致)确保业务流量可以随时回滚到 MySQL; 第三步停止 MySQL 写入,到此业务流量完全切换到 TiDB 数据库上。 迁移过程中最重要的点就是确保两个数据库数据一致,这样读写流量随时可以切回 MySQL,业务逻辑不受任何影响。数据库双写的方案与上文提到的引流测试类似,使用消息队列引一份写入流量,TiDB 访问模块消费消息队列数据,写库。但仅仅这样是不能保证两个库数据一致的,因为这个方案无法保证两个写库操作的原子性。所以我们需要一个更严谨的方案,转转的消息队列还提供了事务消息的支持,可以保证本地操作和发送消息的原子性。利用这一特性再加上异步补偿策略(离线扫描日志,如果有失败的写入请求,修正数据)保证每个消息都被成功消费且两个库每次写入结果都是一致的,从而保证了 MySQL 与 TiDB 两个库的数据一致。2. 遇到问题 按照上述的方案,我们已经将消息所有的业务都切到 TiDB 数据库上。迁移过程中也不都是顺风顺水,也遇到了问题,过程中也得到了 TiDB 官方团队的大力支持。这里主要介绍两个问题:(1)TiDB 作为分布式存储,其锁机制和 MySQL 有很大不同。我们有一个并发量很大,可能同时更新一条记录的场景,我们用了 MySQL 的唯一索引保证了某个 Key 值的唯一性,但如果业务请求使用默认值就会大量命中唯一索引,会造成 N 多请求都去更新统一同一条记录。在 MySQL 场景下,没有性能问题,所以业务上也没做优化。但当我们用这个场景测试 TiDB 时,发现 TiDB 处理不太好,由于其使用的乐观锁,数据库输出大量的重试的日志。业务出现几十秒的请求延迟,造成队列中大量请求被抛弃。PingCAP 的同学建议调整 retry_limit 但也没有完全生效(该 BUG 已经在 2.0 RC 5 已经修复),最后业务进行优化(过滤使用默认值的请求)后问题得到解决。(2)第二个问题是运维方面的,DBA 同学按照使用 MySQL 的运维经验,对一个上近 T 的表做了 Truncate操作,操作后,起初数据库表现正常,但几分钟后,开始出现超时,TiKV 负载变高。最后请教 PingCAP 同学分析,定位是操作触发了频繁回收 Region 的 BUG(该 BUG TiDB 2.0 版本已经修复)。线上效果对比 1. 队列等待情况对比 使用 TiDB 数据库,业务模块队列请求数基本保持 1 个,MySQL 会有较大抖动。2. 请求延迟情况对比 使用 TiDB 数据库,整体响应延时非常稳定,不受业务流量高峰影响,但 MySQL 波动很大。 另外在扩展性方面,我们可以通过无缝扩展 TiDB 和 TiKV 实例提升系统的吞吐量,这个特性 MySQL 是不具备的。3. 业务延迟和错误量对比 接入 TiDB 数据库后业务逻辑层服务接口耗时稳定无抖动,且没有发生丢弃的情况(上图错误大多由数据访问层服务队列堆积发生请求丢弃造成)。TiDB 线上规模及后续规划 目前转转线上已经接入消息、风控两套 OLTP 以及一套风控 OLAP 集群。 集群架构如下:目前转转线上 TiDB 集群的总容量几百 TB,线上 TiDB 表现很稳定,我们会继续接入更多的业务(留言,评论、搜索、商品、交易等等)。1. 后续规划 多个正在开发的新业务在开发和测试环境中使用 TiDB,线上会直接使用 TiDB; 转转核心的留言、评论、搜索、商品、交易订单库计划迁移到 TiDB,已经开始梳理业务,准备展开测试; 计划在后续 TiDB 的使用中,TiKV 服务器池化,按需分配 TiKV 节点。 2. TiDB 使用成果 利用 TiDB 水平扩展特性,避免分库分表带来的问题,使得业务快速迭代; TiDB 兼容 MySQL 语法和协议,按照目前线上 MySQL 使用规范,可以无缝的迁移过去,无需 RD 做调整,符合预期; 在数据量较大的情况下,TiDB 响应较快,优于 MySQL; 集群出现故障对用户无感知; TiDB 自带了完善的监控系统,使得运维成本大大降低。 作者:孙玄,转转公司首席架构师;陈东,转转公司资深工程师;冀浩东,转转公司资深 DBA。 "}, {"url": "https://pingcap.com/cases-cn/user-case-funyours-japan/", "title": "TiDB 在株式会社 FUNYOURS JAPAN 的应用", "content": " 背景 株式会社 FUNYOURS JAPAN 自 2014 在日本成立以来,营运多款颇受好评的页游跟手游,如:剣戟のソティラス、九十九姬 等,对于营运游戏来说,能够了解游戏中的玩家在做什么,喜欢的偏好是什么,关卡的设计是否平衡,都是相当重要的,所以随着营运时间的增长,资料库数据在亿笔以上也是寻常的。所以我们的技术单位也一直不断在评估市面上的各种资料库以及如何改进目前现有系统与架构,近年来最热门的资料库系统可以说是 NoSQL 了,不论 MongoDB,Cassandra,Redis,HBase 等等都占有一片天,具有读写快速,容易扩展等特性。经过初步了解后,采用 NoSQL 方式,需要对于目前的资料储存架构整个重新设计,并且需要配合采用的该套 NoSQL 资料库进行业务改造设计,那么该采用哪一套 NoSQL 资料库又是一个需要慎重考虑的课题。先回过头来看当前最需要处理改进的项目:1. 储存空间扩展不易2. 单台资料库效能有限初期方案 在处理储存空间不足的部分,一开始我们先采用了 MySQL innoDB 提供的压缩表格格式,对于需要时常读写更新的部分使用了 8K page size,过往的日志部分采用 4K page size,效果非常令人满意,释放了大量的储存空间,并且对于效能来说没有造成可察觉的影响。这部分网路上的测试比较多,就不在此多做说明。但是很快的压缩表格节省的空间毕竟是有限的,接下来只能增加 volume 容量以及将没有需要更新的过往日志移动到其他资料库上,虽然造成维护工作跟时间的繁复与负担,但是问题解决了。基于 MySQL 资料库架构单台的性能限制上,我们采用了多组的资料库伺服器,来满足所需的效能。当然不同组之间资料是不共通的,也就是无法直接使用 SQL 来做跨组间的操作,需要额外的程式来作业。而当然为了大量的资料存取上的效能,分表分库对表格进行 partition 这些作业都少不了。初识 TiDB 使用 NoSQL 式资料库看似可以完美的提供出一个解法,但需要付出的成本也是高昂的。于是我们把眼光落到了 MySQL Cluster 上,这时看到了 Google 发布 Cloud Spanner beta 的新闻,NewSQL?这是什么? 很快的引起了我们浓厚的兴趣,然后经过多方调研,我们发现了 TiDB:一个开源在 GitHub 上的 NewSQL 资料库。官方也持续不断发布了很多相关的文章,随着对 TiDB 的认识,认为对于目前现况是很合适的最佳化方案,相容于 MySQL,高可用性,容易水平扩展。在可行性评估与测试的时候,一开始采用了 TiKV 3 台搭配 PD 3 台,TiDB 2 台混搭 PD 的架构,使用了文件建议的 ansible 安装,这时遇到两个困难,第一个是在 ansible 检查机器效能的时候会因为硬碟读写效能而无法安装。由于是使用云端机器,所以对硬体方面没有太大的弹性,只好自己手动去修改脚本才能顺利安装。第二个也是在 ansible 里面会检查 ntp 同步服务是否启动,但是 centos7 预设的时间同步服务是 chrony,所以也是修改了脚本(后来的版本有提供 flag 能切换,也有自动安装 ntp 的选项),总之是顺利安装了。这时因为 PingCAP 才刚发布了 ansible 安装的方式,所以文件对于水平扩展部分,如新增 TiKV、 PD 、TiDB 机器,或者移除机器,官方 doc 没有详细说明,于是就写了封 mail 联系 PingCAP,发完信出去吃午餐回来,官方已经回复并且邀请加入 wechat,提供更即时的沟通跟支援,实在是很令人惊艳。备份与还原的机制,TiDB 在这部分提供了一个性能比官方的 mysqldump 更快的方案- mydumper/loader,这里我们一开始使用 GitHub 上的 source 自己 build,但是有点问题,跟官方交流后,才知道原来 tidb-enterprise-tools 这个工具包里面已经有提供了。mydumper 能够使用正则表达式去挑选出想要的 database 跟 table 备份,对于原本架构就会分库分表的设计,更添加了不少方便,备份出来的档案会全部放在一个资料夹内,使用 loader 就可以将这个备份的资料再次进入 DB。但是采用 TiDB 不就是为了使用同一张表的便利性吗?当巨量的数据都在同一个表内的时候,虽然 mydumper/loader 的效能很好,由于必需全量备份的关系,还是需要一点时间,因为 TiDB 也支援 mysqldump,所以如果需要进行增量备份,也可以采用 mysqldump 搭配 where 条件式来进行。因为需要对于不同的服务进行权限的管制,所以也一并测试了 TiDB 的帐号权限机制,那时还是 pre-GA 版本,根据文件上赋予模糊匹配会无法获得权限,必须要完全匹配才能正常取得;另外是在使用 revoke 回收权限方面会没有正确收回权限。但是在回报 PingCAP 后,很快的在 GA 版中就修复了。上线 TiDB 初期上线采用了 4 core cpu、记忆体 32 GB 作为 TiKV,8 core cpu、记忆体 16 GB 作为 TiDB/PD,3 台 TiKV、3 台 PD 、2 台 TiDB 跟 PD 混搭的方式。透过 prometheus 观察,发现 loading 都集中在同一台 TiKV 上,且 loadaverage 在高峰期间会冲到 7 以上,初步判断可能是规格不够,于是决定将 TiKV 都提升到 16 core 、24 GB 记忆体。因为线上正在举办活动,所以不希望停机,采用先增加三台 TiKV 机器同步后,再移除三台原本 TiKV 的方式进行,也特别感谢 PingCAP 在置换机器中间,一直在线上支援,过程中很平顺的完成了切换机器。机器提高规格后,高峰期的 loadaverage 下降到 4,但是还是会集中在其中某一台 TiKV 上不会分散到三台,在 PingCAP 的协助分析下,判断出可能是业务行为中的 select count(1) 这个 SQL 太过频繁,涉及该业务数据一直存取在同 1 个 region,通过尝试在文件上的提高开发度的方式,还是无法解决(最新的 v1.1 版有在对 count(*) 进行最佳化),最后结合数据特性对业务行为进行了变更,loadavg 几乎都是保持在 1 以下。比较原本架构与 TiDB 架构,原本架构上是采用多组 DB 的方式来让使用者分布在不同组 DB 上面,来达到所需的效能。但是当其中某几组负荷较大时,其他组 DB 并无法协助分担负荷。采用 TiDB 的架构后,在机器的使用上更有效率,并且在使用后台查找分析资料时,原本的架构下,只要时间一拉长到一个月以上,就会对该组 DB 的效能造成影响,而在 TiDB 的架构下,并不会有这样的问题。现在运营上最直接的效益就是硬体成本的节约,原架构下每一组 DB 规格都必须符合尖峰期间的运作。但是在 TiDB 的架构下,将全部的机器整合成一体后,只要全部机器加总起来的效能能够达到尖峰期间即可,在监控上搭配 Prometheus/Grafana 的视觉化系统与能弹性的自订规则的警示,也免去了原本使用 snmp 自建监视系统的成本。另外由于降低了撰写程式的复杂度,当运营企划人员提出新的想得知的分析资料时,能够更快的从资料库中取出,而可以有更多的时间来应对与分析使用者偏好。未来计划 目前正在评估 TiSpark 的使用,未来计划将后台分析资料部份,改采用 TiSpark。因为 TiSpark 可以直接操作 TiKV,也能够应用 Spark 提供的许多现成的函式库来对收集到的 log 做数据分析。预期利用 Spark 的机器学习来初步判断系统内的每个功能是否正常运作,并提出警示,例如当使用者的登入频率异常时等,来协助人工监控游戏运行状态。 作者:张明塘,FUNYOURS JAPAN 运营系统工程師 "}, {"url": "https://pingcap.com/cases-cn/user-case-mobike/", "title": "TiDB 在摩拜单车在线数据业务的应用和实践", "content": " 背景 摩拜单车于 2015 年 1 月成立,2016 年 4 月 22 日地球日当天正式推出智能共享单车服务,截至 2017 年 11 月中旬,已先后进入国内外超过 180 个城市,运营着超过 700 万辆摩拜单车,为全球超过 2 亿用户提供着智能出行服务,日订单量超过 3000 万,成为全球最大的智能共享单车运营平台和移动物联网平台。摩拜每天产生的骑行数据超过 30TB,在全球拥有最为全面的骑行大数据,飞速增长的业务使摩拜面临数据库扩展与运维的巨大挑战。面对飞速增长的并发数与数据量,单机数据库终将因无法支撑业务压力而罢工。在摩拜正式上线以来,我们就在不断思考数据库扩展和运维的未来,近年来业内对数据库进行扩展的常见的方案是通过中间件把数据库表进行水平拆分,将表内数据按照规则拆分到多个物理数据库中。使用这样的中间件方案,在数据库扩容时需要先停下业务,再重构代码,之后进行数据迁移,对于摩拜这样与时间赛跑的创业公司来讲代价巨大,中间件方案对业务过强的侵入性,不支持跨分片的分布式事务,无法保证强一致性事务的特性都使我们望而却步。摩拜单车于 2017 年初开始使用 TiDB,从最早的 RC3、RC4、PreGA、到现在的 1.0 正式版,一步步见证了 TiDB 的成熟和稳定。目前支撑着摩拜内部的实时分析和部分线上业务,同时正在规划迁移更多的线上业务至 TiDB。目前,TiDB 在摩拜部署了数套集群,近百个节点,承载着数十 TB 的各类数据。TiDB 在摩拜的角色和主要应用场景 在摩拜,TiDB 是一个核心的数据交易与存储支撑平台,引入它的主要目的是用来解决海量数据的在线存储、大规模实时数据分析和处理。在我们看来,TiDB 的好处主要有: 弹性扩容。具有 NoSQL 类似的扩容能力,在数据量和访问流量持续增长的情况下能够通过水平扩容提高系统的业务支撑能力,并且响应延迟稳定; 简单易用。兼容 MySQL 协议,基本上开箱即用,完全不用担心传统分库分表方案带来的心智负担和复杂的维护成本,而且用户界面友好,常规的技术技术人员都可以很高地进行维护和管理; 响应及时。因为和 PingCAP 团队有非常深入的合作关系,所以有任何问题都可以第一时间和 PingCAP 团队直接沟通交流,遇到问题都能很快的处理和解决。 下面介绍 TiDB 的应用场景:场景一:开关锁日志成功率统计 开关锁成功率是摩拜业务监控的重点指标之一。在每次开、关锁过程中,用户和锁信息会在关键业务节点产生海量日志,通过对线上日志的汇总分析,我们把用户的行为规整为人和车两个维度,通过分布式、持久化消息队列,导入并存放到 TiDB 里。在此过程中,通过对不同的实体添加不同的标签,我们就能方便地按照地域、应用版本、终端类型、用户、自行车等不同的维度,分别统计各个类别的开锁成功率。按照我们的估计,这个业务一年的量在数百亿,所以使用单机的 MySQL 库需要频繁的进行归档,特别是遇到单机数据库瓶颈的情况下,扩容更是带来了非常大的挑战,这在我们有限的人力情况下,完全是个灾难。所以要支撑整个 Mobike 的后端数据库,我们必须要寻找简单易用的方案,极大地减少在单个业务上的人力成本开销。其次,根据我们之前使用分库分表的经验,对于这类需要频繁更新表结构进行 DDL 操作的业务,一旦数据量过大,很很容易出现数据库假死的情况,不仅影响服务的可用性,更严重的是很可能导致数据不一致的情况出现。最后,我们希望不管今后的业务量如何激增,业务需求如何变化,都可以保持业务逻辑可以很方便地升级支持。在方案设计时,我们进行考察了 MySQL 分库分表的方案和 TiDB 方案的对比。我们先估计了可能的情况: 新业务上线,在线变动肯定是经常发生的; 尽可能存长时间的数据,以备进行统计比较; 数据要支持经常性的关联查询,支撑运营组的临时需求; 要能支撑业务的快速增长或者一些特殊活动造成的临时流量。 考虑到这些情况,MySQL 分库分表的方案就出现了一些问题,首先频繁变动表结构就比较麻烦,而 TiDB 可以进行在线 DDL。数据生命期比较长,可以设计之初做一个比较大的集群,但是弹性就比较差,针对这个问题,TiDB 可以根据需要,弹性的增加或者减少节点,这样的灵活性是 MySQL 分库分表没有的。另外,数据要支持频繁的复杂关联查询,MySQL 分库分表方案完全没办法做到这一点,而这恰恰是 TiDB 的优势,通过以上的对比分析,我们选择了 TiDB 作为开关锁日志成功率统计项目的支撑数据库。目前,大致可以将到端到端的延时控制在分钟级,即,若有开锁成功率下降,监控端可即时感知,此外,还能通过后台按用户和车查询单次故障骑行事件,帮助运维人员快速定位出故障的具体位置。场景二:实时数据分析 数据分析场景中,TiDB 可以从线上所有的 MySQL 实例中实时同步各类数据,通过 TiDB 周边工具 Syncer 导入到 TiDB 进行存储。这个业务的需求很简单,我们线上有数十个 MySQL 集群,有的是分库分表的,有的是独立的实例。这些孤立的数据要进行归集以便供业务方进行数据分析。我们一开始计划把这些库同步到 Hive 中,考察了两种方式,一种是每日全量同步,这么做,对线上的库压力以及 Hive 的资源开销都会越来越大。另一种是增量同步,这种方式非常复杂,因为 HDFS 不支持 update,需要把每日增量的部分和之前的部分做 merge 计算,这种方法的优点是在数据量比较大的情况下,增量同步对比全量同步要更快、更节省空间,缺点是占用相当一部分 Hadoop 平台的计算资源,影响系统稳定性。TiDB 本身有很多不错的工具,可以和 MySQL 的生态方便的连接到一起。这里我们主要使用了 TiDB 的 syncer 工具,这个工具可以方便的把 MySQL 实例或者 MySQL 分库分表的集群都同步到 TiDB 集群。因为 TiDB 本身可以 update,所以不存在 Hive 里的那些问题。同时有 TiSpark 项目,数据进入 TiDB 以后,可以直接通过 Spark 进行非常复杂的 OLAP 查询。有了这套系统,运营部门提出的一些复杂在线需求,都能够快速简洁的完成交付,这些在 Hadoop 平台上是无法提供这样的实时性的。目前,该集群拥有数十个节点,存储容量数十 T,受益于 TiDB 天然的高可用构架,该系统运行稳定,日后集群规模日益变大也仅需简单增加 x86 服务器即可扩展。后台开发、运维、业务方等都可以利用 TiDB 的数据聚合能力汇总数据,进行数据的汇总和分析。场景三:实时在线 OLTP 业务 如前所述,对比传统的分库分表方案,TiDB 的灵活性和可扩展性在实时在线业务上优势更加明显。根据我们的测试,TiDB 在数据量超过 5 千万时,对比 MySQL 优势较大,同时协议层高度兼容 MySQL,几乎不用修改业务代码就能直接使用,所以 TiDB 集群对于数据量大的实时在线业务非常适合。目前,摩拜主要上线了两套在线 OLTP 业务,分别是摩豆信用分业务和摩豆商城业务。摩豆信用分业务 摩拜单车信用分业务与用户骑行相关,用户扫码开锁时先行查询用户信用积分判断是否符合骑行条件,待骑行完成后,系统会根据用户行为进行信用分评估并进行修改。当单车无法骑行,上报故障核实有效后增加信用分、举报违停核实有效后降低信用分;但是如果不遵守使用规范,则会扣除相应的信用分;例如用户将自行车停在禁停区域内,系统就会扣除该用户的部分信用分作为惩罚,并存档该违停记录。当用户的信用分低于 80 分时,骑行费用将会大幅上升。摩豆商城业务(APP 中的摩拜成就馆) 魔豆商城业务即摩拜成就馆,用户的每一次骑行结束后,系统会根据骑行信息赠送数量不等的省时币、环保币、健康币作为积分,通过积累这些积分可以在摩拜成就馆内兑换相应积分的实物礼品。这些业务的共同特点: 7 * 24 * 365 在线,需要系统非常健壮,在任何状况下保证稳定运行; 数据不希望删除,希望能一直保存全量数据; 平时高峰期并发就非常大,搞活动的时候并发会有几倍的增长; 即便有业务变更,业务也不能暂停。 由于是典型 OLTP 场景,可选项并不多,而且数据量增长极快,这些数据库的数据在一年内轻松达到数百亿量级。这些场景在我们有了 TiDB 的使用经验以后,发现 TiDB 的所有特性都非常契合这种海量高并发的 OLTP 场景。TiDB 的容量/并发可随意扩展的特性不在赘述,支持在线 DDL 这个特性特别适合这些业务,有需要业务更改不会阻塞业务,这是我们业务快速迭代比较需要的特性。目前,这两个在线 OLTP 集群拥有数十个节点,百亿级数据,上线以后非常稳定,PingCAP 客户支持团队也协助我们进行该集群的日常运维工作。场景四:违章停车记录/开锁短信库等日志归集库 相对于传统的针对不同的业务分别部署 MySQL 集群的方案,TiDB 在可扩展性和在线跨库分析方面有较大优势。在部署 TiDB 之前,摩拜面对新增的业务需要对其进行单独的规划和设计,并根据业务的数据量,增速以及并发量设计 MySQL 的分库分表方案,这些重复的预先设计工作在所难免。另一方面,不同业务之间往往是有关联的,当运营部门需要不同业务的汇总数据时,就变得异常麻烦,需要新建一个临时的数据汇总中心,例如新建一套 MySQL 分库分表的集群,或者临时向大数据组申请 Hive 的空间,这都让数据提供的工作变得麻烦。有了 TiDB 以后,此类业务的开发和数据提供都变得非常简单,每次新需求下来,只需要按照新增数据量增加 TiKV 节点的数量即可,因为整个集群变得比较大,并发承载能力非常强,基本不需要考虑并发承载能力。特别的好处是,因为这些业务有相关性的业务,放在一个独立的数据库中,运营需要提供某几类某段时间的数据时就变得极为方便。基于 TiSpark 项目,Spark 集群可以直接读取 TiDB 集群的数据,在一些运营需要实时数据提供的场景,不再需要按照原有的提供数据到大数据平台,设计 ETL 方案,运营再去大数据部门沟通运算逻辑。而是直接在 TiDB 现有数据的基础上,直接提出复杂的分析需求,设计 Spark 程序进行在线的直接分析即可。这样做,我们非常容易就可以实现一些实时状态的分析需求,让数据除了完成自己的工作,还能更好的辅助运营团队。使用过程中遇到的问题和优化 在说优化问题之前,先看 TiDB 的架构图,整个系统大致分为几个部分。其中: PD 是整个集群的管理模块,负责:元信息管理、集群调度和分配全局递增非连续ID。 TiDB,是客户端接入层,负责 SQL 解析、执行计划优化,通过 PD 定位存储计算所需数据的 TiKV 地址。 TiKV,是数据的存储层,底层是基于 RocksDB 的 KV 引擎,并在其上分别封装 MVCC 和 Raft 协议,保证数据的安全、一致。 TiSpark,是 Spark 接入层,负责把 Spark 和 TiKV 连接到一起,在执行非常重的 OLAP 业务时可以利用到 Spark 集群的优势。 在使用过程中,遇到过不少问题,但是在我方和 PingCAP 技术团队的充分交流和协作下,都得到了比较完善的解决,下面挑选最为重要的资源隔离与优化展开。TiKV 中数据存储的基本单位是 Region,每个 Region 都会按顺序存储一部分信息。当一个 Region 包含多个表的数据,或一台机器上有多个 Region 同时为热点数据时,就容易产生资源瓶颈。PD 在设计之初考虑了这方面的问题(专门设计了 HotRegionBalance),但是,它的调度粒度是单个 Region,并且,整个调度基于这样的假设:即每个 Region 的资源消耗对等,不同 Region 之间没有关联,同时尽量保持 Region 均摊在所有 Store。但当一个集群同时承载多个库,或一个库中包含多个表时,发生资源瓶颈的概率会明显提升。针对这个问题,我们和 PingCAP 技术团队合作,对 TiDB 做了以下优化。优化一:基于 Table 的分裂 这个修改的目的是解决小表数据的相互影响的问题。当有新表数据插入某一 Region 时,TiKV 会根据当前 Region 的 Key Range 计算出 TableID,如果发现插入的 Key 不在这个 KeyRange 中,会对这个 Region 提前分裂,这就保证了每个 Region 只包含一个表的数据。优化二:表级别的资源隔离 与此同时,我们在 PD 增加了 TableID 和 Namespace 之间的映射关系以及 NameSpace 和 TiKV Store 的映射关系,通过把上述关系持久化到 eEtcd 里,保证该映射关系的安全。当数据插入时,可以在 TiDB 层面拿到 TableID,进而从 PD 找出目标 Region 所在的 TiKV,保证新插入的数据不会放到其他 TiKV。另外,我们还与 PingCAP 团队共同开发实现了一个 NameSpace 调度器,把未规整的 Region 调度回它应在的 TiKV 里,进而在表级别保证数据不会相互干扰。优化三:管理工具 最后的问题是管理 NameSpace 的问题。好在 TiDB 在早期设计时保留了足够的灵活性,通过 TiDB 原有接口,我们只需要调用相关 API 即能通过表名拿到 TableID。同时我们在 PD 的命令行管理台 pc-ctl 中增加了 HTTP 接口,管理确认 Table Name 和 TableID 之间的对应关系。后记 部署 TiDB 近一年来,摩拜单车经历了用户数量近十倍,日骑行数据数十倍的增长,依靠 TiDB 在线扩容的能力,我们完成了多次数据库扩容与服务器更换,而且这些操作对业务是完全透明的,我们可以更专注于业务程序的开发与优化,而无须了解数据库的分片规则,对于快速成长的初创公司,这有着很强的借鉴意义。另外深度参与 TiDB 的开发并和开源社区紧密的互动,也使我们获得了很多有益的反馈,极大降低了代码维护成本。未来,我们会联合 PingCAP 进一步丰富多集群的管理工具,进行更深入的研究和开发,持续提升 TiDB 的性能,将 TiDB 应用到更多的业务中。 作者:丁宬杰 / 胡明,Mobike 技术研发部基础平台中心 "}, {"url": "https://pingcap.com/cases-cn/user-case-360/", "title": "TiDB 在 360 金融贷款实时风控场景应用", "content": " 背景 近几年来基于互联网渠道的现金贷业务发展十分迅猛,无论是新兴的互联网企业还是传统的金融机构,都想在这个领域快速占领市场,攫取客户。然而在线贷款业务与其他互联网业务有着明显的不同,源自金融的基因决定了重视风险的必要性,这不仅关系到产品的收益,也直接影响了产品是否可以成功。将业务推到线上意味着无法准确的获取客户信息,只能通过有限的渠道验证客户的真实性和偿还能力,极大的增加了风险成本。如果申请步骤过于繁琐则降低了用户体验,不利于产品的推广和客户的使用。因此对于互联网贷款风控的一项挑战就是能够在尽可能短的时间内,有限数据的情况下,给出明确的风险判断。应用 建立风险策略的过程中,使用各种风险变量以及相关的衍生变量,通过专家模型进行评分,是一种较为典型的方法。实际应用中,我们发现除了已经被广泛使用的消费行为数据,基本收入数据等,基于特定维度的用户间社交关系也是比较有效的模型变量。在使用这些变量的过程中,我们面临最直接的问题是数据量。如果考虑将用户手机通讯录中出现的电话号码作为一项关系关联的形式,假设每位用户通讯录中联系人的个数平均为 100 个,那 100 万个注册用户就有对应大约 1 亿个联系人。事实上,在系统上线大约 1 年不到的时间内,我们几张存储社交关系的表已经达到了大约 50 亿左右的规模。相对于数据存储,变量的衍生加工和查询匹配是个更加有挑战性的工作。一个人的社交关系是个很典型的「图」数据结构。而很多专家模型中的规则是需要匹配某个用户 3 层以上关系的,最简单的就是匹配用户通过联系人关系,跃进 3 层后,命中系统黑名单的人数。我们还是按照平均 100 个联系人来估算,跃进 3 层后,需要匹配的关联人数为 100 * 100 * 100,即 100 万。而类似计算量的规则不在少数,需要调用这些计算规则的业务场景也较为频繁,同时对响应时间的要求也高。V1.0 版本的解决方案 在评估阶段,我们考虑了几种方案,各有利弊。首先被淘汰的是使用 MySQL 的解决方案。使用关系型数据库的优势是在查询方面的便捷性。在开发效率上,SQL 是开发人员和数据分析人员的必备技能,能够较快的在功能上实现需求。但是在数据存储和计算层面,MySQL 的表现则差强人意。在面对大数据量时,MySQL 能采取的水平扩展策略无非是分库分表,这样的后果就是查询逻辑变的非常复杂,不易维护,且性能下降的较为严重。另一个方案是把 HBase 作为数据存储的解决方案。它的优点很明显,可以水平扩展,数据量不再是瓶颈。但是它的缺点也同样明显,即对开发人员不友好,查询的 API 功能性较差,只能通过 key 来获取单条数据,或是通过 scan API 来批量读取。更关键的是 HBase 对图这样的数据结构支持的不好,只能通过使用 tall table 和存储冗余数据的形式来模拟。第三个方案是使用纯粹的图数据库。首先我们考察了开源的 Titan,发现这个项目已经废弃了,主力团队貌似研发了一个新的商业图数据库,并成立了公司。而且 Titan 的存储引擎也是使用了 HBase 和 Cassandra(根据需求两者选一),性能并不能满足我们的要求。接着我们考察了两款开源的商业产品 Neo4j 和 OrientDB。他们两者都提供了免费的社区版本,当然在功能上比商业版少了些。其中 Neo4j 的社区版不支持 HA,只能在单机上运行。而 OrientDB 的数据版支持 HA 和 Sharding。在编程接口上两者都支持各种主流的编程语言。Neo4j 提供了自家独创的,基于模式匹配的查询语言 cypher。OrientDB 则提供了类 SQL 的语法 API,可谓各有所长。最终上线的方案是混用了 HBase 和 Neo4j 两种存储。HBase 使用了 9 台 32G 内存,16 核的服务器集群,主要负责存储业务对象的基本信息,和第一层的关联信息。Neo4j 则负责图数据结构的存储,使用了单台 256G 内存 2T SSD 的服务器。上线后,相关实时分析接口的 TPS 大约为 300,90% 的相应时间保持在 200ms。部分表的数据量保持在 3000 万 ~ 6 亿的规模,部分核心表大约在 30 亿左右。V2.0 版本 - 引入 TiDB 和优化 系统上线后总体较为稳定,但是仍然存在一些亟需解决的问题。Neo4j 作为存储图数据的系统,在社区版本的功能上只能支持单节点,无法进行水平扩展,虽然现阶段来看无论是性能上还是功能上都可以满足业务的需求,但是可以预见在不久的将来就会有瓶颈。而 HBase 的缺点在于数据结构过于简单,无法给 OLAP 的系统和分析人员提供易用的数据接口,只能通过批量的 ETL 来同步数据至数据仓库,实时性较弱。在和 PingCAP 的技术团队进行交流后,了解到了 TiDB 这个由国人自己研发的分布式数据库。TiDB 中吸引我们的特点有很多,其中能帮助我们解决现有问题的主要集中于两点。其一是能够在近似无限的水平扩展的同时保证事务特性。这样不仅避免了分库,分表的繁琐,也让海量数据能够以关系模型进行存储变为可能。其次是能够高度兼容 MySQL 协议,不仅为开发人员及数据人员都提供了良好的应用接口。基于这些特性,我们发现线上 OLTP 和 OLAP 的界限已经非常模糊,在某些业务场景已经可以完全的融为一体。与 PingCAP 的技术同事沟通后,我们很快的设计了一套新的技术方案(V2.0)。为了考虑到技术方案迁移的稳定性,我们先使用 Kafka 作为一条数据旁路,将所有的基础数据在 TiDB 集群中存储一份。同时将 Neo4j 中大约 70 亿个 vertex 和相关 edge 数据迁出,移入 TiDB 中存储。然后我们基于关系模型的 SQL 接口实现了功能所需的部分图算法,包括最短路径,多节点连通性检查等。虽然在实现过程中要比使用 Neo4j 工作量多一些,但是在性能上,特别是吞吐量上有不少提升。原先 Neo4j 的事务模型较为笨重,在更新 vertex 时较多,且并发量大的时候很容易造成长时间的事务锁,严重降低系统的吞吐性能。最终上线时,我们为 TiDB 部署了 9 台服务器的集群。其中 3 台作为 PD 和 TiDB 的服务器,6 台作为 TiKV 的存储服务器。在运行一段时间后,除了一些业务逻辑上的 bug,表现一直很稳定,从未出过一次问题。而且随着业务量的增大,TPS 指标 也提升至 5000 左右,整个数据库平台的峰值计算能力提升了10 倍左右,但是平台整体的吞吐量和响应时间都没有特别的抖动,一直稳定在可接受范围内。对于风险分析人员,最大的提升就是就是可以用他们熟悉的 SQL 工具直接连接生产的 TiDB 库进行分析工作。不仅实时性大大增加,工作效率得到了质的提升,也省却了部分 ETL 的工作。Next Step 在对 TiDB 有了实际的认识和应用经验后,我们计划使用 TiDB 来取代 HBase,存储用户风险模型的相关数据。同时尝试在 TiDB 中慢慢迁入 Neo4j 的数据,最终回到关系模型的架构下,只是我们手中不再是日渐老去的 MySQL,而是新一代的分布式数据库 TiDB。 作者:金中浩,360 金融 / 数据智能部 / 部门总监 "}, {"url": "https://pingcap.com/cases-cn/user-case-fengchao/", "title": "TiDB at 丰巢:尝鲜分布式数据库", "content": " 随着丰巢业务系统快速增长,其核心系统的数据量,早就跨越了亿级别,而且每年增量仍然在飞速发展。整个核心系统随着数据量的压力增长,不但系统架构复杂度急剧增长,数据架构更加复杂,传统的单节点数据库,已经日渐不能满足丰巢的需求,当单表数量上亿的时候,Oracle 还能勉强抗住,而 MySQL 到单表千万级别的时候就难以支撑,需要进行分表分库。为此,一款高性能的分布式数据库,日渐成为刚需。思考 在互联网公司业务量增大之后,并行扩展是最常用、最简单、最实时的手段。例如负载均衡设备拆流量,让海量流量变成每个机器可以承受的少量流量,并且通过集群等方式支撑起来整个业务。于是当数据库扛不住的时候也进行拆分。但有状态数据和无状态数据不同,当数据进行拆分的时候,会发生数据分区,而整个系统又要高可用状态下进行,于是数据的一致性变成了牺牲品,大量的核对工具在系统之间跑着保证着最终的一致性。在业务上,可能业务同学经常会遇到分过库的同学说,这个需求做不了,那个需求做不了,如果有 sql 经验的业务同学可能会有疑问不就是一条 sql 的事情么,其实这就是分库分表后遗症。为此,我们需要有个数据库帮我们解决以上问题,它的特性应该是: 数据强一致:支持完整的 ACID; 不分表分库:无论多少数据我们只管插入不需要关心啥时候扩容,会不会有瓶颈; 数据高可用:当我们某台数据库的少部分机器磁盘或者其他挂了的时候,我们业务上可以无感知,甚至某个城市机房发生灾难的时候还可以持续提供服务,数据不丢失; 复杂 SQL 功能:基本上单库的 SQL,都可以在这个数据库上运行,不需要修改或者些许修改; 高性能:在满足高 QPS 的同时,保证比较低的延时。 选型 根据以上期望进行分析,我们分析了目前市面上存在的 NewSQL 分布式数据库,列表如下:在综合考虑了开源协议,成熟度,可控度,性能,服务支撑等综合因素之后,我们选择了 TiDB,它主要优势如下: 高度兼容 MySQL 大多数情况下,无需修改代码即可从 MySQL 轻松迁移至 TiDB,分库分表后的 MySQL 集群亦可通过 TiDB 工具进行实时迁移。  水平弹性扩展 通过简单地增加新节点即可实现 TiDB 的水平扩展,按需扩展吞吐或存储,轻松松应对高并发、海量数据场景。 分布式事务  TiDB 100% 支持标准的 ACID 事务。 金融级别的高可用性 相比于传统主从(M-S)复制方案,基于 Raft 的多数派选举协议可以提供金融级的 100% 数据强一致性保证,且在不丢失大多数副本的前提下,可以实现故障的自动恢复(auto-failover),无需人工介入。基于如上的原因,我们选择了 TiDB,作为丰巢的核心系统的分布式数据库,来取代 Oracle 和 MySQL。评估 1. 性能测试 TiDB 的基准测试,使用的工具是 sysbanch 进行测试,使用了 8 张基础数据为一千万的表,分别测试了 insert,select,oltp 和 delete 脚本得到数据如下,查询的 QPS 达到了惊人的 14 万每秒,而插入也稳定在 1 万 4 每秒。核心服务器配置:测试结果:通过~2. 功能测试 通过~接入 因为是核心系统,安全起见,我们采取了多种方案保证验证项目接入的可靠性,保证不影响业务。1. 项目选择 在寻找第一个接入项目的时候,我们以下面 4 个特征,进行了选择:最终,我们选择了推送服务。因为推送服务是丰巢用来发送取件通知的核心服务,量非常大,但逻辑简单,而且有备选外部推送方案,所以即便万一出现问题,而不会影响用户。2. 代码修改 因为 TiDB 是完全兼容 MySQL 语法的,所以在这个项目的接入过程中,我们对代码的修改是很细微的。SQL 基本零改动,主要是外围代码,包括: 异步接口修改,数据异步化入库 同步接口修改,实现异常熔断 停止内嵌数据迁移代码 以上三点,保证了整个系统在不强依赖于数据库,并且能在高并发的情况下通过异步落库保护数据库不被压垮,并且在数据库发生问题的时候,核心业务可以正常进行下去。效果 1. 查询能力 接入 TiDB 之后,原先按照时间维度来拆分的十几个分表,变成了一张大表。最明显的变化,是在大数据量下,数据查询能力有了显著的提升。2. 监控能力 TiDB 拥有很完善的监控平台,可以直观的看到容量,以及节点状态:还能了解每个节点负载和 sql 执行的延时:当然还能了解所在机器上的位置,CPU 内存等负载情况:网络状态也能清晰的监控到:所有这些能让团队能分析出来有问题的 sql,以及数据库本身的问题。小结 TiDB 的接入过程,整体还是非常顺利的,由于之前做了很多接入的保障工作,当天切换流量到 TiDB 的过程只用了 10 分钟的时间,在此也要感谢 TiDB 对于 MySQL 语法的兼容性的支持,以及 PingCAP 提供的各种有用的工具。到目前为止,系统的稳定运行了一个多月,很好的满足了丰巢的业务需求。TiDB 的改造完成之后,丰巢推送服务对大部分消息进行了落地和查询,截止目前为止,推送服务最大的日落地量已经达到了 5 千万,而如果现在推送服务还使用的还是 MySQL 的方案,就需要上各种的分库分表方案,很多细致的业务就无法或者难以开展。此次 TiDB 的改造,只是丰巢对于分布式数据技术探索的一小步,未来丰巢会将更多的分布式技术,引入到更多的业务系统,打造更加极致的产品和服务。"}, {"url": "https://pingcap.com/cases-cn/user-case-shopee/", "title": "TiDB 助力东南亚领先电商 Shopee 业务升级", "content": " 作者介绍:刘春辉,Shopee DBA;洪超,Shopee DBA。 一、业务场景 Shopee 是东南亚和台湾地区领先的电子商务平台,覆盖新加坡、马来西亚、菲律宾、印度尼西亚、泰国、越南和台湾等七个市场。Shopee 母公司 Sea 为首家在纽约证券交易所上市的东南亚互联网企业。2015 年底上线以来,Shopee 业务规模迅速扩张,逐步成长为区域内发展最为迅猛的电商平台之一: 截止 2018 年第三季度 Shopee APP 总下载量达到 1.95 亿次,平台卖家数量超过 700 万。 2018 年第一季度和第二季度 GMV 分别为 19 亿美金和 22 亿美金,2018 上半年的 GMV 已达到 2017 全年水平。2018 年第三季度 GMV 达到了创纪录的 27 亿美元, 较 2017 年同期年增长率为 153%。 2018 年双 11 促销日,Shopee 单日订单超过 1100 万,是 2017 年双 11 的 4.5 倍;刚刚过去的双 12 促销日再创新高,实现单日 1200 万订单。 图 1 Shopee 电商平台展示图我们从 2018 年初开始调研 TiDB,6 月份上线了第一个 TiDB 集群。到目前为止我们已经有两个集群、60 多个节点在线运行,主要用于以下 Shopee 业务领域: 风控系统:风控日志数据库是我们最早上线的一个 TiDB 集群,稍后详细展开。 审计日志系统:审计日志数据库存储每一个电商订单的支付和物流等状态变化日志。 本文将重点展开风控日志数据库选型和上线的过程,后面也会约略提及上线后系统扩容和性能监控状况。二、选型:MySQL 分库分表 vs TiDB 图 2 风控日志收集和处理示意图风控系统基于大量历史订单以及用户行为日志,以实时和离线两种方式识别平台上的异常行为和欺诈交易。它的重要数据源之一是各种用户行为日志数据。最初我们将其存储于 MySQL 数据库,并按照 USER_ID 把数据均分为 100 个表。随着 Shopee 用户活跃度见长,数据体积开始疯长,到 2017 年底磁盘空间显得十分捉襟见肘了。作为应急措施,我们启用了 InnoDB 表透明压缩将数据体积减半;同时,我们把 MySQL 服务器磁盘空间从 2.5TB 升级到了 6TB。这两个措施为后续迁移 MySQL 数据到 TiDB 多争取了几个月时间。关于水平扩容的实现方案,当时内部有两种意见:MySQL 分库分表和直接采用 TiDB。1. MySQL 分库分表 基本思路:按照 USER_ID 重新均分数据(Re-sharding),从现有的 100 个表增加到1000 个甚至 10000 个表,然后将其分散到若干组 MySQL 数据库。 优点:继续使用 MySQL 数据库 ,不论开发团队还是 DBA 团队都驾轻就熟。 缺点:业务代码复杂度高。Shopee 内部若干个系统都在使用该数据库,同时我们还在使用 Golang 和 Python 两种编程语言,每一个系统都要改动代码以支持新的分库分表规则。 2. 直接采用 TiDB 基本思路:把数据从 MySQL 搬迁至 TiDB,把 100 个表合并为一个表。 优点:数据库结构和业务逻辑都得以大幅简化。TiDB 会自动实现数据分片,无须客户端手动分表;支持弹性水平扩容,数据量变大之后可以通过添加新的 TiKV 节点实现水平扩展。理想状况下,我们可以把 TiDB 当做一个「无限大的 MySQL」来用,这一点对我们极具诱惑力。 缺点:TiDB 作为新组件首次引入 Shopee 线上系统,我们要做好「踩坑」的准备。 最后,我们决定采用 TiDB 方案,在 Shopee 内部做「第一个吃螃蟹的人」。风控日志数据库以服务离线系统为主,只有少许在线查询;这个特点使得它适合作为第一个迁移到 TiDB 的数据库。三、上线:先双写,后切换 我们的上线步骤大致如下: 应用程序开启双写:日志数据会同时写入 MySQL 和 TiDB。 搬迁旧数据:把旧数据从 MySQL 搬到 TiDB,并完成校验确保新旧数据一致。 迁移只读流量:应用程序把只读流量从 MySQL 逐步迁移至 TiDB(如图 3 所示)。 停止双写:迁移过程至此结束。 图 3 迁移过程图:保持双写,逐步从读 MySQL 改为读 TiDB双写方式使得我们可以把整个切换过程拖长至几个月时间。这期间开发团队和 DBA 团队有机会逐步熟悉新的 TiDB 集群,并充分对比新旧数据库的表现。理论上,在双写停掉之前,若新的 TiDB 集群遭遇短时间内无法修复的问题,则应用程序有可能快速回退到 MySQL。除此之外,采用双写方式也让我们有了重构数据库设计的机会。这一次我们就借机按照用户所属地区把风控日志数据分别存入了七个不同的逻辑数据库:rc_sg,rc_my,rc_ph,…,rc_tw。Shopee 用户分布于七个不同地区。迁移到 TiDB 之前,所有日志数据共存于同一个逻辑数据库。按照地区分别存储使得我们能够更为方便地为每个地区的日志定制不同的数据结构。四、硬件配置和水平扩容 上线之初我们一共从 MySQL 迁移了大约 4TB 数据到 TiDB 上。当时 TiDB 由 14 个节点构成,包括 3 个 PD 节点,3 个 SQL 节点和 8 个 TiKV 节点。服务器硬件配置如下: TiKV 节点 CPU: 2 * Intel® Xeon® CPU E5-2640 v4 @ 2.40GHz, 40 cores 内存: 192GB 磁盘: 4 * 960GB Read Intensive SAS SSD Raid 5 网卡: 2 * 10gbps NIC Bonding PD 节点和 SQL 节点 CPU: 2 * Intel® Xeon® CPU E5-2640 v4 @ 2.40GHz, 40 cores 内存: 64GB 磁盘: 2 * 960GB Read Intensive SAS SSD Raid 1 网卡: 2 * 10gbps NIC Bonding 截至目前,系统已经平稳运行了六个多月,数据量增长至 35TB(如图 4 所示),经历了两次扩容后现在集群共包含 42 个节点。图 4 风控日志 TiDB 数据库存储容量和使用状况性能 图 5 风控日志 TiDB 数据库 QPS Total 曲线风控日志数据库的日常 QPS(如图 5 所示)一般低于每秒 20K,在最近的双 12 促销日我们看到峰值一度攀升到了每秒 100K 以上。尽管数据量较之 6 个月前涨了 8 倍,目前整个集群的查询响应质量仍然良好,大部分时间 pct99 响应时间(如图 6 所示)都小于 60ms。对于以大型复杂 SQL 查询为主的风控系统而言,这个级别的响应时间已经足够好了。图 6 风控日志 TiDB 数据库两天 pct99 查询响应时间曲线五、问题和对策 TiDB 的字符串匹配区分大小写(Case Sensitive)。目前尚不支持 Case Insensitive 方式。应用程序做了适配以实现 Case Insensitive 方式的字符串匹配。 TiDB 对于 MySQL 用户授权 SQL 语法的兼容支持尚不完善。例如,目前不支持 SHOW CREATE USER 语法,有时候不得不读取系统表(mysql.user)来查看一个数据库账户的基本信息。 添加 TiKV 节点后需要较长时间才能完成数据再平衡。据我们观察,1TB 数据大约需要 24 个小时才能完成拷贝。因此促销前我们会提前几天扩容和观察数据平衡状况。 TiDB v1.x 版本以 region 数目为准在各个 TiKV 节点之间平衡数据。不过每个 region 的大小其实不太一致。这个问题导致不同 TiKV 节点的磁盘空间使用率存在明显差异。据说新的 TiDB v2.x 对此已经做了优化,我们未来会尝试在线验证一下。 TiDB v1.x 版本需要定期手动执行 Analyze Table 以确保元信息准确。PingCAP 的同学告诉我们说:当 (Modify_count / Row_count) 大于 0.3 就要手动 Analyze Table 了。v2.x 版本已经支持自动更新元数据了。我们后续会考虑升级到新版本。 六、未来规划 过去一年亲密接触之下,我们对 TiDB 的未来充满信心,相信 TiDB 会成为 Shopee 数据库未来实现弹性水平扩容和分布式事务的关键组件。当前我们正在努力让更多 Shopee 业务使用 TiDB。我们规划把 Shopee 数据从 MySQL 迁移到 TiDB 上的路线是「先 Non-transactional Data(非交易型数据),后 Transactional Data(交易型数据)」。目前线上运行的集群都属于 Non-transactional Data,他们的特点是数据量超大(TB 级别),写入过程中基本不牵涉数据库事务。接下来我们会探索如何把一些 Transactional Data 迁移到 TiDB 上。MySQL Replica 是另一个工作重点。MySQL Replica 指的是把 TiDB 作为 MySQL 的从库,实现从 MySQL 到 TiDB 实时复制数据。我们最近把订单数据从 MySQL 实时复制到 TiDB。后续来自 BI 系统以及部分对数据实时性要求不那么高的只读查询就可以尝试改为从 TiDB 读取数据了。这一类查询的特点是全表扫描或者扫描整个索引的现象较多,跑在 TiDB 可能比 MySQL 更快。当然,BI 系统也可以借助 TiSpark 绕过 SQL 层直接读取 TiKV 以提升性能。目前我们基于物理机运行 TiDB 集群,DBA 日常要耗费不少精力去照顾这些服务器的硬件、网络和 OS。我们有计划把 TiDB 搬到 Shopee 内部的容器平台上,并构建一套工具实现自助式资源申请和配置管理,以期把 DBA 从日常运维的琐碎中解放出来。七、致谢 感谢 PingCAP 的同学一年来对我们的帮助和支持。每一次我们在微信群里提问,都能快速获得回应。官方架构师同学还不辞辛劳定期和我们跟进,详细了解项目进度和难点,总是能给出非常棒的建议。PingCAP 的文档非常棒,结构层次完整清晰,细节翔实,英文文档也非常扎实。一路跟着读下来,受益良多。TiDB 选择了 Golang 和 RocksDB,并坚信 SSD 会在数据库领域取代传统机械硬盘。这些也是 Shopee 技术团队的共识。过去几年间我们陆续把这些技术引入了公司的技术栈,在一线做开发和运维的同学相信都能真切体会到它们为 Shopee 带来的改变。"}, {"url": "https://pingcap.com/cases-cn/user-case-yiguo/", "title": "TiDB / TiSpark 在易果集团实时数仓中的创新实践", "content": " 项目背景 目前企业大多数的数据分析场景的解决方案底层都是围绕 Hadoop 大数据生态展开的,常见的如 HDFS + Hive + Spark + Presto + Kylin,在易果集团,我们初期也是采取这种思路,但是随着业务规模的快速增长和需求的不断变化,一些实时或者准实时的需求变得越来越多,这类业务除了有实时的 OLTP 需求,还伴随着一些有一定复杂度的 OLAP 的需求,单纯地使用 Hadoop 已经无法满足需求。现有的准实时系统运行在 SQL Server 之上,通过开发人员编写和维护相应的存储过程来实现。由于数据量不大,SQL Server 能够满足需求,但是随着业务的发展,数据量随之增长,SQL Server 越来越不能满足需求,当数据量到达一定的阶段,性能便会出现拐点。这个时候,这套方案已完全无法支撑业务,不得不重新设计新的方案。选型评估 在评估初期,Greenplum、Kudu、TiDB 都进入了我们的视野,对于新的实时系统,我们有主要考虑点: 首先,系统既要满足 OLAP 还要满足 OLTP 的基本需求; 其次,新系统要尽量降低业务的使用要求; 最后,新系统最好能够与现有的 Hadoop 体系相结合。 Greenplum 是一套基于 PostgreSQL 分析为主的 MPP 引擎,大多用在并发度不高的离线分析场景,但在 OLTP 方面,我们的初步测试发现其对比 TiDB 的性能差很多。再说说 Kudu。Kudu 是 CDH 2015年发布的一套介于 Hbase 和 HDFS 中间的一套存储系统,目前在国内主要是小米公司应用的较多,在测试中,我们发现其在 OLTP 表现大致与 TiDB 相当,但是一些中等数据量下,其分析性能相比 TiDB 有一定差距。另外我们的查询目前主要以 Presto 为主,Presto 对接 Kudu 和 PostgreSQL 都是需要考虑兼容性的问题,而 TiDB 兼容 MySQL 协议,在应用初期可以直接使用 Presto-MySQL 进行统一查询,下一步再考虑专门开发 Presto-TiDB。另外,我们希望未来的实时系统和离线系统能够通用,一套代码在两个系统中都能够完全兼容,目前 Tispark 和 SparkSQL 已经很大程度上实现了这点,这支持我们在以后离线上的小时级任务可以直接切换到 TiDB上,在 TiDB 上实现实时业务的同时,如果有 T+1 的需求也能够直接指 HDFS 即可,不用二次开发,这是 Kudu 和 GP 暂时实现不了的。最后,TiSpark 是建立在 Spark 引擎之上,Spark 在机器学习领域里有诸如 Mllib 等诸多成熟的项目,对比 GP 和 Kudu,算法工程师们使用 TiSpark 去操作 TiDB 的门槛非常低,同时也会大大提升算法工程师们的效率。经过综合的考虑,我们最终决定使用 TiDB 作为新的实时系统。同时,目前 TiDB 的社区活跃度非常好,这也是我们考虑的一个很重要的方面。TiDB 简介 在这里介绍一下 TiDB 的相关特性:TiDB 是基于 Google Spanner/F1 论文启发开源的一套 NewSQL 数据库,它具备如下 NewSQL 核心特性: SQL支持 (TiDB 是 MySQL 兼容的) 水平线性弹性扩展 分布式事务 数据强一致性保证 故障自恢复的高可用 同时,TiDB 还有一套丰富的生态工具,例如:快速部署的 TiDB-Ansible、无缝迁移 MySQL 的 Syncer、异构数据迁移工具 Wormhole、以及 TiDB-Binlog、Backup & Recovery 等。SQL Server 迁移到 TiDB 由于我们公司的架构是 .NET + SQL Server 架构,所以我们无法像大多数公司一样去使用 MySQL Binlog 去做数据同步,当然也就无法使用 TiDB 官方提供的 Syncer 工具了。因此我们采用了 Flume + Kafka 的架构,我们自己开发了基于 Flume 的 SQL Server Source 去实时监控 SQL Server 数据变化,进行捕捉并写入 Kafka 中,同时,我们使用 Spark Streaming 去读取 Kafka 中的数据并写入 TiDB,同时我们将之前 SQL Server 的存储过程改造成定时调度的 MySQL 脚本。TiDB 前期测试 在测试初期,我们采用 TiDB 的版本为 RC4,在测试过程中曾经在同时对一张表进行读写时,出现 Region is stale 的错误,在 GitHub 上提出 Issue 后,TiDB 官方很快在 Pre-GA 版本中进行了修复。在测试环境,我们是手动通过二进制包的形式来部署 TiDB ,虽然比较简单,但是当 TiDB 发布 GA 版本之后,版本升级却是一个比较大的问题,由于早期没有使用 TiDB-ansible 安装,官方制作的升级脚本无法使用,而手动进行滚动升级等操作非常麻烦。由于当时是测试环境,在听取了 TiDB 官方的建议之后,我们重新利用 TiDB 官方提供的 TiDB-ansible 部署了 TiDB 的 GA 版本。只需要下载官方提供的包,修改相应的配置,就能完成安装和部署。官方也提供了升级脚本,能够在相邻的 TiDB 版本之前完成无缝滚动升级。同时 TiDB-ansible 默认会提供 Prometheus + Grafana 的监控安装,官方提供了非常丰富完善的 Grafana 模板,省去了运维很多监控配置的工作量,借着 TiDB 部署监控的契机,我们也完成了诸如 Redis,RabbitMQ,Elasticsearch 等很多应用程序的监控由 Zabbix 往 Prometheus 的迁移。这里需要注意的是,如果是用官方提供的部署工具部署 Prometheus 和 Grafana,在执行官方的停止脚本时切记跳过相应的组件,以免干扰其他程序的监控。TiDB 上线过程 在 10 月中旬,随着新机器的采购到位,我们正式将 TiDB 部署到生产环境进行测试,整个架构为 3 台机器,3TiKV+3PD+2TiDB 的架构。在生产环境中的大数据量场景下,遇到了一些新的问题。首先遇到的问题是 OLTP 方面,Spark Streaming 程序设置的 5 秒一个窗口,当 5 秒之内不能处理完当前批次的数据,就会产生延迟,同时 Streaming 在这个批次结束后会马上启动下一个批次,但是随着时间的积累,延迟的数据就会越来越多,最后甚至延迟了 8 小时之久;另一方面,由于我们使用的是机械硬盘,因此写入的效率十分不稳定,这也是造成写入延迟的一个很主要的因素。出现问题之后我们立即与 TiDB 官方取得联系,确认 TiDB 整体架构主要基于 SSD 存储性能之上进行设计的。我们将 3 台机器的硬盘都换成了 SSD;与此同时,我们的工程师也开发了相应的同步程序来替代 Spark Streaming,随着硬件的更新以及程序的替换,写入方面逐渐稳定,程序运行的方式也和 Streaming 程序类似,多程序同时指定一个 Kafka 的 Group ID,同时连接不同机器的 TiDB 以达到写入效率最大化,同时也实现了 HA,保证了即使一个进程挂掉也不影响整体数据的写入。在 OLTP 优化结束之后,随之而来的是分析方面的需求。由于我们对 TiDB 的定位是实时数据仓库,这样就会像 Hadoop 一样存在很多 ETL 的流程,在 Hadoop 的流程中,以 T+1 为主的任务占据了绝大多数,而这些任务普遍在凌晨启动执行,因此只能用于对时间延迟比较大的场景,对实时性要求比较高的场景则不适合,而 TiDB 则能很好的满足实时或者准实时的需求,在我们的业务场景下,很多任务以 5-10 分钟为执行周期,因此,必须确保任务的执行时长在间隔周期内完成。我们取了两个在 SQL Server 上跑的比较慢的重要脚本做了迁移,相比于 SQL Server/MySQL 迁移至 Hadoop,从 SQL Server 迁移至 TiDB 的改动非常小,SQL Server 的 Merge 操作在 TiDB 里也通过 replace into 能够完成,其余一些 SQL Server 的特性,也能够通过 TiDB 的多行事务得以实现,在这一方面,TiDB 的 GA 版本已经做的非常完善,高度兼容 MySQL,因此迁移的成本非常小,从而使我们能够将大部分精力放在了调优方面。在脚本迁移完毕之后,一些简单的脚本能够在秒级完成达到了我们的预期。但是一些复杂的脚本的表现在初期并没表现出优势,一些脚本与 SQL Server 持平甚至更慢,其中最大的脚本 SQL 代码量一共 1000 多行,涉及将近 20 张中间表。在之前的 SQL Server 上,随着数据量慢慢增大,每天的执行时长逐渐由 1-2 分钟增长到 5-6 分钟甚至更久,在双11当天凌晨,随着单量的涌入和其他任务的干扰延迟到 20 分钟甚至以上。在迁移至 TiDB 初期,在半天的数据量下 TiDB 的执行时长大致为 15 分钟左右,与 SQL Server 大致相同,但是并不能满足我们的预期。我们参考了 TiDB 的相关文档对查询参数做了一些调优,几个重要参数为:tidb_distsql_scan_concurrency,tidb_index_serial_scan_concurrency,tidb_index_join_batch_size(TiDB 提供了很好的并行计算能力)。经过验证,调整参数后,一些 SQL 能够缩短一倍的执行时间,但这里依旧不能完全满足我们的需求。引入 TiSpark 随后,我们把目光转向了 TiDB 的一个子项目 TiSpark,用官网的介绍来讲 TiSpark 就是借助 Spark 平台,同时融合 TiKV 分布式集群的优势,和 TiDB 一起解决 HTAP 的需求。TiDB-ansible 中也带有 TiSpark 的配置,由于我们已经拥有了 Spark 集群,所以直接在现有的 Spark 集群中集成了 TiSpark。虽然该项目开发不久,但是经过测试,收益非常明显。TiSpark 的配置非常简单,只需要把 TiSprak 相关的 jar 包放入 Spark 集群中的 jars 文件夹中就能引入 TiSpark,同时官方也提供了 3 个脚本,其中两个是启动和停止 TiSpark 的 Thrift Server,另一个是提供的 TiSpark 的 cli 客户端,这样我们就能像使用 Hive 一样使用 TiSpark 去做查询。在初步使用之后,我们发现一些诸如 select count(*) from table 等 SQL 相比于 TiDB 有非常明显的提升,一些简单的 OLAP 的查询基本上都能够在 5 秒之内返回结果。经过初步测试,大致在 OLAP 的结论如下:一些简单的查询 SQL,在数据量百万级左右,TiDB 的执行效率可能会比 TiSpark 更好,在数据量增多之后 TiSpark 的执行效率会超过 TiDB,当然这也看 TiKV 的配置、表结构等。在 TiSpark 的使用过程中,我们发现 TiSpark 的查询结果在百万级时,执行时间都非常稳定,而 TiDB 的查询时间则会随着数据量的增长而增长(经过与 TiDB 官方沟通,这个情况主要是因为没有比较好的索引进行数据筛选)。针对我们的订单表做测试,在数据量为近百万级时,TiDB 的执行时间为 2 秒左右,TiSpark 的执行时间为 7 秒;当数据量增长为近千万级时,TiDB 的执行时间大致为 12 秒(不考虑缓存),TiSpark 依旧为 7 秒,非常稳定。因此,我们决定将一些复杂的 ETL 脚本用 TiSpark 来实现,对上述的复杂脚本进行分析后,我们发现,大多数脚本中间表很多,在 SQL Server 中是通过 SQL Server 内存表实现,而迁移至 TiDB,每张中间表都要删除和插入落地,这些开销大大增加了执行时长(据官方答复 TiDB 很快也会支持 View、内存表)。在有了 TiSpark 之后,我们便利用 TiSpark 将中间表缓存为 Spark 的内存表,只需要将最后的数据落地回 TiDB,再执行 Merge 操作即可,这样省掉了很多中间数据的落地,大大节省了很多脚本执行的时间。在查询速度解决之后,我们发现脚本中会有很多针对中间表 update 和 delete 的语句。目前 TiSpark 暂时不支持 update 和 delete 的操作(和 TiSpark 作者沟通,后续会考虑支持这两个操作),我们便尝试了两种方案,一部分执行类似于 Hive,采用 insert into 一张新表的方式来解决;另外一部分,我们引入了 Spark 中的 Snappydata 作为一部分内存表存储,在 Snappydata 中进行 update 和 delete,以达到想要的目的。因为都是 Spark 的项目,因此在融合两个项目的时候还是比较轻松的。最后,关于实时的调度工具,目前我们是和离线调度一起进行调度,这也带来了一些问题,每次脚本都会初始化一些 Spark 参数等,这也相当耗时。在未来,我们打算采用 Spark Streaming 作为调度工具,每次执行完成之后记录时间戳,Spark Streaming 只需监控时间戳变化即可,能够避免多次初始化的耗时,通过 Spark 监控,我们也能够清楚的看到任务的延迟和一些状态,这一部分将在未来进行测试。TiDB 官方支持 在迁移过程中,我们得到了 TiDB 官方很好的支持,其中也包括 TiSpark 相关的技术负责人,一些 TiSpark 的 Corner Case 及使用问题,我们都会在群里抛出,TiDB 的官方人员会非常及时的帮助我们解决问题,在官方支持下,我们迁移至 TiSpark 的过程很顺利,没有受到什么太大的技术阻碍。实时数仓 TiDB / TiSpark 在迁移完成之后,其中一条复杂的 SQL,一共 Join 了 12 张表(最大表数量亿级,部分表百万级),在平时小批量的情况下,执行时间会在 5 分钟左右,我们也拿了双 11 全量的数据进行了测试,执行时间在 9 分钟以上,而采用了 TiSpark 的方式去执行,双 11 全量的数据也仅仅花了 1 分钟,性能提升了 9 倍。整个大脚本在 SQL Server 上运行双 11 的全量数据以前至少要消耗 30 分钟,利用 TiDB 去执行大致需要 20 分钟左右,利用 TiSpark 只需要 8 分钟左右,相对 SQL Server 性能提升 4 倍,也就是说,每年数据量最高峰的处理能力达到了分钟级,很好的满足了我们的需求。最后,不管是用 TiDB 还是用 TiSpark 都会有一部分中间表以及与原表进行 Merge 的操作,这里由于 TiDB 对事务进行的限制,我们也采用以万条为单批次进行批量的插入和 Merge,既避免了超过事务的报错又符合 TiDB 的设计理念,能够达到最佳实践。有了 TiSpark 这个项目,TiDB 与 Hadoop 的生态体系得到进一步的融合,在没有 TiSpark 之前,我们的系统设计如下:可以发现,实时数仓与 T+1 异步数仓是两个相对独立的系统,并没有任何交集,我们需要进行数据实时的同步,同时也会在夜晚做一次异步同步,不管是 Datax 还是 Sqoop 读取关系型数据库的效率都远远达不到 TiSpark 的速度,而在有了 TiSpark 之后,我们可以对 T+1 异步数仓进行整合,于是我们的架构进化为如下:这样就能够利用 TiSpark 将 TiDB 和 Hadoop 很好的串联起来,互为补充,TiDB 的功能也由单纯的实时数仓变成能够提供如下几个功能混合数据库: 实时数仓,上游 OLTP 的数据通过 TiDB 实时写入,下游 OLAP 的业务通过 TiDB / TiSpark 实时分析。 T+1 的抽取能够从 TiDB 中利用 TiSpark 进行抽取。 TiSpark 速度远远超过 Datax 和 Sqoop 读取关系型数据库的速度; 抽取工具也不用维护多个系统库,只需要维护一个 TiDB 即可,大大方便了业务的统一使用,还节省了多次维护成本。 TiDB 天然分布式的设计也保证了系统的稳定、高可用。 TiDB 分布式特性可以很好的平衡热点数据,可以用它作为业务库热点数据的一个备份库,或者直接迁入 TiDB 。 上面这三点也是我们今后去努力的方向,由此可见,TiSpark 不仅对于 ETL 脚本起到了很重要的作用,在我们今后的架构中也起到了举足轻重的作用,为我们创建一个实时的统一的混合数据库提供了可能。与此同时,我们也得到 TiDB 官方人员的确认,TiDB 将于近期支持视图、分区表,并会持续增强 SQL 优化器,同时也会提供一款名为 TiDB Wormhole 的异构平台数据实时迁移工具来便捷的支持用户的多元化迁移需求。我们也计划将更多的产品线逐步迁入 TiDB。总结 同时解决 OLAP 和 OLTP 是一件相当困难的事情,TiDB 和 TiSpark 虽然推出不久,但是已经满足很多应用场景,同时在易用性和技术支持上也非常值得称赞,相信 TiDB 一定能够在越来越多的企业中得到广泛应用。 作者简介:罗瑞星,曾就职于前程无忧,参加过 Elasticsearch 官方文档中文翻译工作,现就职于易果集团,担任资深大数据工程师,负责易果集团数据分析架构设计等工作。 "}, {"url": "https://pingcap.com/cases-cn/user-case-lianghuapai/", "title": "TiDB 在量化派风控系统中的应用", "content": " 作者:朱劲松,量化派研发中心系统架构师,主要参与了基础组件开发、API Gateway 等项目,现在致力于公司风控系统相关业务的架构设计和研发。 一、公司简介 量化派(QuantGroup)创办于 2014 年,是数据驱动的科技公司,是国家高新技术企业。量化派以「MOVE THE WORLD WITH DATA, ENLIGHTEN LIFE WITH AI」(数据驱动世界,智能点亮生活)为愿景,利用人工智能、机器学习、大数据技术。为金融、电商、旅游、出行、汽车供应链等多个领域的合作伙伴提供定制化的策略和模型,帮助提升行业效率。量化派已与国内外超过 300 家机构和公司达成深度合作,致力于打造更加有活力的共赢生态,推动经济的可持续发展。我司从 2017 年年中开始调研 TiDB,并在用户行为数据分析系统中搭建 TiDB 集群进行数据存储,经过一年多的应用和研究,积累了丰富的经验。同时,TiDB 官方推出 2.0 GA 版本,TiDB 愈发成熟,稳定性和查询效率等方面都有很大提升。我们于 2018 年 7 月部署 TiDB 2.0.5 版本,尝试将其应用于风控业务中。风控系统主要是在用户申请放款时,根据风控规则结合模型和用户特征进行实时计算并返回放款结果。二、业务背景 风控系统中用到的数据主要可以分为两部分: 一类是原始数据,用于分析用户当前的特征指标。 一类是快照数据,用于计算历史指定时间点的特征指标,供模型训练使用。 原始数据主要分为三种: 产生自公司内各个产品线的业务系统数据。 爬虫组提供的用户联系人、运营商、消费记录等数据。 经过处理后的用户特征数据。 由于我们的风控策略中用到了大量的模型,包括神经网络模型,评分模型等,这些模型的训练需要依靠大量的历史订单以及相关的用户特征,为了训练出更多精准、优秀的模型,就需要更多维度的特征,此时特征的准确性就直接影响了模型的训练结果,为此我们在回溯每一个订单的用户在指定时间的特征表现时,就需要用到数据快照。我们可以通过拉链表的方式来实现数据快照功能,简单说就是在每张表中增加三个字段,分别是new_id、start_time、end_time,每一次记录的更新都会产生一条新的数据,同时变更原有记录的end_time,以记录数据的变更历史。通过上面的介绍可以看到,业务数据和爬虫数据本身数据量就很大,再加上需要产生对应的拉链数据,数据量更是成倍增长。假设每条数据自创建后仅变更一次,那拉链表的数据量就已经是原始表的两倍了,而实际生产环境下数据的变更远不止一次。通过上述的介绍,我们总结风控系统下的数据存储需求应满足以下几点: 业务数据。 业务数据拉链表。 爬虫数据,如联系人信息、运营商数据,消费记录等。 爬虫数据拉链表。 其他数据,如预处理数据等。 三、当前方案 以前方案主要是采用 HBase 进行数据存储。它的水平扩展很好的解决了数据量大的问题。但是在实际使用中,也存在着比较明显的问题,最明显的就是查询的 API 功能性较弱,只能通过 Key 来获取单条数据,或是通过 Scan API 来批量读取,这无疑在特征回溯时增加了额外的开发成本,无法实现代码复用。在实时计算场景中,为了降低开发成本,对于业务数据的获取则是通过访问线上系统的 MySQL 从库来进行查询;爬虫数据由于统一存放在 HBase 中,计算时需要将用到的数据全量拉取在内存中再进行计算。在回溯场景中,针对业务特征回溯,通过查询订单时间之前的数据进行特征计算,这种方式对于已经变更的数据是无能为力的,只能通过 HBase 里的数据快照来实现,但无形增加了很多的开发工作。3.1 TiDB 为我们打开一片新视野 通过上面的介绍,我们知道要构建一个风控系统的实时数仓环境,需要满足下面几个特性: 高可用,提供健壮、稳定的服务。 支持水平弹性扩展,满足日益增长的数据需求。 性能好,支持高并发。 响应快。 支持标准 SQL,最好是 MySQL 语法和 MySQL 协议,避免回溯时的额外开发。 可以发现,TiDB 完美契合我们的每个需求。经过 TiDB 在用户行为数据分析系统中的长期使用,我们已经积累了一定的经验,在此过程中 TiDB 官方也给予了长期的技术支持,遇到的问题在沟通时也能够及时的反馈,而且还与我司技术人员进行过多次技术交流及线下分享,在此我们深表感谢。伴随着风控系统需求的持续增长,我们对整体架构进行了新一轮的优化,新的数据接入及存储架构如图 1。图 1 优化后的架构图通过图 1 可以看到,线上业务系统产生的数据统一存放在 MySQL 中,将这些孤立的数据归集在 TiDB 中,能够提供基于 SQL 的查询服务。通过 binlog 的方式直接从 MySQL 实例进行接入,接入后的数据以两种不同的形式分别存放: 一种是去分库分表后的源数据,降低了实时特征计算的实现及维护成本。 另一种是以拉链数据形式存储实现数据快照功能。 经过调研,针对第一种场景,可以通过阿里的 otter 或者 TiDB 周边工具 Syncer 来快速实现,但对于第二个需求都没有现成的成熟解决方案。最终,我们基于阿里的 canal 进行客户端的定制化开发,分别按照不同的需求拼装合并 SQL 并写入到不同的 TiDB 集群中;同时还可以按需将部分表的数据进行组装并发送至 Kafka,用于准实时分析场景。对于来自爬虫组的数据,我们采用直接消费 Kafka 的方式组装 SQL 写入到 TiDB 即可。在实际是使用中,通过索引等优化,TiDB 完全可以支持线上实时查询的业务需求;在特征回溯时只需要通过增加查询条件就可以获得指定时间的特征结果,大大降低了开发成本。3.2 遇到的问题 风控业务中用户特征提取的 SQL 相对都比较复杂,在实际使用中,存在部分 SQL 执行时间比在 MySQL 中耗时高。通过 explain 我们发现,他并没有使用我们创建的索引,而是进行了全表扫描,在进一步分析后还发现 explain 的结果是不确定的。经过与 TiDB 官方技术人员的沟通,我们进行了删除类似索引、analyze table 等操作,发现问题仍然存在。通过图 2 可以看到完全相同的 SQL 语句,其执行结果的差异性。最后按官方建议,我们采用添加 use index 的方式使其强制走索引,执行时间由 4 分钟变成了 < 1s,暂时解决了业务上的需求。图 2 explain 示意图同时 TiDB 技术人员也收集相关信息反馈给了研发人员。在整个问题的处理过程中,TiDB 的技术人员给予了高度的配合和及时的反馈,同时也表现出了很强的专业性,大大减少了问题排查的时间,我们非常感谢。四、展望 目前我们已经搭建两个 TiDB 集群,几十个物理节点,百亿级特征数据,受益于 TiDB 的高可用构架,上线以来一直稳定运行。如上,TiDB 在我们风控业务中的应用才只是开始,部分业务的迁移还有待进一步验证,但是 TiDB 给我们带来的好处不言而喻,为我们在数据存储和数据分析上打开了一片新视野。后续我们会继续加大对 TiDB 的投入,使其更好地服务于在线分析和离线分析等各个场景。我们也希望进一步增加与 PingCAP 团队的交流与合作,进行更深入的应用和研究,为 TiDB 的发展贡献一份力量。"}, {"url": "https://pingcap.com/cases-cn/user-case-tongcheng/", "title": "支撑百亿级应用的 NewSQL——TiDB 在同程旅游的应用", "content": " 项目背景 初次接触 TiDB,是通过同程网首席架构师王晓波先生的分享,当时同程网正在使开发和数据库全面往开源方向转型,由于业务需要,很多在线业务数据量和访问量都非常的大,而 MySQL 无法满足大数据量下的复杂查询需求,为了使数据库分片对开发透明,同程自研了 DBrouter。但分片后的合并、实时汇总统计及全量数据的监控仍然是困扰我们的一个难点。一直没有特别好的办法解决。急速增长的业务 2016 年国庆前,同程的票务项目(微信九宫格中的火车票、机票等票务业务背后是同程在提供)由于流量激增,订单库压力越来越大,同时相关业务需求也在增加,开发不断的在订单库上新增各种查询,例如为了及时定位异常而增加的限定各类条件的分钟级订单量监控(每分钟执行根据不同的条件进行汇总的订单量)。这样的功能越来越多,同时订单库总大小数 T 左右。对此,公司内部决定将票务订单库进行分片来降低单库压力,应对即将到来的国庆高峰订单爆发。引入 TiDB 经过评估,发现公司自研的分片可以满足绝大多数的查询需求,但是部分复杂条件的查询将会影响整个分片集群的性能,少量的全片扫描 SQL 经常会占用 80% 以上的 IO 资源,导致其他的查询性能下降。这时,刚好我们的首席架构师提议,使用 TiDB 试试,经过中间件组和 DBA 组的配合测试,我们尝试将 TiDB 作为所有数据的集合库提供复杂查询,分片集群则提供简单查询,同时由于 TiDB 高度兼容 MySQL 的连接协议,我们基于 PingCAP 提供的数据同步工具 Syncer 进行了二次开发,可以自定义库名和表名(后来同 TiDB 工程师交流,他们最新的 Wormhole & Syncer 也都已经支持了自定义选项),同时新增了同步状态监控,如 TPS、延迟等,如果出现异常,会通过微信告警。从 MySQL 将数据实时同步到 TiDB 来确保数据的一致。确定方案后,我们连夜安排压测同事和开发同事协作,紧急测试,发现这套分片集群 + TiDB 的方案能够满足我们的功能和性能方面的需求,于是迅速调整了该项目的架构,我们将数千个 MySQL 分片汇总到一个 TiDB 集群,保障了 2016 年国庆的高峰平稳渡过。当时的流量达到了我们平时流量的 2 倍,然而并没有出现异常。该实时同步查询系统架构如下所示: 在该项目实施成功后,我们加深了对于 TiDB 的使用。并根据 PingCAP 的建议和协助部署了各类监控。同时,为了更好的关注数据库的情况,第一时间发现异常,我们将 TiDB 的异常报警接入了公司的监控系统和自愈系统。当发生异常的时候,监控系统会第一时间发现,然后自愈系统会依据提前制定的愈合逻辑处理对应异常,在第一时间恢复应用的可用。更大规模的使用 业务上线以后,我们很快又迁移了机票业务实时同步业务到 TiDB。至本文截稿时,在同程内部,目前共有数套 TiDB 集群,部署服务器数量近百台,总数据量数十 TB。其中最大的一个集群 10 多个数据节点,近十 TB 数据,数据量过百亿,支撑了每天过亿的访问,并提供千万级别的数据监控服务,平均 QPS 在 5000,高峰 QPS 过万。同时,由于 TiDB 的易用性(高度兼容 MySQL 协议和标准的 SQL 语法),我们目前已将 TiDB 作为一个很重要的数据库部署方案,在项目启动时就会考虑是否可以在初期就开始使用。在持续一年多的使用中,我们与 PingCAP 工程师一直保持着沟通和交流,互相之间也经常会进行一些技术和使用方面的沟通。目前最新版的 TiDB 我们也积极与 PingCAP 一起进行测试和问题反馈,他们也非常及时的给予我们反馈并很快的 fix 掉一些 BUG。展望 现在公司内部越来越多的开发在联系 DBA 咨询 TiDB 的信息,我们给他们的反馈就是:这是一个高度兼容 MySQL 协议和语法的数据库,非常简单易用,基本上看下相关文档就可以上手。你们在用的时候就可以当它就是一个 MySQL 来使用,只是它能存放的数据量远远超过 MySQL。而对于 DBA 来讲,这就是一个自带高可用和可动态扩容的数据库,对外是个 MySQL,对内是个分布式数据库。业务侧的开发人员基本没有学习成本,DBA 维护起来也和 MySQL 有很多相似点,系统生态非常好。可以预见,随着项目继续以及新项目建设,TiDB 的实例数和机器数又会继续以较快的速度增长,目前线上用的版本还不是最新的版本,正在做升级到 1.05 的准备工作。我们预计 2018 年底,TiDB 的集群数很快就会有 20 套,机器数数百台,这给开发和运维都带来了一定的挑战。如果我们仍然按照目前的方式建设和运维 TiDB 集群,可能就要面临增加相关人力的处境。我们一直在寻找多 TiDB 集群的便捷管理方案,这时一篇文章引起了我们的注意——《Cloud+TiDB 技术解读》。我们迅速和 TiDB 工程师取得联系,了解到 TiDB 最新的 DBaaS 方案基于 K8S 来自动管理和调度多个 TiDB 实例,这和我们目前大量 docker 化业务和数据库的战略方向是一致的。通过 TiDB-Operator 使可以自动化部署和管理 TiDB 及周边工具,自动化部署这些应用以及使后端获得故障转移能力,这样可以大大降低运维成本,同时提供丰富的接口方便后续对其进行扩展。我们计划 2018 年开始和 PingCAP 合作尝试引入 TiDB DBaaS 方案。另外,我们通过同 PingCAP 工程师的深度交流,了解到了 TiDB 的子项目 TiSpark ,后续计划引入 TiSpark 来对数据进行实时分析、实时数仓等工作的尝试,让技术对业务产生更大的价值。 作者:瞿锴,同程网资深 DBA。 "}, {"url": "https://pingcap.com/cases-cn/user-case-telaidian/", "title": "TiDB 在特来电的实践", "content": " 背景介绍 特来电新能源有限公司是创业板第一股特锐德(300001)的全资子公司,主要从事新能源汽车充电网的建设、运营及互联网的增值服务。特来电颠覆了传统充电桩的模式,世界首创了电动汽车群智能充电系统,获得 336 项技术专利,以“无桩充电、无电插头、群管群控、模块结构、主动防护、柔性充电”的特点引领世界新能源汽车充电的发展,系统的鉴定结论为:“产品世界首创、技术水平国际领先。主动柔性充电对电池寿命可以延长 30% 左右,电池充电的安全性可以提升 100 倍以上。”特来电采用互联网思维,依靠国际领先的汽车群智能充电技术和系统,创新电动汽车充电商业模式,建设全国最大的汽车充电网,通过大系统卖电、大平台卖车、大共享租车、大数据修车、大支付金融、大客户电商,打造让客户满意、政府放心的中国最大汽车充电网生态公司,引领充电网、车联网、互联网“三网融合”的新能源互联网。为什么研究 TiDB 特来电大数据平台通过开源与自研相结合的方式,目前已经上线多套集群满足不同的业务需求。目前在大数据存储和计算方面主要使用了 HBase、Elasticsearch、Druid、Spark、Flink。大数据技术可谓是百花齐放、百家争鸣,不同的技术都有针对性的场景。结合实际情况,选择合适的技术不是一件容易的事情。随着接入大数据平台的核心业务的增加,我们在 OLAP 上主要遇到以下痛点问题: 随着基于大数据分析计算的深入应用,使用 SQL 进行分析的需求越来越旺盛,但目前已经上线的大数据集群(HBase、Elasticsearch、Druid、Spark、Flink)对 SQL 的支持度都比较弱。 目前进入大数据集群的数据主要以宽表方式进行,导致在数据归集和后期基础数据放生变化时应用成本较高。 数据仓库业务有些还是基于复杂的 T+1 模式的 ETL 过程,延时较高,不能实时的反映业务变化。 由于每个大数据集群主要针对特定的场景,数据重复存储的情况较多,这就造成了存储成本的增加,同时也会导致数据的不一致性。 目前进入 HDFS / Druid / ES 的数据,在历史数据更新时,成本较高,灵活性降低。 大数据技术发展迅速,我们也一直希望采用新的技术可以解决我们以上问题,我们关注到目前 NewSQL 技术已经有落地产品,并且不少企业在使用,所以决定在我们平台内尝试引入 NewSQL 技术解决我们的痛点问题。我们先了解一下 NewSQL。图 1 数据库发展史如图 1 所示,数据库的发展经历了 RDBMS、NoSQL 以及现在的 NewSQL,每种不同的技术都有对应的产品,每种数据库的技术背后,都有典型的理论支撑。2003 年 Google GFS 开创了分布式文件系统、2006 年的 BigTable 论文催生了 Hadoop 生态,在 2012 年的 Spanner 和 2013 年的 F1 论文发表后,被业界认为指明了未来关系型数据库的发展。随着大数据技术的发展,实际上 SQL 和 NoSQL 的界限逐渐模糊,比如现在 HBase 之上有 Phoenix,HiveSQL,SparkSQL 等,也有一些观点认为 NewSQL = SQL + NoSQL。不同的技术都有各自的最佳适应场景,Spanner 和 F1 被认为是第一个 NewSQL 在生产环境提供服务的分布式系统技术,基于该理念的开源产品主要为 CockroachDB、TiDB。结合社区活跃度以及相关案例、技术支持,我们决定 NewSQL 技术上引入 TiDB。TiDB 介绍 TiDB 是 PingCAP 公司受 Google Spanner / F1 论文启发而设计的开源分布式 HTAP 数据库,结合了传统的 RDBMS 和 NoSQL 的最佳特性。TiDB 兼容 MySQL,支持无限的水平扩展,具备强一致性和高可用性。图 2 TiDB 架构图TiDB 具有以下核心特性: 高度兼容 MySQL —— 无需修改代码即可从 MySQL 轻松迁移至 TiDB 水平弹性扩展 —— 轻松应对高并发、海量数据场景 分布式事务 —— TiDB 100% 支持标准的 ACID 事务 高可用 —— 基于 Raft 的多数派选举协议可以提供金融级的 100% 数据强一致性保证 一站式 HTAP 解决方案 —— 一份存储同时处理 OLTP & OLAP,无需传统繁琐的 ETL 过程 其中涉及到的分布式存储和分布式计算,大家可以参考 TiDB 的官方网站,在这里就不再进行论述。在处理大型复杂的计算时,PingCAP 结合上图说的 TiKV 以及目前大数据生态的 Spark,提供了另外一个开源产品 TiSpark。不得不说这是一个巧妙的设计,充分利用了现在企业已有的 Spark 集群的资源,不需要另外再新建集群。TiSpark 架构以及核心原理简单描述如下:图 3 TiSpark 架构图TiSpark 深度整合了 Spark Catalyst 引擎,可以对计算提供精确的控制,使 Spark 能够高效的读取 TiKV 中的数据,提供索引支持以实现高速的点查。通过多种计算下推减少 Spark SQL 需要处理的数据大小,以加速查询;利用 TiDB 的内建的统计信息选择更优的查询计划。从数据集群的角度看,TiSpark + TiDB 可以让用户无需进行脆弱和难以维护的 ETL,直接在同一个平台进行事务和分析两种工作,简化了系统架构和运维。除此之外,用户借助 TiSpark 项目可以在 TiDB 上使用 Spark 生态圈提供的多种工具进行数据处理。例如使用 TiSpark 进行数据分析和 ETL;使用 TiKV 作为机器学习的数据源;借助调度系统产生定时报表等等。目前的应用情况 由于很多用户已经部署了生产系统,我们没有在测试上再次投入比较大的精力,经过了简单的性能测试以后,搭建了我们的第一个 TiDB 集群,尝试在我们的业务上进行使用。目前主要用于我们的离线计算,以及部分即系查询场景,后续根据使用情况,逐渐调整我们的集群规模以及增加我们的线上应用。1. 目前的集群配置图 4 集群配置清单2. 规划的应用架构图 5 引入 TiDB 以后的应用架构图基于 TiDB 我们规划了完整的数据流处理逻辑,从数据接入到数据展现,由于 TiDB 高度兼容 MySQL,因此在数据源接入和 UI 展现就有很多成熟的工具可以使用,比如 Flume、Grafana、Saiku 等。3. 应用简介a. 充电功率的分时统计每个用户使用特来电的充电桩进行充电时,车辆的 BMS 数据、充电桩数据、环境温度等数据是实时的保存到大数据库中。我们基于采集的用户充电数据,需要按照一定的时间展示全国的充电功率 比如展示过去一天,全国的充电功率变化曲线,每隔 15 分钟或者 30 分钟进行一次汇总。随着我们业务规模的增加,此场景的计算也逐步进行了更新换代。图 6 充电功率的分时统计目前我们单表数据量接近 20 亿,每天的增量接近 800 万左右。使用 TiDB 后,在进行离线计算分析时,我们的业务逻辑转成了直接在我们的离线计算平台通过 SQL 的方式进行定义和维护,极大的提高了维护效率,同时计算速度也得到了大幅提升。b. 充电过程分析上面我们讲了,我们已经有了充电过程中的宝贵的海量数据,如何让数据发挥价值,我们基于充电数据进行充电过程的分析就是其中的一个方式,比如分析不同的车型在不同的环境(环境温度、电池特性)下,充电的最大电压和电流的变化情况,以及我们充电桩的需求功率满足度等。图 7 充电过程分析针对海量的历史数据计算我们使用了 TiSpark 进行计算,直接使用了我们现有的 Spark 集群,在使用 Spark 进行计算时,一开始由于不熟悉 TiSpark,分配的资源比较少,耗时多一些。后来和 TiDB 技术人员交流了解到最佳实践,提升配置和调整部分参数后,性能提升不少。这个场景中我们充分利用了 TiDB 和 TiSpark 进行协同工作,满足了我们的业务需求。总结及问题 1. 最佳应用场景结合我们的线上验证,我们认为使用 TiDB,主要有以下几个优势: SQL 支持度相对于现有的集群支持度较好,灵活性和功能性大大增强。 可以进行表之间的 join 运算,降低了构造宽边的复杂度以及因此带来的维护成本。 历史数据方便修改。 高度兼容 MySQL 生态下对应的成熟软件较多(开发工具、展现、数据接入)。 基于索引的 SQL 性能在离线计算上基本可以满足我们需求,在即席查询上最适合海量数据下进行多维度的精确查询,类似与“万里挑一”的场景。 使用 TiSpark 进行复杂的离线计算,充分利用了现有的集群,数据存储做到了一份,同时也降低了运维成本。 2. 目前的定位结合我们的实际现状,现阶段我们主要用于进行离线计算和部分即席查询的场景,后期随着应用的深入,我们逐步考虑增加更多的应用以及部分 OLTP 场景。 作者介绍:潘博存,特来电大数据技术研发部架构师,具有 10 多年平台软件设计开发经验,现专注于大数据领域快速读写方向。 "}, {"url": "https://pingcap.com/cases-cn/user-case-eleme-1/", "title": "TiKV 在饿了么的大规模应用实践", "content": " 背景介绍 饿了么从 2008 年创建以来,一直都是飞速的发展。目前,饿了么已覆盖了 2000 多个城市,拥有 2.6 亿的用户,130 万的商户,300万的骑手。饿了么在配送时间上追求卓越,目前饿了么的准时达订单平均配送时长已达到 28 分钟以内。从 2015 年开始,饿了么形成了 2 大业务,在线交易平台业务和即时配送平台业务。饿了么的用户量和订单量的快速增长,带来了数据量的快速增长,从而产生对大数据量存储的强烈需求,并且很多数据都是 KeyValue 格式的数据。之前饿了么没有统一的 Key-Value 存储系统,这部分数据被存储在 MySQL、Redis、Mongo、Cassandra 等不同的系统中,将数据存储在这些系统中,带来一些问题,比如数据扩容不方便、内存不可靠、性能不达标、运维不方便等。我们希望用一套统一的 Key-Value 存储系统来存储这些 Key-Value 形式的数据,并且满足以下所有的技术要求: 大数据量,可以存储至少数十 TB 级别的数据。 高性能,在满足高 QPS 的同时,保证比较低的延时。 高可靠,数据被可靠的持久化存储,少量机器的损坏不会导致数据的丢失。 高可用,作为在线服务的底层依赖存储,要有非常完善的高可用性能力,外卖服务不同于电子商务,对实时性要求非常高,对系统的可用性的要求则是更高的。 易运维,可以在不停服的基础上进行数据迁移,和集群扩容。 从 2017 年下半年开始,饿了么开始基于 TiKV 构建饿了么的 Key-Value 存储系统,并且取得了很好的应用效果。饿了么对 Key-Value 系统的使用是在线系统,由离线计算集群生成数据,在线服务消费这些数据。这些在线服务覆盖了饿了么在线交易和即时配送 2 大平台,在线交易平台中的首页搜索、商品品类、商品排序、天降红包等等,即时配送平台中的物流旗手智能调度等,各种在线服务都在使用我们的 Key-Value 系统。 目前,TiKV 的应用会影响饿了么全平台 80% 的流量,包括从用户选餐下单到订单配送整个饿了么流程。TiKV集群上线情况 目前已在饿了么部署了十几套 TiKV 集群,分别位于北京、上海、广州的四个机房,共计 100+ 机器节点,承载了数十 TB 的数据。 配置了完备的监控告警系统,所有集群都已接入,可以在集群出现问题时及时发送告警信息,为集群的正常运行提供了保障。 业务高峰期时,最繁忙的一个集群,写入 QPS 近 5w,读取 QPS 近 10w。 至今已稳定运行大半年,没有发生过线上事故。  在 Key-Value 的这个领域中,有着林林总总的开源系统。我们为什么要选择 TiKV 呢?首先要从 TiDB 的架构说起。TiDB 由 TiKV 存储层和 TiDB SQL 层组成。TiKV 层是 TiDB 系统的底层存储层,TiKV 层本身是一个分布式的 Key-Value 存储系统。而 TiDB 层构建于 TiKV 层基础之上,实现了无状态的 SQL 协议层,负责将用户的 SQL 请求,转化为 TiKV 的 Key-Value 请求,从而整体上实现分布式的 SQL 存储。这种架构借鉴了 Google 的 Spanner 系统,Spanner 是一个分布式的 Key-Value 存储系统,Google 在 Spanner 的基础之上,构建了一个名叫 F1 的系统,实现了 SQL 协议。我们也比较推崇这种架构,并且我们认为在 Key-Value 基础之上,不仅仅可以构建 SQL 协议,也可以构建 Redis 这样的 Key-Value 协议。在这种架构中,上层负责协议转换。TiKV 层则通过数据分片、Raft 协议、MVCC、分布式事务等技术,实现了水平扩展、高可用、强一致性等分布式特性。 我们的 Redis layer 实现如下:我们构建了一个 ekvproxy 的服务。在这个服务中,我们封装了一个 TiKV 的 SDK,对 Redis 的协议进行了解析,并且将 Redis 协议转成对 TiKV 的调用。并且在这个基础之上,实现了压缩和限流等一些扩展功能。由于我们兼容了 Redis 协议,各种语言均可以在不做任何修改的情况下,直接使用官方的 Redis 客户端访问我们的 Key-Value 服务。在最大程度上减轻了使用方的负担。便于 TiKV 的落地推广。另外,PingCAP 的工程师还第一时间帮我们实现了 TiKV 的 raw scan 的功能,从而能更好的与 Redis 协议兼容,在此表示感谢。虽然系统在线上性能表现已经非常不错,但这仍然没有达到 TiKV 的最大处理能力,上线前,我们对 TiKV 进行了详细的性能测试,我们测试环境选在 32 核 CPU,256G 内存,3.5T PCIE SSD 硬盘的机器上, 得到了更好的结果,取其中典型数据如下:使用 TiKV 的这半年的时间来,在饿了么取得了非常良好的应用效果,应用场景不断增多,数据量不断增大,对饿了么业务做了非常好的支撑,这也依赖于 TiKV 技术人员对我们的各种到位的技术支持。未来,TiKV 在饿了么的应用场景会更加丰富。我们也会考虑将我们 Redis Proxy 开源,开放给社区。 作者介绍:陈东明,饿了么北京技术中心架构组负责人,负责饿了么的产品线架构设计以及饿了么基础架构研发工作。曾任百度架构师,负责百度即时通讯产品的架构设计。具有丰富的大规模系统构建和基础架构的研发经验,善于复杂业务需求下的大并发、分布式系统设计和持续优化。 "}, {"url": "https://pingcap.com/cases-cn/user-case-toutiao/", "title": "TiDB 在今日头条的实践", "content": " 本文整理自今日头条数据库中间件/分布式数据库负责人吴镝(知乎 ID:吴镝)在 TiDB DevCon2018 上的分享内容。 TiDB 主要应用在今日头条核心 OLTP 系统 - 对象存储系统中,存储其中一部分元数据,支持头条图片和视频相关业务,比如抖音等。如今(数据截至发文),TiDB 支撑着今日头条 OLTP 系统里 QPS 比较高的场景:集群容量约几十 T,日常 QPS 峰值会达到几十万。为什么我们需要用 TiDB 今日头条内部有一些业务数据量非常大,之前用的 MySQL 的单机盘是大概 2.8T 的 SSD 盘。我们做对象存储。因为头条不但做视频,还做图片,这些视频和图片当中基本上都是用我们自研的 S3 存储系统,这种存储系统需要一个元数据,比如一个图片存下来,它存在 S3 系统的哪个机器、哪个文件、哪个偏移里面的数据,还有比如一个大的视频,S3 会把它切成很多小的视频片段,每一个分片的位置,都会存在元数据里面。用 TiDB 之前,元数据是存在 MySQL 里的一个 2.8TB 的盘,因为增长的特别快,所以导致磁盘不够用,只能用分库分表的方案。我们以前用的的分库分表方案是 MyCAT。但用这个方案的过程中我们有遇到了一些问题,比如丢数据。某一个数据我 commit 了之后,最后发现这个数据丢了。再就是连接的问题,目前头条做分片是大概固定分 100 个片。如果你的业务是需要分库分表,那你这边搞 101 个分片,这样有些业务,他用了一个分片键,用分片键来做查询,那可能中间件只用一个连接就可以找到相关数据。但有些业务,确实有不带分片键的请求。会导致 select 语句过来的时候,下面会建 101 个对后端的连接,也就是说,因为有连接的限制,有一个没有带分片键的这种请求过来之后, MyCAT 可以启 101 个连接到后面的每一个 MySQL 库。那这样的话,有时候我给它 5 万个连接,他一下子就把一百万用掉了。这样会导致它在非分片键的 select 请求,它连接速度消耗非常快,经常在业务这边会抛出说,连接数不够。头条的数据库主要用的是 MySQL 和 MongoDB,相对比较单一,所我们也想多尝试一些其他的数据库。主要使用场景 目前,TiDB 主要在以下两个场景下使用: 首先是 OLTP 的场景,也就是大数据量的场景,我们不仅仅是考虑到延时,而是考虑到数据量单机装不下,需要扩展性; 还有 OLAP 场景,有些用户,他用的是 Hive 或者 Tableau,然后用的过程中发现,因为后面都是接 MySQL,做一些 OLAP 的方式查询就比较慢。后来公司在推广 TiDB,所以就接了一些 OLAP 的业务场景。 头条的自研对象存储系统元数据量非常大,而且增长非常快。以其中最大的一个集群举例:该集群有两种方式,一是分片信息最早是用 MySQL 的。如果想用 TiDB 的话,可能先得把 TiDB 做了 MySQL 的备,用 TiDB 提供的 syncer 来同步数据,有些读请求我们可以从 MySQL 上切到 TiDB 上来。我们用了一段时间,觉得 TiDB 其实挺稳定的。然后,公司会有这种需求,比如说突然接了一个元旦的活动,这个时候上传的图片就比较多,数据增长的就太大了,这种活动中 S3 系统压力比较大。我们 MySQL 的单盘基本上稳定的在 2.0TB 以上(盘总计 2.8TB),对此我们就只能删数据(一些很老的数据),跟业务部门沟通说,这个数据不要了,从 MySQL 的单盘里删掉,通过这种方式来支撑。但即使这么做,单盘还是扛不住现在数据增长的需求。然后当时就想干脆激进点,把一些写进来后立即就读、并且以后都不会读的一些流量切到 TiDB 里。因为 S3 存储分很多 bucket ,做活动的人就去新建一些 bucket, 这些 bucket 的元数据就直接存在 TiDB 里面,就不存 MySQL 了。这两个 case,就是目前在头条的 OLAP 和 OLTP 里数据流量最大、QPS 最大的一个场景。集群部署状态 关于部署,我们把 TiDB 和 PD 部在一起,都是 3 个。TiKV 我们一共是用了几十台的机器。CPU 是 40 个虚拟的 CPU,256G 的内存。目前平均值 QPS 在十几万,用了 3 个 TiDB,3 个 TiDB 总的连接数加起来大概 14K,然后 Latency 的 pct99 小于 60ms。这其实都属于挺高峰时期的数据了,做活动的时候 QPS 会达到几十万。与 MySQL 的延时对比 在使用 TiDB 过程中,我们也比较了一下 TiDB 和 MySQL 的延时:第一条线就是 MySQL 的延时,pct99 的,下面的黑线是 TiDB 的延时。可以看到,在 MySQL 的数据量非常大的情况下,TiDB 是明显 Latency 更优的,虽然说它用的机器会稍微多点。一些使用中的吐槽和经验 使用的过程中我们也碰到了一些槽点,这些槽点 TiDB 现在的版本已经基本都解决了。第一个就是直方图。大家知道基于 CBO 的这种优化器,肯定要用一些统计信息,TiDB 在之前的版本里对直方图的统计信息的更新没有做到很及时,导致我拿了一个 SQL 选执行计划的时候我会选错。比如说我可以选一个索引,但是实际上,因为这个更新信息不实时,所以它可能会做全表扫描。大家以后发现这种你可以用 explain 这个命令看执行计划,如果有这样的问题就可以用 analyze 这个命令,他可以把一张表统计信息给更新,更新之后再一次执行 SQL 语句,你会发现他的执行计划已经变了。第二个就是 raft leader。因为大家都知道,每个 region 是一个 raft ,TiDB 有一个监控指标,给出每个机器上有多少个 raft leader。当我们数据量跑到 10TB+,大概 20TB 的时候,会发现这个 raft leader 频繁掉线。掉线的原因主要是由于做 region 迁移的时候,比如你后边做迁移或者做负载均衡,会把 RocksDB 里面一个 range 的数据发到你要迁移的目标机器上面去。发过去了之后,目标端相当于要把 SST 文件 load 到 RocksDB 里,这个过程中,由于 RocksDB 实现的一个问题,导致把 SST 加到 RocksDB 的里面去的这个过程花费了大概 30 到 40 秒,正常情况下可能就毫秒级或者 1 秒。RocksDB 实现 ingest file 的时候,它打开了一些其实不需要打开的文件。因为 LevelDB、RocksDB 有很多层,把一个 file 给 ingest 进去的时候其实你要和一些 overlap 的数据做合并,因为它的实现问题,导致有一些没有必要去 touch 的 SST 它都会去 touch,会产生大量 IO 。因为我们数据量比较大, SST 就非常多,所以在数据量非常大的情况下就会踩到这个坑。然后,RocksDB ingest 一个文件时间过长,导致 Raft 的心跳就断了。因为 Raft 协议要维持你的 lease,你要发心跳包,这个时候心跳包都给堵在后面,因为前面 ingest file 时间太长了。然后 Raft leader 就掉,掉了以后很多读写请求就会有问题。第三个是大量的短链接。我们的业务使用数据库的时候,经常建了非常多短链接。因为大部分业务都是不大会使用数据库的,它也不知道要设置连接池,idle connection 这种东西。所以经常用完一个连接后就关掉。这种大量的短链接最后打到 TiDB,TiDB 连接建立了之后要去查一个 System 的变量,这些变量在 TiDB 里面是存在某几个 TiKV 实例里面的,那如果有大量短链接,这些短链接一上来,就会去查这些系统变量,刚好这些系统变量就聚在几台机器上面,导致说这几台机器就负载特别大。然后就会报警读请求堆积。TiKV 使用的是线程模型,请求过来之后,丢到队列里面去。然后线程再拿出来处理。现在 PingCAP 也在做优化,把这些 Cache 在 TiDB 这个进程里面。第四点,严格来说这不算是 TiKV 的问题,算是 prometheus 的客户端有问题。我们当时遇到这么一个情况:部署 prometheus 的这个机器宕掉了,重启之后,我们会发现很多 TiKV 的监控信息都没有上报。后来查的时候发现压根 TiKV 这台机器都没有到 prometheus 这台机器的连接。所以我们就觉得 prometheus 这边客户端实现有问题。第五个问题就是 Row id 的打散。这个问题正好是我们这边碰到的一个性能上的问题。因为 TiDB 存储数据是这么存的:我要插入一行数据,他会有两行,第一行是索引,索引是 Key ,然后 value 是 row id;第二行是 row id 是 Key,value 是整行的数据,相当于第二行有点像聚集索引这种东西。但是这个聚集索引的 Key 是 row id。原来的版本实现上是说这个 row id 是个递增了,所以这种就导致不管你插入什么数据,这个 row id 都是递增的,因为 row id 一递增,这些数据都会打到一个 TiKV 的一个 region 上面。因为我的 TiKV 是一个有序的 Map,所以说 row id 如果递增的话,肯定大家插入的时候都是打到一个 TiKV 上面。我们当时业务的压力比较大,导致客户发现他把这个业务的机器实例数给扩容上去之后,会发现这个 insert 的 TPS 大概也就在两万,一行大概就一百多个字节吧,你再怎么加他上不去了,也就是说 insert 的这个 QPS 上不去了。这一点 TiDB 新版本的方案就是,row id 不是单调递增,而是把 row id 打的很散,这种方案性能会比较好,没有热点。最后这个问题,因为 TiDB 这种事务模型,是需要拿一个事务版本,这个事务版本在 TiDB 里面是一个时间戳,并且这个时间戳是由 PD 这个组件来管理的。相当于每一个事务基本上连上来之后,它都要去访问 PD 这个组件拿时间戳。其实做 rpc 的时候拿时间戳延迟不会太长,也就是个位数毫秒级。但因为 TiDB 是 Go 写的,有调度开销。从 PD 拿回来一堆时间戳的 goroutine 把这堆时间戳发放给执行事务的一堆 goroutine 很慢,在链接数和压力都比较大的时候,大概有 30 毫秒左右的延时。可能调 rpc 的时候也就大概需要 1 毫秒,不到 2 毫秒。但由于 Go 的开销,能把这个延时翻几倍。以上这些讲的都是 TiDB 在头条做 OLTP 的场景下,碰到的一些主要的问题,这些问题大部分现在已经修复。头条在 OLAP 上的一些应用 在 OLAP 的场景下内容就比较少了。前面的一些业务喜欢用 tableau 这种客户端后面连接 MySQL,这就太慢了。可以用 syncer 把一些数据从 MySQL 同步到 TiDB。这就可能碰到一个问题:我们公司有一个组件,是会把 Hive 的数据批量的同步到 MySQL 的一个工具,很多做数据分析的同学就会把 Hive 里的数据同步到 TiDB。但是这个工具产生的事务非常大,而 TiDB 本身对事务的大小是有一个限制的。此时,把下面这两个配置项打开之后,TiDB 内部会把这种大的事务切成很多小的事务,就没有这个问题: set @@tidb_batch_insert =ON set @@tidb_batch_delete = ON 有事务大小的限制主要在于 TiKV 的实现用了一致性协议。对于任何一个分布式数据库,如果你要用一致性协议去做这种复制,肯定要避免非常大的事务。所以这个问题不是 TiDB 的问题。基本上,每个想要做分布式数据库的肯定都会碰到这么一个问题。在 OLAP 场景下,大家对数据的事务性要求没那么高,所以把这个配置项打开没什么问题。这就是头条在 OLAP 上的一些应用:比如说 ugc 点击量,app crash 的需求是客户端请求挂掉之后,要打一个 log 在 TiDB 的集群里面。druid 这个 OLAP 这个引擎,他会有 MySQL 的数据做元数据,有些人就把这个元数据存在 TiDB 上了,还有一些问答业务,也是把一些相关的数据放到 TiDB 上。"}, {"url": "https://pingcap.com/cases-cn/user-case-qunar/", "title": "Qunar 高速发展下数据库的创新与发展 - TiDB 篇", "content": " 目前互联网公司数据存储主要依赖于 MySQL 为代表的关系型数据库,但是随着业务量的增长,使用场景更加多样,传统的关系型数据库不能很好的满足业务需求,主要是在两个维度:一是随着数据量爆炸式增长,性能急剧下降,而且很难在单机内存储;二是一些场景下业务对响应速度要求较高,数据库无法及时返回结果,而传统的 memcached 缓存又存在无法持久化数据,存储容量受限于内存等问题。针对这两个问题,去哪儿的 DBA 团队分别调研了 TiDB 和 InnoDB memcached 以满足业务需求,为用户提供更多的选择方案。接下来的文章系列,我们将陆续为大家带来 TiDB 和 InnoDB memcached 在去哪儿的调研和实践,本篇文章先介绍 TiDB。分布式数据库诞生背景 随着互联网的飞速发展,业务量可能在短短的时间内爆发式地增长,对应的数据量可能快速地从几百 GB 涨到几百个 TB,传统的单机数据库提供的服务,在系统的可扩展性、性价比方面已经不再适用。随着业界相关分布式数据库论文的发布,分布式数据库应运而生,可以预见分布式数据库必将成为海量数据处理技术发展的又一个核心。目前业界最流行的分布式数据库有两类,一个是以 Google Spanner 为代表,一个是以 AWS Auraro 为代表。 Spanner 是 shared nothing 的架构,内部维护了自动分片、分布式事务、弹性扩展能力,数据存储还是需要 sharding,plan 计算也需要涉及多台机器,也就涉及了分布式计算和分布式事务。主要产品代表为 TiDB、CockroachDB、OceanBase 等。 Auraro 主要思想是计算和存储分离架构,使用共享存储技术,这样就提高了容灾和总容量的扩展。但是在协议层,只要是不涉及到存储的部分,本质还是单机实例的 MySQL,不涉及分布式存储和分布式计算,这样就和 MySQL 兼容性非常高。主要产品代表为 PolarDB。去哪儿数据存储方案现状 在去哪儿的 DBA 团队,主要有三种数据存储方案,分别是 MySQL、Redis 和 HBase。MySQL 是去哪儿的最主要的数据存储方案,绝大部分核心的数据都存储在 MySQL 中。MySQL 的优点不用多说,缺点是没法做到水平扩展。MySQL 要想能做到水平扩展,唯一的方法就业务层的分库分表或者使用中间件等方案。因此几年前就出现了各大公司重复造轮子,不断涌现出中间层分库分表解决方案,比如百度的 DDBS,淘宝的 TDDL,360 的 Atlas 等。但是,这些中间层方案也有很大局限性,执行计划不是最优,分布式事务,跨节点 join,扩容复杂(这个心酸 DBA 应该相当清楚)等。Redis 主要作为缓存使用,针对读访问延时要求高的业务,使用场景有限。 HBase 因其分布式的特点,可以通过 RS 的增加线性提升系统的吞吐,HDFS 具有水平扩展容量的能力,主要用来进行大数据量的存储,如日志、历史数据、订单快照等。HBase 底层存储是 LSM-Tree 的数据结构,与 B+ Tree 比,LSM-Tree 牺牲了部分读性能,用来大幅提升写性能。 但在实际运维的过程中,HBase 也暴露了一些缺点: 1. HBase 能提供很好地写入性能,但读性能就差很多,一是跟本身 LSM-Tree 数据结构有关。二是 HBase 因为要存储大容量,我们采用的是 SAS 盘,用 SSD 成本代价太大。三是跟 HBase 自身架构有关,多次 RPC、JVM GC 和 HDFS 稳定性因素都会影响读取性能。 2. HBase 属于 NoSQL,不支持 SQL,对于使用惯了关系 SQL 的人来说很不方便,另外在运维定位问题的时候也增加了不少难度。比如在运维 MySQL 过程中,可以很快通过慢查询日志就识别出哪些 SQL 执行效率低,快速定位问题 SQL。而在 HBase 运维中,就很难直接识别出客户端怎样的操作很慢,为此我们还在源码中增加了慢查询 Patch,但终归没有直接识别 SQL 来的方便。 3. HBase 的软件栈是 Java,JVM 的 GC 是个很头疼的问题,在运维过程中多次出现 RegionServer 因为 GC 挂掉的情况,另外很难通过优化来消除访问延时毛刺,给运维造成了很大的困扰。此外,HBase 在编程语言支持访问对 Java 友好,但是其他语言的访问需要通过 Thrift,有些限制。 4. 架构设计上,HBase 本身不存储数据,HBase 通过 RPC 跟底层的 HDFS 进行交互,增加了一次 RPC,多层的架构也多了维护成本。另外 ZooKeeper 的高可用也至关重要,它的不可用也就直接造成了所有 HBase 的不可用。 5. HBase 不支持跨行事务。HBase 是 BigTable 的开源实现,BigTable 出现之后,Google 的内部就不停有团队基于 BigTable 做分布式事务,所以诞生了一个产品叫 MegaStore,虽然延时很大,但禁不住好用,所以用的人也很多,BigTable 的作者也后悔当初没有在 BigTable 中加入跨行事务。没有了跨行事务,也就没法实现二级索引,用户只能根据设计 rowkey 索引来进行查询,去哪儿不少业务开发问过我 HBase 是否支持二级索引,结果也不得不因为这个限制放弃了使用 HBase。业界很多公司也在 HBase 上实现二级索引,比如小米、华为等,比较出名的是 Phoenix。我们当初也调研了 Phoenix 来支持二级索引,但在 HBase 本身层次已经很多,Phoenix 无疑又多了一层,在运维的过程中也感觉坑很多 , 此外何时用 Phoenix 何时用 HBase API 的问题也给我们造成很多困扰,最终放弃了这个方案。综上所述,为了解决现有数据存储方案所遇到的问题,去哪儿 DBA 团队从 2017 年上半年开始调研分布式数据库,在分布式数据库的产品选择上,综合各个方面因素考虑,最终选择了 TiDB,具体原因不在这里细说了,下面开始具体聊聊 TiDB。TiDB 架构设计 如下图,TiDB 架构主要分为三个组件: TiDB Server:负责接收 SQL 请求,处理 SQL 相关逻辑,通过 PD 找到所需数据的 TiKV 地址。TiDB Server 是无状态的,本身不存储数据,只负责计算,可以无限水平扩展。TiDB 节点可以通过负载均衡组件 (如 LVS、HAProxy 或者 F5) 对外提供统一入口,我个人觉得如果要能实现像 Elasticsearch 那样自己的客户端就更好。 PD Server:Placement Driver (简称 PD) 是整个集群的管理模块,其主要工作有三个: 存储集群元信息(某个 Key 存储在哪个 TiKV 节点)。 对 TiKV 集群进行调度和负载均衡(数据迁移、Raft group leader 迁移等)。 分配全局唯一且递增的事务 ID。 TiKV Server:TiKV 负责存储数据,存储数据基本单位是 Region,每个 TiKV 节点负责管理多个 Region。TiKV 使用 Raft 协议做复制,保证数据一致性和容灾。数据在多个 TiKV 之间的负载均衡由 PD 调度,以 Region 为单位调度。 TiDB 最核心的特性是水平扩展和高可用。 水平扩展:TiDB Server 负责处理 SQL 请求,可以通过添加 TiDB Server 节点来扩展计算能力,以提供更高的吞吐。TiKV 负责存储数据,随着数据量的增长,可以部署更多的 TiKV Server 节点来解决数据 Scale 的问题。 高可用:因 TiDB 是无状态的,可以部署多个 TiDB 节点,前端通过负载均衡组件对外提供服务,这样可以保证单点失效不影响服务。而 PD 和 TiKV 都是通过 Raft 协议来保证数据的一致性和可用性。 TiDB 原理与实现 TiDB 架构是 SQL 层和 KV 存储层分离,相当于 innodb 插件存储引擎与 MySQL 的关系。从下图可以看出整个系统是高度分层的,最底层选用了当前比较流行的存储引擎 RocksDB,RockDB 性能很好但是是单机的,为了保证高可用所以写多份(一般为 3 份),上层使用 Raft 协议来保证单机失效后数据不丢失不出错。保证有了比较安全的 KV 存储的基础上再去构建多版本,再去构建分布式事务,这样就构成了存储层 TiKV。有了 TiKV,TiDB 层只需要实现 SQL 层,再加上 MySQL 协议的支持,应用程序就能像访问 MySQL 那样去访问 TiDB 了。这里还有个非常重要的概念叫做 Region。MySQL 分库分表是将大的数据分成一张一张小表然后分散在多个集群的多台机器上,以实现水平扩展。同理,分布式数据库为了实现水平扩展,就需要对大的数据集进行分片,一个分片也就成为了一个 Region。数据分片有两个典型的方案:一是按照 Key 来做 Hash,同样 Hash 值的 Key 在同一个 Region 上,二是 Range,某一段连续的 Key 在同一个 Region 上,两种分片各有优劣,TiKV 选择了 Range partition。TiKV 以 Region 作为最小调度单位,分散在各个节点上,实现负载均衡。另外 TiKV 以 Region 为单位做数据复制,也就是一个 Region 保留多个副本,副本之间通过 Raft 来保持数据的一致。每个 Region 的所有副本组成一个 Raft Group, 整个系统可以看到很多这样的 Raft groups。最后简单说一下调度。 TiKV 节点会定期向 PD 汇报节点的整体信息,每个 Region Raft Group 的 Leader 也会定期向 PD 汇报信息,PD 不断的通过这些心跳包收集信息,获得整个集群的详细数据,从而进行调度,实现负载均衡。硬件选型和部署方案 在硬件的选型上,我们主要根据三个组件对硬件不同要求来考虑,具体选型如下:因 TiDB 和 PD 对磁盘 IO 要求不高,所以只需要普通磁盘即可。TiKV 对磁盘 IO 要求较高。TiKV 硬盘大小建议不超过 500G,以防止硬盘损害时,数据恢复耗时过长。综合内存和硬盘考虑,我们采用了 4 块 600G 的 SAS 盘,每个 TiKV 机器起 4 个 TiKV 实例,给节点配置 labels 并且通过在 PD 上配置 location-labels 来指明哪些 label 是位置标识,保证同一个机器上的 4 个 TiKV 具有相同的位置标识,同一台机器是多个实例也只会保留一个 Replica。有条件的最好使用 SSD,这样可以提供更好的性能。强烈推荐万兆网卡。TiDB 节点和 PD 节点部署在同台服务器上,共 3 台,而 TiKV 节点独立部署在服务器上,最少 3 台,保持 3 副本,根据容量大小进行扩展。 部署工具使用了 TiDB-Ansible,TiDB-Ansible 是 PingCAP 基于 Ansible playbook 功能编写了一个集群部署工具叫 TiDB-Ansible。使用该工具可以快速部署一个完整的 TiDB 集群(包括 PD、TiDB、TiKV 和集群监控模块),一键完成以下各项运维工作: 初始化操作系统,包括创建部署用户、设置 hostname 等 部署组件 滚动升级,滚动升级时支持模块存活检测 数据清理 环境清理 配置监控模块 监控方案 PingCAP 团队给 TiDB 提供了一整套监控的方案,他们使用开源时序数据库 Prometheus 作为监控和性能指标信息存储方案,使用 Grafana 作为可视化组件进行展示。具体如下图,在 client 端程序中定制需要的 Metric。Push GateWay 来接收 Client Push 上来的数据,统一供 Prometheus 主服务器抓取。AlertManager 用来实现报警机制,使用 Grafana 来进行展示。下图是某个集群的 Grafana 展示图。TiDB 使用情况 对于 TiDB 的使用,我们采用大胆实践、逐步推广的思路,一个产品是否经得起考验,需要先用起来,在运维的过程中才能发现问题并不断反馈完善。因此,去哪儿 DBA 经过了充分调研后,8 月下旬开始,我们就先在非核心业务使用,一方面不会因为 TiDB 的问题对现有业务影响过大,另一方面 DBA 自身也积累运维经验,随着产品自身的完善,集群使用量和运维经验的积累,后续我们再逐步推广到更重要的集群中,解决业务上遇到的数据存储的痛点。目前已经上线了两个 TiDB 集群。 机票离线集群,主要是为了替换离线 MySQL 库,用于数据统计。当前系统容量是 1.6T,每天以 10G 的增量进行增长,用 MySQL 存储压力较大,且没法扩展,另外一些 OLAP 查询也会影响线上的业务。  金融支付集群,主要是想满足两方面需求,一是当前存储在 MySQL 中的支付信息表和订单信息表都是按月进行分表,运营或者开发人员想对整表进行查询分析,现有的方案是查多个表查出来然后程序进行进一步统计 。二是有些查询并不需要在线上进行查询,只需要是作为线下统计使用,这样就没有必要对线上表建立索引,只需要离线库建立索引即可,这样可以避免降低写性能。  目前的架构是用 syncer 从线上 MySQL 库做分库分表数据同步到 TiDB 中,然后开发可以在 TiDB 上进行 merge 单表查询、连表 join 或者 OLAP。 作者:蒲聪,去哪儿平台事业部 DBA,拥有近 6 年的 MySQL 和 HBase 数据库运维管理经验,2014 年 6 月加入去哪儿网,工作期间负责支付平台事业部的 MySQL 和 HBase 整体运维工作,从无到有建立去哪儿网 HBase 运维体系,在 MySQL 和 Hbase 数据库上有丰富的架构、调优和故障处理等经验。目前专注于分布式数据库领域的研究和实践工作。 "}, {"url": "https://pingcap.com/cases-cn/user-case-yuanfudao/", "title": "TiDB 在猿辅导数据快速增长及复杂查询场景下的应用实践", "content": "猿辅导是国内拥有最多中小学生用户的在线教育机构,旗下有猿题库、小猿搜题、猿辅导三款在线教育 APP,为用户提供在线题库、拍照搜题、名师在线辅导相关的服务。其中,猿辅导 APP 已经有超过 116 万付费用户,提供小学英语、奥数,和初中高中全学科的直播辅导课程,全国任何地区的中小学生,都可以享受在家上北京名师辅导课的服务。海量的题库、音视频答题资料、用户数据以及日志,对猿辅导后台数据存储和处理能力都提出了严峻的要求。猿辅导的业务决定了其后台系统具有以下特点: 数据体量大,增速快,存储系统需要能够灵活的水平扩展; 有复杂查询,BI 方面的需求,可以根据索引,例如城市、渠道等,进行实时统计; 数据存储要具备高可用、高可运维性,实现自动故障转移。 在最初方案选型时,猿辅导初期考虑用单机 MySQL。但根据业务发展速度预估,数据存储容量和并发压力很快就会达到单机数据库的处理瓶颈。如果在 MySQL 上加入分库中间件方案,则一定要指定 sharding key,这样是无法支持跨 shard 的分布式事务。同时 proxy 的方案对业务层的侵入性较强,开发人员必须了解数据库的分区规则,无法做到透明。除此之外,分库分表很难实现跨 shard 的聚合查询,例如全表的关联查询、子查询、分组聚合等业务场景,查询的复杂度需要转嫁给开发者。即使某些中间件能实现简单的 join 支持,但是仍然没有办法保证查询的正确性。另外广播是一个没有办法 Scale 的方案,当集群规模变大,广播的性能开销是很大的。同时,传统 RDBMS 上 DDL 锁表的问题,对于数据量较大的业务来说,锁定的时间会很长,如果使用 gh-ost 这样第三方工具来实现非阻塞 DDL,额外的空间开销会比较大,而且仍然需要人工的介入确保数据的一致性,最后切换的过程系统可能会有抖动。可以说,运维的复杂性是随着机器数量指数级增长,而扩容复杂度则是直接转嫁给了 DBA。最终,猿辅导的后台开发同学决定寻求一个彻底的分布式存储解决方案。通过对社区方案的调研,猿辅导发现分布式关系型数据库 TiDB 项目。TiDB 是一款定位于在线事务处理/在线分析处理(HTAP)的融合型数据库产品,具备在线弹性水平扩展、分布式强一致性事务、故障自恢复的高可用、跨数据中心多活等核心特性;对业务没有任何侵入性,能优雅的替换传统的数据库中间件、数据库分库分表等 Sharding 方案,并在此过程中保证了事务的 ACID 特性。同时它也让开发运维人员不用关注数据库 Scale 的细节问题,专注于业务开发,极大的提升研发的生产力。用户可以把 TiDB 当作一个容量无限扩展的单机数据库,复杂的分布式事务和数据复制由底层存储引擎来支持,开发者只需要集中精力在业务逻辑的开发上面。图为 TiDB 与传统的 MySQL 中间件方案的一些对比TiDB 集群主要分为三个组件:TiDB Server、TiKV Server、PD Server。TiDB 整体架构图TiDB Server 负责处理 SQL 请求,随着业务的增长,可以简单的添加 TiDB Server 节点,提高整体的处理能力,提供更高的吞吐。TiKV 负责存储数据,随着数据量的增长,可以部署更多的 TiKV Server 节点解决数据 Scale 的问题。PD 会在 TiKV 节点之间以 Region 为单位做调度,将部分数据迁移到新加的节点上。所以企业在业务的早期,可以只部署少量的服务实例,随着业务量的增长,按照需求添加 TiKV 或者 TiDB 实例。在实际上线的部署设置中,猿辅导选择了 2 TiDB + 3 TiKV + 3 PD 的架构,随着业务数据的增加可以弹性扩容,数据条数每天 500w,日常库中数亿条记录,峰值 QPS 1000。猿辅导的用户端会做一些直播过程的音视频质量的数据收集,比如丢包,延迟,质量打分。然后客户端把这些数据发回服务器,服务器把这些数据存到 TiDB 上。在猿辅导研发副总裁郭常圳看来:“TiDB 是一个很有野心的项目,从无到有的解决了 MySQL 过去遇到的扩展性问题,在很多场合下也有 OLAP 的能力,省去了很多数据仓库搭建成本和学习成本。这在业务层是非常受欢迎的。”对于接下来的计划,猿辅导预计在其他分库分表业务中,通过 syncer 同步,进行合并,然后进行统计分析。实际上,类似猿辅导这种场景的并不是第一家,在互联网快速发展下,大量的企业面对着业务激增的情况。TiDB 灵活的水平扩展能力,能够满足企业业务快速发展的需要。"}, {"url": "https://pingcap.com/cases-cn/user-case-erweihuo/", "title": "TiDB 在二维火餐饮管理实时报表中的实践", "content": " 二维火 SaaS 平台介绍 二维火作为餐饮商家管理标准化服务提供商,帮助商家节省经营成本、提升服务效果是我们的使命。在商家日常生产中,上游系统产生了很多数据,包括供应链采购系统(Support),门店收银系统(POS),食客排队系统(Queueing),智能厨房显示系统(KDS),电子菜谱系统等(E-Menu), 一个实时、精准、可多维度分析的报表系统能充分利用这些数据,支持商家对经营决策进行优化,极大提升商家工作效率。主要服务于以下场景: 收银员交接班需要通过收银软件、财务报表进行多维度对账,来保障收银员一天的辛苦劳动。 商家运营人员需要时段性监控每个门店的经营状况,并通过监控数据实时调整运营策略。 中小型店老板解放自我,不再需要时时刻刻呆在门店里,也能从原料变化到收入波动进行实时把控。 大型门店连锁更有专门的指挥中心,实时了解每个门店的经营状况,实现一体化管理。 二维火各类报表界面:二维火实时报表的业务约束 要求实时或者准实时,数据延迟不超过 3 秒。 数据量大、数据增速快,报表结果查询需要在 500 ms 之内返回结果。 查询维度多,查询条件复杂,涉及十几个业务表,上百个维度汇总查询。 随着业务范围扩大以及功能扩展,实时报表业务不光承担了报表业务,业务方同时希望这是一个数据实时、可多维度查询分析的数据平台工具,为业务进行各种数据支持。二维火数据的特殊场景 商家门店连锁关系不是固定的,A 门店数据今天属于 AA 连锁,明天可能会变成 BB 连锁。 数据展现多人多面,权限不同展现结果不同。 数据变更非常频繁,一条数据最少也会经过五六次变更操作。 实时报表展现的不仅是当天数据,涉及到挂帐、垮天营业、不结账等复杂状况,生产数据的生命周期往往会超过一个月以上。 如果用 MySQL 作为报表存储引擎的话,一个门店所属连锁总部变更,相当于分库的路由值产生了变化,意味着需要对这家店的数据进行全量迁移,这是个灾难性的事情,我们希望连锁只是个属性,而不用受到 Sharding Key 的制约导致的一地鸡毛。开始的解决方案 我们的业务数据是构建在 MySQL 之上,按照业务和商家维度进行分库。利用 Otter 订阅业务数据,进行数据整理归并到 Apache Solr[1] 中,输出分析、统计报表所需要的数据。然而随着业务的快速发展以及客户定制化需求不断增加,Solr 的瓶颈从一张白纸慢慢地被填充。 不断的添加检索维度,需要不停的对索引进行 Full Build,Solr 的 Full Build 成本慢慢地高成了一座大山。 为保障数据精准,Solr 的 Full Build 必须隔段时间操作一次。 随着业务蓬勃发展,数据更新频率越来越高、范围时间内更新的数据条数越来越多,面对 Solr GC 这个问题,我们对数据更新做了窗口控制,一条数据的更新延迟到了 10 秒钟。 Solr 的故障恢复时间过长,严重影响业务可用性。 Solr 很好,但是对于要求能灵活定制、数据即时、维度复杂的报表业务来说,他还不够好。 引入 TiDB 在引入 TiDB 之前,我们也评估和使用过 Greenplum,但是发现并发实时写入的性能无法满足我们的业务承载,在机缘巧合之下认识了 TiDB 同学们,经过了一段时间熟悉、测试和研究之后,我们意识到 TiDB 就是我们想要的产品,于是就开始在实际环境中使用 TiDB 来构建实时报表系统。特别要赞美下 TiDB 的软件太棒了,国内开源软件无出其右,天然的高可用,本身减少了很多运维工作,Ansible 多节点、多组件一键部署,业务无感知滚动升级,特别是把监控也嵌合到软件本身里,让我们追踪、定位问题异常清晰明了,大大缩减了排查成本。当然 TiDB 的优点很多: 首先解决了繁琐的分库分表以及无限水平扩展问题,并且能保证事务特性。 其次故障自恢复,计算、存储全无单点。 还有 TiDB 在做 DDL 操作时候,基本不影响业务使用,这个对我们经常调整表结构的业务来说,大大加快了迭代速度,在线 DDL 不再是一件奢侈的事情。 TiDB 通过下推到存储节点进行并行计算等技术,在数据量大、同时不影响写入的情况下,能非常好的满足各种统计查询响应时间要求。 总之,TiDB 很好的解决了我们之前在实时报表碰到了各种痛点,让我们终于不用为业务方的每项决策和用户的需求而绞尽脑汁和痛苦不堪。TiDB 集群总体配置如下:2*TiDB、3*TiKV、3*PDTiDB 使用体验 我们基于 TiDB 的实时报表系统稳定运行了一个多月,目前实时报表承载的日数据更新量在一亿以上,高峰时期 TiDB 写入 QPS 高于 4000,百级读 QPS ,读流量基本上是统计类 SQL, 比较复杂,最多包含十几张表的关联查询。TiDB 不管从性能、容量还是高可用性以及可运维性来说,完全超出了我们的预期。TiDB 让我们的业务开发回到了业务本质,让简单的再简单,开发不需要再拆东墙补西墙忙于数据爆发带来的各种手忙脚乱。整体数据库架构图:在 TiDB 使用中的几点注意事项 一些注意事项,TiDB 的官方文档写的非常详细全面了,这里我再画蛇添足几点个人觉得非常重要的几项: TiDB 对 IO 操作的延迟有一定的要求,所以一定要本地 SSD 盘。我们一开始在一个集群中使用了云 SSD 盘,发现性能抖动非常厉害,特别是扩容缩容会导致业务基本不可用。 删除大数据的时候,用小数据多批量方式操作,我们现在每批次是小于 1000 条进行删除。 在大批量数据导入后,务必先操作 analyze table${table_name}。 TiDB 开发非常活跃,版本迭代非常快,升级的时候先在非生产环境演练下业务,特别是一些复杂 SQL 的场景。 后续计划 在接入一个业务实时报表后,我们对 TiDB 越来越了解,后续我们计划对 TiDB 进行推广使用,具体包括: 把公司所有实时报表以及统计结果都逐渐迁移到 TiDB 中。 对业务进行分类,大表、多表关联的复杂场景准备开始使用 TiSpark,结合现有 TiDB,会大大简化目前整个数据产品、架构,同时大大解放运维。 中期会考虑将 OLTP 的业务迁入到 TiDB。 最终通过 TiDB 构造成一个同时兼容分析型和事务型(HTAP)的统一数据库平台。 作者介绍:火烧(花名),二维火架构运维负责人 "}, {"url": "https://pingcap.com/cases-cn/user-case-keruyun/", "title": "TiDB 助力客如云餐饮 SaaS 服务", "content": " 公司介绍 客如云成立于 2012 年,是全球领先、 国内最大的 SaaS 系统公司。 目前面向餐饮、 零售等服务业商家, 提供软硬一体的新一代智能化前台、收银等 SaaS 云服务,包括预订、排队、外卖、点餐、收银、会员管理、进销存等系统服务,并将数据实时传达云端。我们是客如云的大数据基础架构组,负责公司的大数据架构和建设工作,为公司提供大数据基础数据服务。业务发展遇到的痛点 1. 随着公司业务架构越来越复杂,技术架构组需要在服务器端与应用端尽可能的通过微服务化实现业务解耦,同时需要第三方熔断服务机制来保证核心业务正常运行。数据库层面,为了保证高并发的实时写入、实时查询、实时统计分析,我们针对地做了很多工作,比如对实时要求较高的服务走缓存、对大表进行分库分表操作、对有冷热属性的大表进行归档、库分离,虽然用大量人力资源解决了部分问题,但是同时也带来了历史数据访问、跨库分表操作、多维度查询等问题。2. 大数据量下,MySQL 稍微复杂的查询都会很慢,线上业务也存在单一复杂接口包含执行几十次 SQL 的情况,部分核心交易大库急需解决访问性能。3. 餐饮行业有明显的业务访问高峰时间,高峰期期间数据库会出现高并发访问,而有些业务,比如收银,在高峰期出现任何 RDS 抖动都会严重影响业务和用户体验。4. 传统的数仓业务往往有复杂的 T+1 的 ETL 过程,无法实时的对业务变化进行动态分析和及时决策。业务描述 大数据的 ODS(Operational Data Store)以前选型的是 MongoDB,ODS 与支持 SaaS 服务的 RDS 进行数据同步。初期的设想是线上的复杂 SQL、分析 SQL,非核心业务 SQL 迁移到大数据的 ODS 层。同时 ODS 也作为大数据的数据源,可以进行增量和全量的数据处理需求。但是由于使用的 MongoDB,对业务有一定侵入,需要业务线修改相应查询语句,而这点基本上遭到业务线的同学不同程度的抵制。同时目前大数据使用的是 Hadoop + Hive 存储和访问方案,业务线需要把历史明细查询迁移到 Hadoop ,然后通过 Impala、Spark SQL、Hive SQL 进行查询,而这三个产品在并发度稍微高的情况下,响应时间都会很慢,所以大数据组在提供明细查询上就比较麻烦。 同时更为棘手的是,面对客户查询服务(历史细则、报表等),这类查询的并发会更高,而且客户对响应时间也更为敏感,我们首先将处理后的数据(历史细则等)放在了 MongoDB 上(当时 TiDB 1.0 还没有 GA,不然就使用 TiDB 了),然后针对 OLAP 查询使用了 Kylin ,先解决了明细查询的问题。 但是由于业务很复杂, 数据变更非常频繁,一条数据最少也会经过五六次变更操作。报表展现的不仅是当天数据,涉及到挂账、跨天营业、不结账、预定等复杂状况,生产数据的生命周期往往会超过一个月以上。所以当前的 OLAP 解决方案还有痛点,所以后续我们要把 OLAP 查询移植一部分到 TiDB 上面去,来减轻 Kylin 的压力并且支持更加灵活的查询需求,这个目前还在论证当中。 同时,我们发现 TiDB 有一个子项目 TiSpark, TiSpark 是建立在 Spark 引擎之上,Spark 在机器学习领域里有诸如 MLlib 等诸多成熟的项目,算法工程师们使用 TiSpark 去操作 TiDB 的门槛非常低,同时也会大大提升算法工程师们的效率。我们可以使用 TiSpark 做 ETL,这样我们就能做到批处理和实时数仓,再结合 CarbonData 可以做到非常灵活的业务分析和数据支持,后期根据情况来决定是否可以把一部分 Hive 的数据放在 TiDB 上。新老框架如下图:图:老的框架图:新的框架TiDB 测试应用 1. 配置 阿里云服务器: TiDB / PD:3 台 i1 型 机器,16c 64g ; TiKV :5 台 i2 型机器,16c 128g, 1.8T*2 每台机器部署两个 KV; 监控机一台。 目前我们将线上 RDS 中三个库的数据通过 Binlog 同步到 TiDB ,高峰期 QPS 23k 左右,接入了业务端部分查询服务;未来我们会将更多 RDS 库数据同步过来,并交付给更多业务组使用。因为 TiDB 是新上项目,之前的业务线也没有线上 SQL 迁移的经历,所以在写入性能上也没有历史数据对比。2. 性能对比 (1)查询一个索引后的数字列,返回 10 条记录,测试索引查询的性能。(2)查询两个索引后的数字列,返回 10 条记录(每条记录只返回 10 字节左右的 2 个小字段)的性能,这个测的是返回小数据量以及多一个查询条件对性能的影响。(3)查询一个索引后的数字列,按照另一个索引的日期字段排序(索引建立的时候是倒序,排序也是倒序),并且 Skip 100 条记录后返回 10 条记录的性能,这个测的是 Skip 和 Order 对性能的影响。(4)查询 100 条记录的性能(没有排序,没有条件),这个测的是大数据量的查询结果对性能的影响。(5)TiDB 对比 MySQL 复杂 SQL 执行速率: Table 1 TiDB 数据量 5 千万,MySQL数据量 2.5 千万; Table 2 TiDB 数据量 5 千万,MySQL数据量 2.5 千万; Table 3 TiDB 数据量 5 千万,MySQL数据量 2.5 千万。 a. 对应 SQL:SELECT sum(p.exempt_amount) exempt_amount FROM table1 p JOIN table2 c ONp.relate_id=c.id AND p.is_paid = 1 andp.shop_identy in(BBBBB) andp.brand_identy=AAAAA andp.is_paid=1 AND p.status_flag=1 AND p.payment_type!=8 WHEREc.brand_identy = AAAAA ANDc.shop_identy in(BBBBB) ANDc.trade_type in(1,3,4,2,5) ANDc.recycle_status=1 AND c.trade_statusIN (4,5,10) ANDp.payment_time BETWEEN '2017-08-11 16:56:19' AND '2018-01-13 00:00:22' ANDc.status_flag = 1 ANDc.trade_pay_status in(3,5) AND c.delivery_type in(1,2,3,4,15)  b. 对应 SQL:SELECT sum(c.sale_amount)tradeAmount,sum(c.privilege_amount) privilege_amount,sum(c.trade_amount)totalTradeAmount,sum(c.trade_amount_before) tradeAmountBefore FROM (SELECTc.sale_amount,c.privilege_amount,c.trade_amount,c.trade_amount_before FROM table1p JOIN table2c ON p.relate_id=c.id andp.shop_identy in(BBBBB) andp.brand_identy=AAAAA andp.is_paid=1 AND p.status_flag=1 AND p.payment_type!=8 and c.brand_identy = AAAAA ANDc.shop_identy in(BBBBB) ANDc.trade_type in(1,3,4,2,5) ANDc.recycle_status=1 AND c.trade_statusIN (4,5,10) ANDp.payment_time BETWEEN '2017-07-31 17:38:55' AND '2018-01-13 00:00:26' ANDc.status_flag = 1 ANDc.trade_pay_status in(3,5) ANDc.delivery_type in(1,2,3,4,15) ANDp.payment_type not in(4,5,6,8,9,10,11,12) GROUP BY p.relate_id ) c  c. 对应 SQL:SELECT SUM(if(pay_mode_id=-5 or pay_mode_id = -6,0,IFNULL(pi.face_amount, 0) - IFNULL(pi.useful_amount, 0) -IFNULL(pi.change_amount, 0))) redundant FROM table2c JOIN table1 p ON c.id = p.relate_id AND c.brand_identy=p.brand_identy JOIN table3pi ON pi.payment_id=p.id AND pi.pay_status in (3,5,10) AND pi.brand_identy=p.brand_identy ANDpi.pay_mode_id!=-23 andp.shop_identy in(BBBBB) andp.brand_identy=AAAAA andp.is_paid=1 AND p.status_flag=1 AND p.payment_type!=8 WHEREc.brand_identy = AAAAA ANDc.shop_identy in(BBBBB) ANDc.trade_type in(1,3,4,2,5) ANDc.recycle_status=1 AND c.trade_statusIN (4,5,10) ANDp.payment_time BETWEEN '2017-07-31 17:38:55' AND '2018-01-13 00:00:26' ANDc.status_flag = 1 ANDc.trade_pay_status in(3,5) AND c.delivery_type in(1,2,3,4,15) d. 对应 SQL:SELECT t.id tradeId,sum(t.trade_amount - t.trade_amount_before) AS roundAmount, sum(-p.exempt_amount) AS exemptAmount FROM table2t LEFT JOINtable1 p ON p.relate_id = t.id LEFT JOINtable3 pi ON pi.payment_id = p.id WHEREt.brand_identy =AAAAA AND t.trade_status IN (4,5,10) ANDt.trade_pay_status IN (3,4,5,6,8) ANDp.payment_type IN (1,2) ANDpi.pay_mode_id !=-23 ANDp.is_paid=1 AND t.status_flag=1 AND t.shop_identy IN(<123个商户号码>) GROUP BY t.id e. 对应 SQL:SELECT t.id tradeId, sum(t.trade_amount- t.trade_amount_before) AS roundAmount, sum(-p.exempt_amount)AS exemptAmount FROM table2t JOIN table1 p ON t.id = p.relate_id WHERE t.brand_identy = AAAA ANDt.trade_status IN(4,5,10) ANDt.trade_pay_status IN (3,4,5,6,8) ANDp.is_paid=1 AND t.status_flag=1 group by t.id ; (6)OLTP 对比测试结果:(7)简单测试结论: 不管是索引查询、分页查询、线上业务级的负载查询,大数据量下 TiDB 的性能都比 MySQL 更强; TiDB 整体性能表现满足我们业务的需求。 生产使用情况 目前线上已经存储超过 6 个月的数据,总数据量几 T,支持线上的查询和分析需求,很多一般复杂度 OLAP 查询都能够在秒级返回结果。TiSpark 我们也调试通过,准备移植一些支持 OLAP 的 ETL 应用做到实时 ETL。目前 TiDB 生产还有很多优化的空间,比如系统参数,SQL 的使用姿势,索引的设计等等。未来规划 已经有一个交易量很大业务部门在向我们了解 TiDB,有可能要使用 TiDB 作为线上交易系统; 后续大数据也会使用 TiSpark 来做 OLAP 查询和数据处理,同时也可能会作为 Kylin 的数据源; 可以预见将来不管是 OLTP,还是 OLAP 场景,TiDB 都会在客如云发挥越来越重要的作用。 致谢 感谢 TiDB 的厂商的人员给予了我们巨大的支持,希望我们能够提供给 TiDB 一些有意义的信息和建议,在 TiDB 成长的路上添砖加瓦。 作者:客如云 BigData Infra Team  "}, {"url": "https://pingcap.com/cases-cn/user-case-eleme-2/", "title": "TiDB 在饿了么归档环境的应用", "content": " 背景 随着业务增长,公司数据规模不断膨胀,表变多、变大。一方面占用的磁盘、CPU 等物理资源疾速上涨,另一方面大表性能下降且变更困难。实际上,很多大表的数据无需保留很久,比如某些业务可能只需近 3 周或近 3 个月的数据。对此类表,可依据业务要求,在线上环境只保留指定天数的数据,其余超出时间范围的过期数据可予以删除。出于某些原因,比如对账,线上业务查冷数据等,从生产环境删除的数据不能直接丢弃,需要存档以备不时之需,所谓归档。方案 目前我们公司主要使用的是 MySQL 数据库服务,那么我们使用大磁盘容量的机器搭建几套主从结构的 MySQL 集群,配上高可用机制,将生产环境指定库表、指定时间范围之外且满足其他指定条件的数据按照一定的顺序定期分批导入到这些目标集群,并在每批确认导入成功后对源生产环境的数据予以删除,下批再从上次结束的位点开始导入、删除,如此循环重复,使生产环境表的数据始终维持在指定的时间范围。至于归档目标环境的数据则可以根据公司的要求统一保留指定的时间,比如 1 年。对于归档目标环境过期的数据可以进行直接删除处理。问题 上述是一个典型的归档系统需要完成的基本功能和基本的处理流程,如果数据规模不是很大且增幅稳定而且表结构固定,那么上述流程可以很好的运行的。但现实的情况是公司数据规模庞大、数据增长迅速,而且由于业务发生变化等原因,后端的表结构可能需要跟着变化。而且,还需要考虑归档对生产集群正常业务的影响、对主从延迟的影响和 DDL 的影响等(这部分内容不在本文讨论范围)。对于表结构变更有两种处理方式, “温和型”:在发现源端表结构发生变更后,相应的在目标端的表上执行同样的变更,以确保两端表结构一致数据可以正常写入; “粗暴型”:一旦发现源端表结构发生了变更,则在目标端轮转一个新表(旧表重命名,然后按源表新的表结构在目标端重建表)以确保源和目标表结构统一。 “粗暴型”的解决方式可以很好的处理结构不一致问题,但如前边所述,一些线上的业务可能需要查询归档环境的冷数据,比如,用户想要查询半年前的订单数据,对于这类表简单粗暴的将其重命名会对业务查询归档数据造成困难;“温和型”的解决方式不仅可以处理表结构不一致的问题,而且也可以避免轮转表导致的数据查询问题,但是,对于 MySQL 来说,当归档表变得很大的时候,DDL 通常会非常耗时。对于数据规模大、数据增长快这一情况,尽管选用了大磁盘容量的机型来存储归档数据,但因表多且数据量大往往在运行几个月后磁盘空间即被写满。这部分数据因为还没超出指定的有效期,所以还不能从归档目标环境直接清理,而 MySQL 又不能方便的进行容量扩展,所以只能考虑将现有的归档作业迁移至新的归档目标集群进行归档,而这一迁移也会对需要访问归档环境数据的应用造成影响。另外,尽管启用了高可用机制,因为归档环境数据量大,一旦归档目标集群发生了 Master 节点切换,要想重新同步一份数据搭建一个 Slave 节点会非常耗时。上述问题可简要概括为三个主要痛点: 快速 Online DDL; 水平扩展存储容量; 故障恢复后的数据自动同步。 探索 弹性伸缩和快速 Online DDL 不是我们在归档环境遇到的个案问题,其实也是数据库业界普遍会遇到的两个问题,尤其是现如今各类海量数据的大背景下,也因此出现过诸多解决方案。比如,TokuDB 存储引擎就可以快速安全的处理 DDL,而且是作为 MySQL 插件的方式提供的,所以对于基于 MySQL 的应用几乎可以不用进行任何改造就可以在 TokuDB 引擎上运行。而且 TokuDB 引擎有很高的压缩比,这一点对很多资源敏感型的用户也很具吸引力。美中不足的是,TokuDB 只是插件式的存储引擎,并不能解决弹性扩容问题。 MySQL Cluster、PXC 等具备弹性扩容能力,但它们只是扩展了计算能力,并不能扩展存储能力,且大表的 DDL 依然是个问题。Cassandra,Vertica 这类分布式列式存储可以对计算和存储方便的进行弹性伸缩,DDL 也可以快速安全的进行,但这类数据库是非关系型的,不支持分布式事务(对于归档应用不是什么问题),且对于基于 MySQL 的应用需要进行大量兼容性的改造才可能迁移至这些存储(对于 MySQL 的归档意味着我们要进行额外的大量的改造工作)。基于 Google Spanner 和 F1 之类的数据库可以横向扩展、可以快速 Online DDL,且是关系型的,支持分布式事务,但却不支持 MySQL 协议,这对于新的应用不是大的问题,但对于基于 MySQL 的应用的迁移,对于我们目前的 MySQL 归档却是个问题。Hadoop 生态系统的 HBase 存在其他列式存储同样的优缺点,且对于我们归档应用显得有点重。简单讲,我们的选型原则是:能在实现目标的前提下,越简单越好。TiDB 分布式数据库集群在这一背景下进入我们的视野,它几乎支持前述提到的各个特性同时高度兼容 MySQL,这对于我们的业务是非常友好的。TiDB 整个 2017 年,TiDB 在数据库行业发展的如火如荼,我们也对此予以了极大的关注。恰逢我们的归档环境存在前述问题,且生产环境也面临诸多大表扩容和高读写表的改造问题亟待解决,因此在归档环境率先尝试使用 TiDB 以解决当前面临的问题,并对其进行验证以便将来应用于生产环境变得势在必行。1. TiDB 整体架构 TiDB 集群有三大组件构成:TiDB Server、PD Server、TiKV Server(图 1)。图 1 TiDB 架构其中各个组件的功能如下: TiDB Server,可以理解为 SQL Layer,负责接收 SQL 请求,处理 SQL 解析、SQL 优化等相关逻辑,并通过 PD 与底层 TiKV 交互来获取或变更数据; PD Server,可以视作集群的大脑,负责集群各类元信息的存储以及 TiKV 节点间的数据调度和负载均衡,另外还负责集群全局事务 ID 的分配; TiKV Server,集群的存储层,数据最终以 Key-Value 的形式存储于其中,并通过 PD 在各个 KV 节点调度,以保证各节点负载均衡。TiKV Cluster 本身也可作为分布式的 Key-Value 存储独立使用。 2. TiDB 核心特性 水平扩展计算与存储 TiDB Server 负责处理 SQL 请求,随着业务的增长,可以简单的添加 TiDB Server 节点,提高整体的计算处理能力。TiKV 负责存储数据,随着数据量的增长,可以部署更多的 TiKV Server 节点,提高集群整体的存储能力。PD 会在 TiKV 节点之间做调度,将部分数据迁移到新加的节点上,这个过程不需要人为的干预。 故障自恢复的高可用 TiDB / TiKV / PD 三个组件都能容忍部分实例失效,不影响整个集群的可用性。TiDB Server 节点失效,只会影响该节点上的 session,应用连接失败重试后可通过前端负载均衡中间件将请求发送到其他正常的 TiDB Server 节点。PD 节点失效,若非 Raft leader 节点(PD Cluster 通过 Raft 协议保证自身数据一致性)则无影响,否则会重新选取 leader,期间该无法对外提供服务(约 3 秒钟)。TiKV 节点失效,会影响该节点上的所有 region,若 region 非 Raft leader(TiKV Cluster 也通过 Raft 协议保证节点间的数据一致性),则服务不受影响,否则服务会中断,待重新选举 leader 后恢复。如果 PD 确认了失效的 TiKV 节点已经不能恢复,则会自动将该节点的数据调度至其他正常的 TiKV 节点。3. TiDB 其他特性及原理 高度兼容 MySQL 语法和协议; 分布式事务; 跨数据中心数据强一致性保证; 海量数据高并发实时写入与实时查询。 至于 TiDB 的内部原理,比如,数据在 TiKV 层是如何组织和管理的,又是如何保证数据一致性的;SQL 层是如何实现的,又是如何将关系型表结构、关系型数据、索引、SQL 映射为 K-V 模型的;PD 是如何保证自身元数据一致性的,又是如何协调 TiDB、调度 TiKV 实现负载均衡的超出了本文的范围。针对原理部分,TiDB 有三篇系列文章将这些问题描述的很清楚,详情可参考(以下文字可跳转至原文): 说存储 说计算 谈调度 可弹性扩容,故障自恢复且可自动迁移数据,高度兼容 MySQL 协议,快速 Online DDL,这是我们计划选择 TiDB 作为归档目标集群所考虑的主要四点。TiDB 在饿了么归档环境的实践 1. 初试 整个实践过程并非一帆风顺,部署和测试期间遇到过不少问题。经历了从单机 12 实例部署 TiKV,到单机 4 实例部署,再到目前的单机 3 实例部署。也经历了 TiDB 版本由 RC 升级 PreGA、由 PreGA 升级 GA1.0.0、再由 1.0.0 升级到目前的 1.0.4。还有期间各种压缩、缓存、调度等参数的组合测试与调优和各类 bug、疑难问题的排查与解决。起初,考虑到归档环境数据量庞大,且对于分布式的 TiDB 来说本身会存储多份数据副本无需对磁盘进行 RAID,而且机器内存和 CPU 充足,因此将每台物理机的 SATA 磁盘拆成了独立的 12 块,每块盘上部署一个实例,以增加集群总的可用空间。这样一共 3 台物理机共部署了 36 个 TiKV 实例来进行测试,TiDB 和 PD 各 3 个实例共享另外 3 台物理机。在使用 sysbench 压测过程中线程数开到 64 的时候(64 个表,单表 3000W 数据),持续的高并发写入导致数据在 TiKV 实例间分布极不均衡,写入的数据集中在其中 3 个 TiKV 实例,其他实例上的数据非常少,且没有看到预期的明显的数据从 region 较多的节点向 region 较少的节点调度的迹象。后台大量的 server busy 报错,监控页面大量的底层 RocksDB stall 信息。后期分析发现是 SATA 盘的性能太弱,而 TiDB 的各类默认参数都只针对 SSD/NVMe 盘做了优化(这也是官方的安装程序检测磁盘性能的原因),且当时的 TiDB 版本比较老,还没有热点调度功能,持续的并发写入导致磁盘 IO 飙升,region 数量快速增长且热点集中,大量的 region 调度又引起大量的 snapshot 操作,从而又加剧了磁盘 IO 的消耗,最终导致了恶性循环,region 在最初写入的节点不断堆积,无法调度出去。后期,将 12 块盘以 RAID10 方式打成了 1 块盘以提升性能,单台物理机的 TiKV 实例数量也由 12 降至了 3,增加了 block-cache-size 的大小,同时,考虑到机器 CPU 性能较强悍,调高了 TiKV 默认的 compression-level 以尽可能的减少需要调度的数据量,也将版本升级后遇到的问题得以解决。后续对 TiDB 的扩缩容,online DDL,高可用进行了测试,也都符合预期。尽管 TiDB 是兼容 MySQL 语法和协议的,但在测试过程中还是碰到一些小的问题。比如,暂不支持临时表,部分 SQL Hints 语法暂不支持,SELECT MIN()MAX() 查询有索引的列也会比较慢等。对此,我们对归档应用进行了兼容性的改造。比如,针对 SELECT MIN()MAX() 查询使用等价的 ORDER BY + LIMIT 1 的方式变通等(新版本已经直接支持了)。任何产品从最初开发到最终的成熟应用,迭代过程中必然会出现一些 bug,在使用 TiDB 的过程中也遇到过一些部署、授权、监控、PD-CTL 查看 store 状态信息等方面的问题。不过在反馈给 TiDB 官方团队后,都得到了快速的响应和解决。在 TiDB 集群测试基本满足需求后,我们并没有直接将现有的所有归档作业迁移至 TiDB。毕竟模拟压测和真实的应用环境还有比较大的差距,我们计划让 TiDB 承载尽可能接近真实的归档工作来进一步考验其表现。TiDB 官方提供了一个很好的工具—— Syncer 来做这个事情。Syncer 可以模拟成 MySQL Slave 节点从上游读取和解析 Binlog 并在匹配过滤规则后应用于下游的 TiDB(图 2)。Syncer 支持断点续传功能,可以同时起多个 Syncer 实例分别使用不同的过滤规则从一个数据源向到多个目标进行数据同步,也可以从多个数据源向同一个目标进行数据同步。我们选择了当前负载比较高的两套 MySQL 归档集群作为数据源,使用 Syncer 将每天夜里归档期间的增量数据(百 GB 数量级)实时同步至 TiDB 集群。同步持续运行了一周左右,未发现有明显异常。图 2 Syncer 架构2. 应用 即使利用 Syncer 同步数据的方案在 TiDB 集群模拟了归档期间的负载,但毕竟顺序应用 Binlog 时事务是单线程执行的,同直接在 TiDB 进行归档时的多线程并发执行的负载也还是有区别。所以,我们选择分批迁移归档作业至 TiDB 集群,每次一小批,运行一段时间无异常后迁移下一小批。截至目前,已有 45% 左右的归档作业迁移至了 TiDB 集群。至此 TiDB 集群一直平稳运行。当前的归档方案(图 3)。图 3 归档架构TiDB 集群的部署情况和集群监控告警架构(如图 4、图 5)。图 4 TiDB 集群部署情况对于归档表我们进行了分类处理,对于需要业务访问的表,在源和目标表结构不一致时会同步变更目标环境的表结构,对不需要业务访问的表,在遇到表结构不一致时或者每月月初会自动轮转一个新表,以便于后续的归档顺利进行和后期的过期数据处理。由于 DDL 在 TiDB 是串行执行的,且大部分表无需业务访问,所以在月初会有近五万张表的 rename、create 和 drop 操作在 TiDB 排队等待执行,造成较多的归档超时失败。对于这一部分的处理,我们计划将轮转表的逻辑从归档流程中解耦,在非归档时段提前将表慢慢轮转掉,到归档开始进行时便无需等待 DDL。图 5 TiDB 集群监控告警方案3. 成果 截至目前整个归档平台已部署归档作业千余个,涉及数百套源集群数百个库数百张表。其中 TiDB 上部署的归档作业占总归档作业量的 45%,涉及近百套源集群几十个库上百张表。整个归档平台日均数据增量数亿行,大小数百 GB,其中 MySQL 占 75% 左右,TiDB 占 25% 左右。目前 TiDB 集群的总容量几十 TB,已归档的数据量占 TiDB 集群总空间约 20%。后期,在现有 TiDB 集群容量不足时只需添加 TiKV 节点即可实现容量的扩展而无需迁移之上的归档作业,不影响业务的访问。对于源端发生了结构变更的表,也可以方便快速的在归档目标同步这个变更。如果集群中节点出现了故障也不会影响整个集群的访问,且在替换掉故障节点后数据会自动同步至新节点,无需人工干预。当前 TiDB 尚存在的一些问题 TiDB 中 DDL 串行执行,当某种原因在同一时刻有大量 DDL 请求时,会排队等待,待所有的 DDL 都执行完成可能需要很长时间。希望能增加 DDL 并发执行的特性。 当前需要手动对 TiDB 上的大表进行 Analyze 操作以收集准确的索引统计信息,以便于查询的高效执行。希望可支持自动采样分析来保证执行计划的准确性。 TiDB Binlog 依赖于 Kafka 集群,感觉架构有点重。 我们也就以上三点咨询了 TiDB 官方,下面是官方回复: 并行 DDL 正在做,预计会在 2.1 版本初步提供,3.0 版本完善。 目前发布 2.0 版本已经提供了统计信息的动态更新以及自动全量 analyze,不过还没有默认打开,测试稳定后,会默认打开。 为保证 Binlog 高可用,依赖于分布式消息队列在所难免,Kafka 是其中最好的解决方案。 关于使用 TiDB 的一些建议 多实例部署 TiKV 时, capacity、block-cache-size 等参数一定要设置好,否则可能导致磁盘空间溢出和内存溢出。每个 region 也会占用很少一部分的内存,随着集群 region 数量上升,TiKV 使用的内存量会缓慢上涨,需要留意。 在磁盘使用量达到了设置的 capacity 的 80% 左右时,集群会控制不往这些节点调度数据,但正常的数据写入依然会进行。另外,扩容需要额外的临时空间,所以需要提前做好扩容准备。建议在容量 60% 的时候就开始准备扩容工作。 多实例部署 TiKV 时需要设置好 label,以便于将数据尽可能的写到不同机房、机架和主机,避免几个副本落在同一台机器,保证各节点负载相对均衡。 TiDB 对单个事务大小有限制,主要原因是对大规模的数据做两阶段提交和多副本复制压力太大。在使用 mydumper 工具导出并使用 myloader 工具导入数据时常会碰到这个问题,可以通过加 -F 参数限制 mydumper 导出的单个 insert 的大小来避免。 计划 TiDB 在归档环境的成功应用是我们的一个良好开始,也为我们日后尝试在生产环境使用积累了不少经验,接下类我们计划再搭建 1~2 套 TiDB 集群,将剩余的未迁移至 TiDB 的归档作业全部迁移至 TiDB。另外,目前生产环境也存在较多的大表治理问题和海量数据的推送问题。传统的 Sharding 方案对一些不好确定 sharding key 的大表无能为力, MySQL 主从方案对于海量数据的推送也力不从心。因此我们需要找到解决方案来应对这些挑战。致谢 在 TiDB 部署与测试过程中,得到了 PingCAP 公司同事的大力支持。对他们的及时响应和耐心解答深表敬佩和谢意。TiDB 背后有这么一支强悍的精于技术和服务的队伍,想必一定会走的很长很远! 作者:张延召,饿了么高级数据库工程师 "}, {"url": "https://pingcap.com/cases-cn/user-case-kasi/", "title": "TiDB 助力卡思数据视频大数据业务创新", "content": " 卡思数据是国内领先的视频全网数据开放平台,依托领先的数据挖掘与分析能力,为视频内容创作者在节目创作和用户运营方面提供数据支持,为广告主的广告投放提供数据参考和效果监测,为内容投资提供全面客观的价值评估。图 1 卡思数据产品展示图业务发展遇到的痛点 卡思数据首先通过分布式爬虫系统进行数据抓取,每天新增数据量在 50G - 80G 之间,并且入库时间要求比较短,因此对数据库写入性能要求很高,由于数据增长比较快,对数据库的扩展性也有很高的要求。数据抓取完成后,对数据进行清洗和计算,因为数据量比较大,单表 5 亿 + 条数据,所以对数据库的查询性能要求很高。起初卡思数据采用的是多个 MySQL 实例和一个 MongoDB 集群,如图 2。 MySQL 存储业务相关数据,直接面向用户,对事务的要求很高,但在海量数据存储方面偏弱,由于单行较大,单表数据超过千万或 10G 性能就会急剧下降。 MongoDB 存储最小单元的数据,MongoDB 有更好的写入性能,保证了每天数据爬取存储速度;对海量数据存储上,MongoDB 内建的分片特性,可以很好的适应大数据量的需求。 图 2 起初卡思数据架构图但是随着业务发展,暴露出一些问题: MySQL 在大数据量的场景下,查询性能难以满足要求,并且扩展能力偏弱,如果采用分库分表方式,需要对业务代码进行全面改造,成本非常高。 MongoDB 对复杂事务的不支持,前台业务需要用到数据元及连表查询,当前架构支持的不太友好。 架构优化 1. 需求 针对我们遇到的问题,我们急需这样一款数据库: 兼容 MySQL 协议,数据迁移成本和代码改造成本低 插入性能强 大数据量下的实时查询性能强,无需分库分表 水平扩展能力强 稳定性强,产品最好有成熟的案例 2. 方案调研 未选择 TiDB 之前我们调研了几个数据库,Greenplum、HybirdDB for MySQL(PetaData)以及 PolarDB。Greenplum 由于插入性能比较差,并且跟 MySQL 协议有一些不兼容,首先被排除。HybirdDB for MySQL 是阿里云推出的 HTAP 关系型数据库,我们在试用一段时间发现一些问题: 一是复杂语句导致计算引擎拥堵,阻塞所有业务,经常出现查询超时的情况。 二是连表查询性能低下,网络 I/O 出现瓶颈。举一个常见的关联查询,cd_video 表,2200 万数据,cd_program_video 表,节目和视频的关联表,4700 万数据,在关联字段上都建有索引,如下 SQL:select v.id,v.url,v.extra_id,v.title fromcd_video v join cd_program_video pv on v.id = pv.video_id where program_id =xxx;当相同查询并发超过一定数量时,就会频繁报数据库计算资源不可用的错误。 三是 DDL 操作比较慢,该字段等操作基本需要几分钟,下发至节点后易出现死锁。 PolarDB 是阿里云新推出新一代关系型数据库,主要思想是计算和存储分离架构,使用共享存储技术。由于写入还是单点写入,插入性能有上限,未来我们的数据采集规模还会进一步提升,这有可能成为一个瓶颈。另外由于只有一个只读实例,在对大表进行并发查询时性能表现一般。3. 选择 TiDB 在经历了痛苦的传统解决方案的折磨以及大量调研及对比后,卡思数据最终选择了 TiDB 作为数据仓库及业务数据库。TiDB 结合了传统的 RDBMS 和 NoSQL 的最佳特性,高度兼容 MySQL,具备强一致性和高可用性,100% 支持标准的 ACID 事务。由于是 Cloud Native 数据库,可通过并行计算发挥机器性能,在大数量的查询下性能表现良好,并且支持无限的水平扩展,可以很方便的通过加机器解决性能和容量问题。另外提供了非常完善的运维工具,大大减轻数据库的运维工作。上线 TiDB 卡思数据目前配置了两个 32C64G 的 TiDB、三个 4C16G 的 PD、四个 32C128G 的 TiKV。数据量大约 60 亿条、4TB 左右,每天新增数据量大约 5000 万,单节点 QPS 峰值为 3000 左右。由于数据迁移不能影响线上业务,卡思数据在保持继续使用原数据架构的前提下,使用 Mydumper、Loader 进行数据迁移,并在首轮数据迁移完成后使用 Syncer 进行增量同步。卡思数据部署了数据库监控系统(Prometheus/Grafana)来实时监控服务状态,可以非常清晰的查看服务器问题。由于 TiDB 对 MySQL 的高度兼容性,在数据迁移完成后,几乎没有对代码做任何修改,平滑实现了无侵入升级。目前卡思数据的架构如图 3:图 3 目前卡思数据架构图查询性能,单表最小 1000 万,最大 8 亿,有比较复杂的连表查询,整体响应延时非常稳定,监控展示如图 4、图 5。图 4 Duration 监控展示图图 5 QPS 监控展示图未来展望 目前的卡思数据已全部迁移至 TiDB,但对 TiDB 的使用还局限在数据存储上,可以说只实现了 OLTP。卡思数据准备深入了解 OLAP,将目前一些需要实时返回的复杂查询、数据分析下推至 TiDB。既减少计算服务的复杂性,又可增加数据的准确性。感谢 PingCAP 非常感谢 PingCAP 小伙伴们在数据库上线过程中的大力支持,每次遇到困难都能及时、细心的给予指导,非常的专业和热心。相信 PingCAP 会越来越好,相信 TiDB 会越来越完善,引领 NewSQL 的发展。 作者:刘广信,火星文化技术经理 "}, {"url": "https://pingcap.com/cases-cn/user-case-ifeng/", "title": "TiDB 在凤凰网新闻内容业务的创新实践", "content": " 背景 凤凰网(纽交所上市公司,代码:FENG)是全球领先的跨平台网络新媒体公司,整合旗下综合门户凤凰网、手机凤凰网和凤凰视频三大平台,秉承”中华情怀,全球视野,兼容开放,进步力量”的媒体理念,为主流华人提供互联网、无线通信、电视网的三网融合无缝衔接的新媒体优质内容与服务。在媒体行业,新闻内容就是核心的业务数据,我们需要一个稳定的、具有高可用的、易水平扩展的数据存储系统,来存放公司核心数据,在最早,我们采用比较流行的 MySQL 来存储各个业务模块的内容,通过主从切换的方式进行高可用,但随着数据量的增加,MySQL 单机容量成为了瓶颈,传统的基于 MySQL 分片方案在实现及运维都需要比较昂贵的成本,同时 MySQL 主流主从切换方案由于机制问题,在判断“主库真死”,“新主库选举”及“新路由信息广播”上都存在一些不足,整体时间消耗比较大,并不能达到公司核心业务的高可用要求。于是,我们不得不寻找新的解决方案。选择 TiDB 前期方案选择在选择评估初期,我们主要有以下几个考虑点: 支持业务弹性的水平扩容与缩容; 满足业务故障自恢复的高可用; 支持 MySQL 便捷稳定的迁移,不影响线上业务; 支持 SQL,尽量少的改动代码; 使用上、运维上要足够优化,最好支持在线 DDL。 在寻找的道路中,我们惊喜的发现了 TiDB — 中国人研发主导的开源分布式数据库。数据库容量及扩展记得有这样一句话:“单机 MySQL 能解决的问题,不要使用 TiDB!”,我们原有的数据存储存放于多个 MySQL 数据库中。诚然,对于数据量小的库来说,一些常见的点查、范围查 MySQL 的性能要比 TiDB 的性能好,如果不考虑扩张的问题,短期内使用主从 MySQL 比使用 TiDB 更满足我们的线上需求,但是,即使如此,我们也不得不考虑成本问题。将多套线上的主从 MySQL 迁移到 TiDB,更能充分利用服务器资源,减少资源的浪费。而对于很多业务来说,扩张问题是不可能回避的,对数据日益增长的数据库来说,单表响应时间会越来越长,而分库分表的成本过高,代码需要改动和测试,即使业务上能接受这一次的操作,那下次扩容呢?TiDB 通过底层自动进行分片帮我们解决了这个问题,同时业务量的增加或减少可以通过添加减少节点来处理,代码上基本无改动,这也是我们所期望的。高可用对于原有的主从 MySQL,并没有配置高可用,我们也对 MHA 等第三方工具做过调研,在发生主从切换后,在新路由信息分发这块也依赖修改网络配置或者数据库中间件(DBproxy),有一定的时间成本,虽然业界有很多中间件方案,但也很多问题和技术成本,所以这个方向并不是我们首选,之前的方式是一旦 MySQL 主数据库宕机,我们通过内部的监控系统获知,再进行更改 Keepalived + HAproxy 配置,即使人为响应非常及时,其影响的时间也早已超过业务的容忍。而选择天然的多节点 TiDB 自然就避免了这一点,配合网络 HAproxy 完全实现了 DB 层面的高可用。前一段时间,我们内部监控系统升级,其中一台机器没有对 TiKV 添加监控,而该 TiKV 节点由于硬件原因服务宕了几天,我们业务上也未感知,当然这是我们的失误,但是也侧面反应了 TiDB 自身的高可用机制。OSC 问题众所周知,一个可编程的内容管理平台,增加字段是再正常不过的业务场景,虽然 MySQL 5.7 已经支持 Online DDL,但实际操作还有很多限制,并且经常性导致从库延迟,TiDB 支持在线 DDL,加字段的过程是非阻塞的,平滑的,业务无感知的,这也是我们选择它的一个重要原因。迁移 TiDBMySQL 数据迁移到 TiDB 上,我们使用 mydumper、loader 对数据导入导出。而后续数据的增量同步,PingCAP 公司提供了 Syncer 工具回放 MySQL 传来的 Binlog 日志来模拟 MySQL 的 Slave。让我们感到惊喜的是,它支持多个 MySQL 同时同步到一个 TiDB,刚开始,我们就采用这种方式来搭建环境,这种便捷的方案可以把我们的精力从数据迁移中解放出来,更多关注在业务测试和试用上,经过完善的业务测试后,我们发现 TiDB 高度兼容 MySQL,于是我们逐步将每个库流量切到 TiDB 上,整个数据迁移、流量迁移都非常友好便捷。实际迁移过程中,只遇到了由于部分原有 MySQL 版本过低导致 Binlog 格式不兼容的问题,除此之外其他都很顺利。节点迁移TiDB 的线上节点迁移。我们线上的部分 TiDB 是使用 Binary 部署的,且版本过老(2016 年的版本),无法进行及时的自动化升级,因此当我们涉及到机房迁移的时候,会担心是否会影响服务。好在迁移涉及的是无状态的 TiDB 节点和存储元数据的 PD 节点,在对 PD 节点一上一下逐步增加减少验证无误后,启动新机房中的 TiDB 节点,经 Haproxy 层灰度上线几台后,下掉原有的 TiDB 节点,完成迁移。官方强力支持当然,虽然官方提供的迁移方案很友好,但在学习了解、实际操作阶段也免不了磕磕绊绊,之前很长一段时间内我们并没有与 PingCAP 公司取得联系,但当我们出现迁移问题的时候,我们选择求助官方,他们非常迅速的响应了我们,解决了线上迁移因 etcd 导致的 PD 节点去除故障,而且还安排了架构师来我们公司进行技术交流,锦上添花不如雪中送炭,当时我们在与官方人员沟通时,深深体会到了这一点。TiDB 数据库的稳定性还是非常不错的,在我们和官方取得联系的时候,我们使用的 beta4 版本也已稳定运行了近 220 天。TiDB 目前环境目前我司有三套 TiDB 在使用,均为 OLTP 业务。其中前两套使用 Binary 安装的远古版本(beta4),第三套才是 TiDB GA 版本,通过官方 Ansible 进行的部署。在与官方沟通中获知,两套远古版本(beta4)由于距离现有版本太多需要进行迁移升级,官方也十分愿意为我们提供技术支持,在此,就先谢过官方的帮助,显然,对我们来说后续也少不了麻烦。一点吐槽TiDB 的出现,帮我们跳过了传统的 Sharding + proxy 的路线,给我们节省了巨大的技术成本,我们对 TiDB 非常的钟爱,但在接触、使用 TiDB 过程中,我们也遇到一些问题。即使官方对于服务器配置有明确的要求(SSD 以上硬盘),但对我们公司内来说,刚开始很难申请到高性能的机器来进行 TiDB 功能性测试,和学习、熟悉 TiDB 的搭建、扩容、迁移等操作,于是在刚开始,我们拿几台低性能的测试机,使用 loader 导入数据进而进行增量测试的时候,出现了报错,TiDB 的报错信息并没有提醒我这是由于机器性能低引起的,而在官方文档中,也没有这方面的引导,这导致我们反复导入测试多次,问题依然存在,后才考虑可能是机器性能导致的(官方已经在最新的 ansible 安装脚本中做了硬件的性能检测),于是申请了几台高性能机器进行复测,验证确实是因为机器性能导致。后在与官方人员沟通时得知,整个 TiDB 架构是面向未来、面向海量数据高并发场景,底层存储技术(如数据定位 seek)都是针对当前主流的 SSD 进行设计和优化的,不会对传统的 SATA/SAS 机械硬盘再进行优化。至于官方文档和报错信息,他们也在持续快速的更新中。展望 在与官方进行详细沟通,听取官方架构师的分享后,我们近期打算再上 2-3 套 TiDB 集群对众多不同业务线主从 MySQL 进行整理归纳,这样不但可以逐步统一、规范数据库的使用,而且还可以大大减少机器资源浪费,运维成本,同时借助 TiDB 实现我司数据库的高可用。而在听取分享的其他部门的小伙伴也已经行动起来,对于我司一个重点 OLTP 新项目,已经确定使用 Cloud TiDB(在 K8S 上部署 TiDB)作为数据库系统。同时我们了解到,TiDB 不仅仅满足 OLTP 业务,它还能满足很多 OLAP 业务场景,听完分享后,大数据组小伙伴也在跃跃欲试中。未来,我们将加强与 PingCAP 官方的沟通交流,进行更深入的研究和开发,持续提升 TiDB 的性能,将它全面应用到凤凰网业务中。 作者:卞新栋,凤凰网工程师 "}, {"url": "https://pingcap.com/cases-cn/user-case-g7/", "title": "TiDB 在 G7 的实践和未来", "content": " 背景 2010 年,G7 正式为物流运输行业提供面向车队管理的 SaaS 服务,经过持续创新,通过软硬一体化的产品技术能力,致力于数字化每一辆货车,以实时感知技术创造智慧物流新生态。G7 为客户提供全方位的数据服务、智能的安全和运营管理、手机管车、数字运力、以及 ETC、油和金融等增值服务。目前,G7 连接了 600,000 辆货车,每天行驶 6500 万公里(可绕地球赤道 1625 圈),13.5 亿个轨迹点和 2,200 万次车辆事件触发,并且以直线速度飞速增长。G7 每天产生的车辆行驶、状态、消费等数据超过 2T,飞速增加的车辆、数据类型和复杂的金融业务,使得数据库的事务、分析、扩展和可用性面临巨大的挑战。在大量的车辆信息和轨迹相关数据业务中,当前我们通过 Spark、Hive 等对大量原始数据进行分析后,存入阿里云 DRDS,对外提供基础数据接口服务。由于清洗后的数据量依然很大,使用 DRDS 的存储成本非常高,且面对很多 OLAP 的查询时,效率不如人意。而在金融和支付这种复杂业务场景中,面临 CAP 中 C 和 P 的挑战。在以往的工作中,支付系统由于面临强一致性事务的高峰值写入问题,采用了 2PC+MySQLXA(单个 MySQL 作为参与者,上层增加 Proxy 作为协调者)完成了分布式事务数据库的方案。但是这种方案在 Partition 中,极为麻烦。同时,运营和风控系统经常需要做相对复杂的查询,要么通过 MySQL+ETL+OLAP 数据库(成本高),要么容忍查询的效率问题。探索 G7 的技术团队一直在寻找一种能解决上述问题的数据库。要找到这样一种数据库,除了需要满足上述需求以外,还需要满足另一个需求:可维护性和易迁移性。这要求该数据库具体需要满足如下几个要求: 兼容 MySQL 协议,使得数据库的变更对上层业务透明,这个有多重要,做过基础架构升级落地的同学应该深有感触。 支持 MySQL 的主从同步机制,使得数据库的变更可以平滑逐步升级,降低变更风险。 必须是开源的。数据库的稳定需要付出很大的精力和时间,在这个过程中,或多或少都出现问题。出现问题不可怕,可怕的是无法定位和解决问题,只能依赖“他人”。数据库的一个 BUG 对“他人”来说,可能是一个小问题,对 G7 业务而言,可能是一个巨大的灾难。当“屁股”不在同一个板凳上时,我们需要对数据库有很强的掌控力。 开源的同时,背后一定需要有一个有实力的技术团队或商业公司的全力投入。在见识了不少“烂尾”和“政绩”的开源项目后,只有一个稳定全职投入的技术团队或商业公司,才能最终让这个数据库越来越好。 在这么多限制和需求的情况下,TiDB+TiSpark 很快进入我们的视线,并且开始调研。通过和 TiDB 技术人员的交流,除了满足上述的需求外,如下技术细节使我们一致认为可以选择这样的方案: 将 MySQL 架构中 Server 和 StorageEngine 概念进一步松耦合,分为 TiDB 和 TiKV,水平扩展性进一步提升。 定位于 Spanner 的开源实现,但是没有选择 Multi-Paxos,而是采用了更容易理解、实现和测试的 Raft,使得我们在分布式一致性上少了很多担忧。 使用 RocksDB 作为底层的持久化KV存储,单机的性能和稳定性经过了一定的考验。 基于 GooglePercolator 的分布式事务模型,在跨区域多数据中心部署时对网络的时延和吞吐要求比较高,但我们目前没有这样的强需求。 初体验——风控数据平台 该风控数据平台是将众多的业务数据做清洗和一定复杂度的计算,形成一个客户在 G7 平台上金融数据指标,供后续的风控人员来查询客户的风险情况,同时支撑运营相对复杂的查询。由于数据量较大,传统的关系型数据库在扩展性和处理 OLAP 上不符合该业务的需求;同时该业务面向内部,在一开始不熟悉的情况下,不会影响到客户,因此,我们决定在这个业务上,选择使用 TiDB。风控数据平台开始于 2017 年 8 月,2017 年 10 月上线了第一个版本,对线上用户提供服务。最开始使用的 TiDB RC4 版本,后升级到 Pre-GA,我们计划近期升级到 GA 版本。系统架构如下所示,整个流程非常简洁高效。在使用的过程中,我们还是遇到了不少兼容性相关的问题。为了增加我们对 TiDB 的理解,我们和 TiDB 技术团队取得联系,积极参与到 TiDB 项目中,熟悉代码和修复部分兼容性和 BUG 相关的问题。以下是我们在实践过程中解决的问题: 修复 INFORMATION_SCHEMA.COLUMNS 中 ,COLUMN_TYPE 不支持 UNSIGNED 的兼容性问题。https://github.com/pingcap/tidb/pull/3818 修复 IGNORE 关键字对 INSERT、UPDATE和DELETE 的兼容性问题。https://github.com/pingcap/tidb/pull/4376https://github.com/pingcap/tidb/pull/4397https://github.com/pingcap/tidb/pull/4564 修复 Set 和 Join 中存在的 PanicBUG。https://github.com/pingcap/tidb/pull/4326https://github.com/pingcap/tidb/pull/4613 增加了对 SQL_MODE 支持 ONLY_FULL_GROUP_BY 的特性。https://github.com/pingcap/tidb/pull/4613 这里仍然存在一个与 MySQL 不兼容的地方。当开启事务后,如果 insert 的语句会导致主键或者唯一索引冲突时,TiDB 为了节省与 TiKV 之间的网络开销,并不会去 TiKV 查询,因此不会返回冲突错误,而是在 Commit 时才告知是不是冲突了。希望准备使用或关注 TiDB 的朋友能注意到这一点。后来我们咨询 TiDB 官方,官方的解释是:TiDB 采用乐观事务模型,冲突检测在执行 Commit 操作时才会进行。感谢在初体验过程中,TiDB 团队非常认真、负责和快速的帮助我们排查和解决问题,提供了非常好的远程支持和运维建议。在其它业务中的推广规划 2018 年初,运维团队和每一个业务方进行了一次需求沟通,业务方对 TiDB 的需求越来越强烈。我们正沿着如下的路径,让 TiDB 发挥应用到更多的场景中。 将 TiDB 作为 RDS 的从库,将读流量迁移到 TiDB; 从内部业务开始,逐步将写流量迁移到 TiDB; 将更多 OLAP 的业务的迁到 TiSpark 上; 合作开发 TiDB 以及 TiDB 周边工具。 参与 TiDB 社区的 Tips 善用 GDB 工具去了解和熟悉 TiDB 的代码结构和逻辑。 初始选择一些 Issue,去分析和尝试修复。 利用火焰图去关注和优化性能。 如果没有读过周边的论文,可以试着去读一读,加深对系统原理的理解。 积极参与 TiDB 的社区活动,加深与 TiDB 核心研发的沟通。 有合适的业务场景,可以多试用 TiDB,拓宽 TiDB在 不同场景下的应用实践。 作者简介:廖强,曾供职于百度,负责百度钱包的分布式事务数据库,基础架构和收银台。现 G7 汇通天下技术合伙人,负责金融产品研发、运维和安全。 "}, {"url": "https://pingcap.com/cases-cn/user-case-mobikok/", "title": "TiDB 在 Mobikok 广告系统中的应用和实践", "content": " 公司介绍 Mobikok(可可网络)成立于 2013 年,是一家快速成长的移动互联网营销公司,专注于移动 eCPM 营销。总部在中国深圳,聚焦于订阅 offer 的海外流量变现业务。Mobikok 提供的接口方式支持各类手机端流量(API、SDK、Smartlink),RTB(实时竞价系统)对接海外的 DSP(Demand-Side Platform,需求方平台)高效优化客户的广告效果。截止目前,系统已对 2 亿用户进行广告优化,已接入上百家广告主以及上百家渠道,Mobikok 致力于高效,便捷,专业的帮助广告主以及渠道互惠共赢。场景介绍:SSP 系统 订阅 SSP(Sell-Side-Platform)平台当前业务主要分为:SDK、Smartlink、Online API 以及 Offline API;在当前 SSP SDK 业务系统当中,累计用户已达到 2 亿,最初使用的是 MySQL 主从分表的方式存储用户数据,随着数据量的增加,MySQL 单机容量以及大数据量查询成为了瓶颈;当单表数据达到 2 千万以上时,单机 MySQL 的查询以及插入已经不能满足业务的需求,当访问量到一定阶段后,系统响应能力在数据库这一块是一个瓶颈。一次很偶然的机会在 GitHub 上面了解到 TiDB,并且因为现在业务系统当中使用的 Redis 集群是 Codis,已在线上稳定使用两年,听闻 TiDB 创始团队就是之前 Codis 的作者,所以对 TiDB 有了极大的兴趣并且进行测试。通过测试单机 MySQL 和 TiDB 集群,当数据量达到数千万级别的时候发现 TiDB 效率明显高于 MySQL。所以就决定进行 MySQL 到 TiDB 迁移。迁移后整体架构图:引入 TiDB 在选择使用替换 MySQL 方案当中。我们主要考虑几点: 支持 MySQL 便捷稳定的迁移,不影响线上业务; 高度兼容 MySQL,少改动代码; 支持水平弹性部署服务以及在线升级; 支持水平扩展业务; 成熟的配套监控服务。 TiDB 数据库整体集群配置:2*TiDB、3*TiKV、3*PD。从 12 月初正式上线到目前为止,TiDB 稳定运行四个多月,最高 QPS 达到 2000,平均 QPS 稳定在 500 左右。TiDB 在性能、可用性、稳定性上完全超出了我们的预期,但是由于前期我们对 TiDB 的了解还不深,在此迁移期间碰到的一些兼容性的问题,比如 TiDB 的自增 ID 的机制,排序的时候需要使用字段名等,咨询 TiDB 的工程师都很快的得到了解决,非常感谢 TiDB 团队的支持以及快速响应。下图是当前集群的 Grafana 展示图:后续计划 使用 TiDB 对于像我们这样可预期核心数据会暴增的场景,有非常大的意义。在后端支撑力量有限时,业务暴增时只需要增加机器,而不是频繁重构业务,让我们有更多精力在自己的业务上耕耘,增加我们的行业竞争力。未来我们还有 ADX(Ad Exchang,广告交易平台)和 DSP 业务,需要处理海量的用户数据以及广告数据。目前统计数据这一块当前业务当中使用的是 Spark Streaming,通过和 TiDB 开发团队沟通,官方 TiSpark 可直接引入到当前统计 Spark 群集当中,非常期望在后续开发当中使用 TiSpark。问题建议 在实际应用当中,因为我们切换的并不是只有用户数据表,还迁移了关于广告业务、渠道业务基础数据表。由于 TiDB 是一个分布式数据库,对于一些小表以及 count(*) 操作会影响效率,后来咨询 TiDB 官方得知,TiDB 有不同的隔离级别,SQL 也有高低优先级,如果有全表扫描的需求,可以使用低的隔离级别或者是低的优先级。将来我们就可以直接所有线上业务使用 TiDB 进行替换,最后还是非常感谢 TiDB 团队的支持与帮助。 作者:rayi,深圳可可网络服务端架构负责人 "}, {"url": "https://pingcap.com/cases-cn/user-case-linkdoc/", "title": "TiDB 在零氪科技(LinkDoc)大数据医疗系统的实践", "content": " 公司介绍 零氪科技作为全球领先的人工智能与医疗大数据平台,拥有国内最大规模、体量的医疗大数据资源库和最具优势的技术支撑服务体系。多年来,零氪科技凭借在医疗大数据整合、处理和分析上的核心技术优势,依托先进的人工智能技术,致力于为社会及行业、政府部门、各级医疗机构、国内外医疗器械厂商、药企等提供高质量医疗大数据整体解决方案,以及人工智能辅助决策系统(辅助管理决策、助力临床科研、AI 智能诊疗)、患者全流程管理、医院舆情监控及品牌建设、药械研发、保险控费等一体化服务。LinkDoc 的主要应用场景 LinkDoc 通过将患者真实的病例数据和算法模型应用于肿瘤治疗,构建精准的诊疗模型并提供数据支持,从而辅助医院管理决策、辅助科研、辅助临床诊疗。目前 Hubble 系统“肺癌淋巴结跳跃转移风险预测”模块可避免肺癌病人由于误判而导致提前 8-10 个月的复发,每年能让近两万病人的生命再延长 8-10 个月。Hubble 系统“AI - 肺结节智能诊断”模块全自动地识别 CT 影像中所有的结节,识别率达 91.5%。LinkDoc 希望凭借医疗大数据整合、处理和分析上的核心技术优势,以互联网人工智能上的创新研发,提升中国医师的全球医学水准,并通过支持药物研发与医疗保险行业的发展,让每一位患者享有普惠、精准的医疗服务。支撑 LinkDoc 业务的底层数据库平台也面临着医疗行业新领域的技术 & 业务挑战,如数据量的快速增长(亿级别)、大数据量下的清洗逻辑的数据擦写、分析型事务对数据库的读压力都要求我们在数据库平台进行重新探索,选择一款适合医疗大数据业务的数据库解决方案。选择 TiDB 业务痛点 数据量大,单实例 MySQL 扩容操作复杂; 写入量大,主从延时高,由于业务对数据有低延时的要求,所以传统的 MySQL 主从架构在该项目下不能满足需求,大量数据写入下主库成为性能瓶颈; 随着数据量越来越大,部分统计查询速度慢; 分库分表业务开发和维护成本高。 业务需求 高可靠性 & 稳定性; 可扩展性,可随数据量 & 请求量增长快速提升存储 & 请求处理能力; 更低的延时。 方案调研 未选择 TiDB 之前我们调研了 MyCAT、Cobar、Atlas 等中间件解决方案,这些中间件整体来说就是让使用者觉得很“拧巴”,从社区支持、MySQL 功能兼容、系统稳定性上都不尽人意,需要业务做大量改造,对于快速发展的公司来说切换成本太高。在 LinkDoc 首席架构师王晓哲的推荐下我们调研了 TiDB, TiDB 的如下特性让我们眼前一亮: 兼容绝大部分 SQL 功能(意味着业务可以简单改造后平滑迁移至 TiDB); 水平扩展能力; 分布式事务; 故障快速恢复能力; 监控指标覆盖度。 上线 TiDB 兼容性测试 经过兼容性测试后我们对业务做了如下简单改造: Blob 类型数据迁移至 HBase 做 key-value 存储; Batch delete 改成小批量多次操作,一批删除 1000 条。 灰度上线 由于业务对于主从同步延时要求较高,我们采用业务双写的方案切换了我们的第一个应用。灰度第一阶段业务同时写 MySQL、TiDB,读走 MySQL,并验证数据一致性,经过2周的验证后我们灰度第二阶段。灰度第二阶段业务双写 TiDB、MySQL,读业务走 TiDB。经过一个月的业务验证后我们彻底下掉了 MySQL。系统架构 上线过程中也遇到一个小坑,之前用的阿里云普通实例 + SSD 云盘跑 TiDB,在该配置下经常会遇到性能抖动问题,在 PingCAP 同学的建议下我们更换了阿里云本地 SSD 型机型,目前系统运行良好。系统配置 & 架构如下:生产集群部署情况(机器基于阿里云):目前现状和下一步规划 目前 TiDB 在 LinkDoc 已承载数据量最大的两个业务。平时 QPS 6K,峰值 12K。后续将使用 TiDB 承载更多大数据量业务库, 并调研 TiSpark。通过 TiDB 构造成一个兼容分析型和事务型的统一数据库 HTAP 平台。致 PingCAP 非常感谢 PingCAP 小伙伴们的大力支持,从硬件选型、业务优化、系统培训到上线支持 PingCAP 都展现了热情的服务态度、专业的技术能力,帮助 LinkDoc 顺利上线 TiDB,解决系统难题,支持业务快速发展。相信在这样一群小伙伴的努力下 TiDB 会越来越成熟、承载更多的业务场景,用技术创造奇迹。 作者介绍:杨浩,现任零氪科技运维&安全负责人,曾就职于阿里巴巴-技术保障部-CDN。专注 CDN、安全、自动化运维、大数据等领域。 "}, {"url": "https://pingcap.com/cases-cn/user-case-yimian/", "title": "TiDB 助力一面数据实现消费领域的决策分析平台", "content": " 公司介绍 深圳市一面网络技术有限公司(下称:一面数据)是一家为消费领域的领导企业提供实时、精准、全面的数据洞察和决策指导的创新型企业,利用人工智能和算法,进行自然语言处理,语义情感分析,回归预测模型等,帮助客户实现精准产品运营和预测市场变化。一面数据服务于国内外一流企业,包括世界最大的对冲基金、国际一线汽车品牌、快消品龙头厂商,以及时尚鞋服大牌等。改造前系统架构 一面数据的核心 IT 系统覆盖了从数据获取、数据清洗处理、数据建模到数据可视化的全套数据分析流程。核心系统每天有海量从互联网采集的公开数据和来自企业内部的数据,对数据存储的容量、扩展性和可用性都有很高的要求。起初,一面数据的核心系统采用的是多个 MySQL 实例和一个 Cassandra 集群。MySQL 多实例集群主要存储指定特征的爬虫数据,Cassandra 主要存储数据量大、不适合存储 MySQL 的全页面缓存的数据。在数据量/请求量小的时候系统运行正常。下图为一面数据改造前系统构架图:随着数据量的增长,逐渐暴露出很多问题: MySQL:随着数据增长,存储容量接近单机的磁盘极限,单机的磁盘 IO 繁忙且易阻塞,查询性能难以满足业务增长的需求。数据量大了以后,传统的 MySQL 水平扩展能力弱,性能和稳定性容易产生问题,在数据量和访问量增长到一定阶段将无法满足常见的 OLAP 场景分析需求。技术团队通过诊断系统性能问题,认识到现有数据库已经成为瓶颈。 Cassandra:Cassandra 对磁盘 IO 和内存要求高,添加一个实例,需要从其他实例迁数据,对网络带宽、 磁盘要求特别高。另外 CQL 支持的特性太少,业务开发麻烦,例如不能联表,不支持主键之外的索引,对主键以外的查询比较困难,虽然有 Secondary Index,但是使用限制大。生态圈不完善,例如很难找到好用的监控。 改造后的系统架构 引入 TiDB 替换 MySQL 和 Cassandra 为从根本上解决以上问题,一面数据的技术团队决定通过增加部署一套高性能的数据库系统,以解决当前业务的痛点。 在评估和验证了 MySQL Sharding 和 MongoDB 等传统技术手段之后,团队认识到:基于 MySQL Sharding (即利用 MySQL 中间件分库分表) 架构在高可用安全能力,业务和查询的灵活支持以及运维管理难度和成本上都不尽如人意,有着诸多架构上和技术上的缺陷;而 MongoDB 比较适合存储爬虫数据,但迁移成本高,不管是数据还是应用程序都需要做侵入性修改和调整,难度和开发成本骤升。另外,作为 NoSQL 数据库,MongoDB 不支持 SQL 和 JOIN ,对 BI 工具的支持也不完善,数据分析师们无法直接使用。 最终从满足业务需求、降低切换成本和减少运维成本等角度考虑,一面数据选择了分布式关系型数据库-TiDB 作为业务的首选事务型数据库。TiDB 支持包括跨行事务,JOIN 及子查询在内的绝大多数 MySQL 的语法,用户可以直接使用现有的 MySQL 客户端连接。如果现有的业务已经基于 MySQL 开发,大多数情况不需要修改代码即可直接替换单机的 MySQL。同时现有的大多数 MySQL 运维工具(如 PHPMyAdmin, Navicat, MySQL Workbench 等),以及备份恢复工具(如 mysqldump, mydumper / myloader)等都可以在 TiDB 直接使用,这也让开发运维人员不用关注数据库 scale 的细节问题,专注于业务开发,极大的提升研发的生产力。下图为一面数据改造后系统构架图:一面数据的生产环境部署了数十个 TiKV 节点及几个 TiDB 节点。迁移原有 MySQL 集群数据时使用 Percona 的 mydumper 以及 TiDB 专有优化的 loader 工具,逐个爬虫进行迁移。目前 TiDB 集群存储了接近数十 TB 的数据,把另外几个应用迁移完成后将会每日新增近亿条记录。完成迁移以后,系统不再需要维护多个 MySQL 实例以及 Cassandra 集群,运维成本大幅缩减,监控使用 Prometheus/Grafana,并且可以通过 Prometheus 的 AlertManager 定制规则复杂的报警规则。这些改变都让一面数据的爬虫存储侧的工作便利许多,可以让一面数据的研发把精力更多放在业务研发而不是运维多个不同技术栈的复杂集群。未来的架构规划 目前 TiDB 新增了 TiSpark 组件,并且在 TiKV 层实现了 Spark 的下推算子,使得可以直接在 TiDB 集群上跑 Spark 程序,这样可以省去 ETL 的步骤。后续一面数据也考虑深入使用 TiSpark 组件,让一面数据的整个系统增加一定的实时复杂查询的能力。长远来看,可以把现在 ElasticSearch,Impala,Hive 的业务都迁移到 Spark 集群上,这样一方面统一了分析侧的技术栈,另一方面连接了 Spark 丰富庞大的生态。下图为一面数据未来系统构架图:在一面数据 CTO 张锦杰看来:“TiDB 水平扩展性、兼容 MySQL 是非常好的特性,对需要使用关系型数据库作为存储方案的业务有极大的诱惑力,避免了传统分表、分库方案带来的上层应用的复杂性,解决了我们目前迫切的关系型数据存储的需求。” 作者:刘畅, "}, {"url": "https://pingcap.com/blog-cn/tidb-source-code-reading-23/", "title": "TiDB 源码阅读系列文章(二十三)Prepare/Execute 请求处理", "content": " 在之前的一篇文章《TiDB 源码阅读系列文章(三)SQL 的一生》中,我们介绍了 TiDB 在收到客户端请求包时,最常见的 Command --- COM_QUERY 的请求处理流程。本文我们将介绍另外一种大家经常使用的 Command --- Prepare/Execute 请求在 TiDB 中的处理过程。Prepare/Execute Statement 简介 首先我们先简单回顾下客户端使用 Prepare 请求过程: 客户端发起 Prepare 命令将带 “?” 参数占位符的 SQL 语句发送到数据库,成功后返回 stmtID。 具体执行 SQL 时,客户端使用之前返回的 stmtID,并带上请求参数发起 Execute 命令来执行 SQL。 不再需要 Prepare 的语句时,关闭 stmtID 对应的 Prepare 语句。 相比普通请求,Prepare 带来的好处是: 减少每次执行经过 Parser 带来的负担,因为很多场景,线上运行的 SQL 多是相同的内容,仅是参数部分不同,通过 Prepare 可以通过首次准备好带占位符的 SQL,后续只需要填充参数执行就好,可以做到“一次 Parse,多次使用”。 在开启 PreparePlanCache 后可以达到“一次优化,多次使用”,不用进行重复的逻辑和物理优化过程。 更少的网络传输,因为多次执行只用传输参数部分,并且返回结果 Binary 协议。 因为是在执行的同时填充参数,可以防止 SQL 注入风险。 某些特性比如 serverSideCursor 需要是通过 Prepare statement 才能使用。 TiDB 和 MySQL 协议 一样,对于发起 Prepare/Execute 这种使用访问模式提供两种方式: Binary 协议:即上述的使用 COM_STMT_PREPARE,COM_STMT_EXECUTE,COM_STMT_CLOSE 命令并且通过 Binary 协议获取返回结果,这是目前各种应用开发常使用的方式。 文本协议:使用 COM_QUERY,并且用 PREPARE,EXECUTE,DEALLOCATE PREPARE 使用文本协议获取结果,这个效率不如上一种,多用于非程序调用场景,比如在 MySQL 客户端中手工执行。 下面我们主要以 Binary 协议来看下 TiDB 的处理过程。文本协议的处理与 Binary 协议处理过程比较类似,我们会在后面简要介绍一下它们的差异点。COM_STMT_PREPARE 首先,客户端发起 COM_STMT_PREPARE,在 TiDB 收到后会进入 clientConn#handleStmtPrepare,这个函数会通过调用 TiDBContext#Prepare 来进行实际 Prepare 操作并返回 结果 给客户端,实际的 Prepare 处理主要在 session#PrepareStmt 和 PrepareExec 中完成: 调用 Parser 完成文本到 AST 的转换,这部分可以参考《TiDB 源码阅读系列文章(五)TiDB SQL Parser 的实现》。 使用名为 paramMarkerExtractor 的 visitor 从 AST 中提取 “?” 表达式,并根据出现位置(offset)构建排序 Slice,后面我们会看到在 Execute 时会通过这个 Slice 值来快速定位并替换 “?” 占位符。 检查参数个数是否超过 Uint16 最大值(这个是 协议限制,对于参数只提供 2 个 Byte)。 进行 Preprocess, 并且创建 LogicPlan, 这部分实现可以参考之前关于 逻辑优化的介绍,这里生成 LogicPlan 主要为了获取并检查组成 Prepare 响应中需要的列信息。 生成 stmtID,生成的方式是当前会话中的递增 int。 保存 stmtID 到 ast.Prepared (由 AST,参数类型信息,schema 版本,是否使用 PreparedPlanCache 标记组成) 的映射信息到 SessionVars#PreparedStmts 中供 Execute 部分使用。 保存 stmtID 到 TiDBStatement (由 stmtID,参数个数,SQL 返回列类型信息,sendLongData 预 BoundParams 组成)的映射信息保存到 TiDBContext#stmts。 在处理完成之后客户端会收到并持有 stmtID 和参数类型信息,返回列类型信息,后续即可通过 stmtID 进行执行时,server 可以通过 6、7 步保存映射找到已经 Prepare 的信息。COM_STMT_EXECUTE Prepare 成功之后,客户端会通过 COM_STMT_EXECUTE 命令请求执行,TiDB 会进入 clientConn#handleStmtExecute,首先会通过 stmtID 在上节介绍中保存的 TiDBContext#stmts 中获取前面保存的 TiDBStatement,并解析出是否使用 userCursor 和请求参数信息,并且调用对应 TiDBStatement 的 Execute 进行实际的 Execute 逻辑: 生成 ast.ExecuteStmt 并调用 planer.Optimize 生成 plancore.Execute,和普通优化过程不同的是会执行 Exeucte#OptimizePreparedPlan。 使用 stmtID 通过 SessionVars#PreparedStmts 获取到到 Prepare 阶段的 ast.Prepared 信息。 使用上一节第 2 步中准备的 prepared.Params 来快速查找并填充参数值;同时会保存一份参数到 sessionVars.PreparedParams 中,这个主要用于支持 PreparePlanCache 延迟获取参数。 判断对比判断 Prepare 和 Execute 之间 schema 是否有变化,如果有变化则重新 Preprocess。 之后调用 Execute#getPhysicalPlan 获取物理计划,实现中首先会根据是否启用 PreparedPlanCache 来查找已缓存的 Plan,本文后面我们也会专门介绍这个。 在没有开启 PreparedPlanCache 或者开启了但没命中 cache 时,会对 AST 进行一次正常的 Optimize。 在获取到 PhysicalPlan 后就是正常的 Executing 执行。COM_STMT_CLOSE 在客户不再需要执行之前的 Prepared 的语句时,可以通过 COM_STMT_CLOSE 来释放服务器资源,TiDB 收到后会进入 clientConn#handleStmtClose,会通过 stmtID 在 TiDBContext#stmts 中找到对应的 TiDBStatement,并且执行 Close 清理之前的保存的 TiDBContext#stmts 和 SessionVars#PrepareStmts,不过通过代码我们看到,对于前者的确直接进行了清理,对于后者不会删除而是加入到 RetryInfo#DroppedPreparedStmtIDs 中,等待当前事务提交或回滚才会从 SessionVars#PrepareStmts 中清理,之所以延迟删除是由于 TiDB 在事务提交阶段遇到冲突会根据配置决定是否重试事务,参与重试的语句可能只有 Execute 和 Deallocate,为了保证重试还能通过 stmtID 找到 prepared 的语句 TiDB 目前使用延迟到事务执行完成后才做清理。其他 COM_STMT 除了上面介绍的 3 个 COM_STMT,还有另外几个 COM_STMT_SEND_LONG_DATA,COM_STMT_FETCH,COM_STMT_RESET 也会在 Prepare 中使用到。COM_STMT_SEND_LONG_DATA 某些场景我们 SQL 中的参数是 TEXT,TINYTEXT,MEDIUMTEXT,LONGTEXT and BLOB,TINYBLOB,MEDIUMBLOB,LONGBLOB 列时,客户端通常不会在一次 Execute 中带大量的参数,而是单独通过 COM_SEND_LONG_DATA 预先发到 TiDB,最后再进行 Execute。TiDB 的处理在 client#handleStmtSendLongData,通过 stmtID 在 TiDBContext#stmts 中找到 TiDBStatement 并提前放置 paramID 对应的参数信息,进行追加参数到 boundParams(所以客户端其实可以多次 send 数据并追加到一个参数上),Execute 时会通过 stmt.BoundParams() 获取到提前传过来的参数并和 Execute 命令带的参数 一起执行,在每次执行完成后会重置 boundParams。COM_STMT_FETCH 通常的 Execute 执行后,TiDB 会向客户端持续返回结果,返回速率受 max_chunk_size 控制(见《TiDB 源码阅读系列文章(十)Chunk 和执行框架简介》), 但实际中返回的结果集可能非常大。客户端受限于资源(一般是内存)无法一次处理那么多数据,就希望服务端一批批返回,COM_STMT_FETCH 正好解决这个问题。它的使用首先要和 COM_STMT_EXECUTE 配合(也就是必须使用 Prepared 语句执行), handleStmtExeucte 请求协议 flag 中有标记要使用 cursor,execute 在完成 plan 拿到结果集后并不立即执行而是把它缓存到 TiDBStatement 中,并立刻向客户端回包中带上列信息并标记 ServerStatusCursorExists,这部分逻辑可以参看 handleStmtExecute。客户端看到 ServerStatusCursorExists 后,会用 COM_STMT_FETCH 向 TiDB 拉去指定 fetchSize 大小的结果集,在 connClient#handleStmtFetch 中,会通过 session 找到 TiDBStatement 进而找到之前缓存的结果集,开始实际调用执行器的 Next 获取满足 fetchSize 的数据并返回客户端,如果执行器一次 Next 超过了 fetchSize 会只返回 fetchSize 大小的数据并把剩下的数据留着下次再给客户端,最后对于结果集最后一次返回会标记 ServerStatusLastRowSend 的 flag 通知客户端没有后续数据。COM_STMT_RESET 主要用于客户端主动重置 COM_SEND_LONG_DATA 发来的数据,正常 COM_STMT_EXECUTE 后会自动重置,主要针对客户端希望主动废弃之前数据的情况,因为 COM_STMT_SEND_LONG_DATA 是一直追加的操作,客户端某些场景需要主动放弃之前预存的参数,这部分逻辑主要位于 connClient#handleStmtReset 中。Prepared Plan Cache 通过前面的解析过程我们看到在 Prepare 时完成了 AST 转换,在之后的 Execute 会通过 stmtID 找之前的 AST 来进行 Plan 跳过每次都进行 Parse SQL 的开销。如果开启了 Prepare Plan Cache,可进一步在 Execute 处理中重用上次的 PhysicalPlan 结果,省掉查询优化过程的开销。TiDB 可以通过 修改配置文件 开启 Prepare Plan Cache, 开启后每个新 Session 创建时会初始化一个 SimpleLRUCache 类型的 preparedPlanCache 用于保存用于缓存 Plan 结果,缓存的 key 是 pstmtPlanCacheKey(由当前 DB,连接 ID,statementID,schemaVersion, snapshotTs,sqlMode,timezone 组成,所以要命中 plan cache 这以上元素必须都和上次缓存的一致),并根据配置的缓存大小和内存大小做 LRU。在 Execute 的处理逻辑 PrepareExec 中除了检查 PreparePlanCache 是否开启外,还会判断当前的语句是否能使用 PreparePlanCache。 只有 SELECT,INSERT,UPDATE,DELETE 有可能可以使用 PreparedPlanCache 。 并进一步通过 cacheableChecker visitor 检查 AST 中是否有变量表达式,子查询,”order by ?“,”limit ?,?” 和 UnCacheableFunctions 的函数调用等不可以使用 PlanCache 的情况。 如果检查都通过则在 Execute#getPhysicalPlan 中会用当前环境构建 cache key 查找 preparePlanCache。未命中 Cache 我们首先来看下没有命中 Cache 的情况。发现没有命中后会用 stmtID 找到的 AST 执行 Optimize,但和正常执行 Optimize 不同对于 Cache 的 Plan, 我需要对 “?” 做延迟求值处理, 即将占位符转换为一个 function 做 Plan 并 Cache, 后续从 Cache 获取后 function 在执行时再从具体执行上下文中实际获取执行参数。回顾下构建 LogicPlan 的过程中会通过 expressionRewriter 将 AST 转换为各类 expression.Expression,通常对于 ParamMarkerExpr 会重写为 Constant 类型的 expression,但如果该条 stmt 支持 Cache 的话会重写为 Constant 并带上一个特殊的 DeferredExpr 指向一个 GetParam 的函数表达式,而这个函数会在执行时实际从前面 Execute 保存到 sessionVars.PreparedParams 中获取,这样就做到了 Plan 并 Cache 一个参数无关的 Plan,然后实际执行的时填充参数。新获取 Plan 后会保存到 preparedPlanCache 供后续使用。命中 Cache 让我们回到 getPhysicalPlan,如果 Cache 命中在获取 Plan 后我们需要重新 build plan 的 range,因为前面我们保存的 Plan 是一个带 GetParam 的函数表达式,而再次获取后,当前参数值已经变化,我们需要根据当前 Execute 的参数来重新修正 range,这部分逻辑代码位于 Execute#rebuildRange 中,之后就是正常的执行过程了。文本协议的 Prepared 前面主要介绍了二进制协议的 Prepared 执行流程,还有一种执行方式是通过二进制协议来执行。客户端可以通过 COM_QUREY 发送:PREPARE stmt_name FROM prepareable_stmt; EXECUTE stmt_name USING @var_name1, @var_name2,... DEALLOCTE PREPARE stmt_name 来进行 Prepared,TiDB 会走正常 文本 Query 处理流程,将 SQL 转换 Prepare,Execute,Deallocate 的 Plan, 并最终转换为和二进制协议一样的 PrepareExec,ExecuteExec,DealocateExec 的执行器进行执行。写在最后 Prepared 是提高程序 SQL 执行效率的有效手段之一。熟悉 TiDB 的 Prepared 实现,可以帮助各位读者在将来使用 Prepared 时更加得心应手。另外,如果有兴趣向 TiDB 贡献代码的读者,也可以通过本文更快的理解这部分的实现。"}, {"url": "https://pingcap.com/weekly/2019-01-02-tidb-weekly/", "title": "Weekly update (December 24 ~ December 30, 2018)", "content": " Weekly update in TiDB Last week, we landed 57 PRs in the TiDB repository.Added Add SHOW FULL TABLES to display the View status Provide virtual table facilities Improved Generate the logical property for Group of the Cascades planner Improve the label of the QueryDurationHistogram metric Improve the compatibility with the old MySQL handshake protocol Support building DataS from View Remove the timezone information of records in mysql.tidb Improve selectivity estimation for the correlated column Refine transaction commit slow logs Check the null flag when eliminating the count aggregation Add support for recursive virtual columns Use single delRange and sessionPool in DDL Check the privilege of the ANALYZE TABLE statement Adjust the worker number of Add Index dynamically Fixed Avoid the overlapped range for the prefix index Validate the value for the time_zone global system variable Fix the panic when generating the index join for partitioned tables Avoid goroutine leak for hash aggregation Fix the failure when executing delete...from...join... with binlog enabled Fix the problem of adding partitions concurrently Fix the parser panic caused by hint in the subquery Return null when casting non-binary data to the huge binary type Fix the bug of canceling Drop Column Fix the bug of canceling Drop Table/Database Weekly update in TiSpark Last week, we landed 9 PRs in the TiSpark repository.Added Add set and enum type support Add time type support Add year type support Weekly update in TiKV and PD Last week, we landed 34 PRs in the TiKV and PD repositories.Added Introduce a new storage engine: Titan Introduce the batch system Add left_binary and right_binary built-in functions Add the add to_days built-in function Add the date_diff built-in function Use Observers to collect Region information to a collection Implement the Seek Region on RegionInfoAccessor Improved Perform a full synchronization of a new member New contributors (Thanks!) tikv: Fullstop000 GinYM edwardpku parser: SwanSpouse liutang123 o-oops wangbo docs-cn: httpcheck "}, {"url": "https://pingcap.com/blog-cn/for-community-tidb-2019-level-up/", "title": "写给社区的回顾和展望:TiDB 2019, Level Up!", "content": "2018 年对于 TiDB 和 PingCAP 来说是一个由少年向成年的转换的一年,如果用一个关键字来概括就是「蜕变」。在这一年很欣喜的看到 TiDB 和 TiKV 在越来越多的用户使用在了越来越广泛的场景中,作为一个刚刚 3 岁多的开源项目,没有背后强大的社区的话,是没有办法取得这样的进展的。 同时在技术上,2018 年我觉得也交出了一份令人满意的答卷,TiDB 的几个主要项目今年一共合并了 4380 个提交,这几天在整理 2018 年的 Change Log 时候,对比了一下年初的版本,这 4380 个 Commits 背后代表了什么,这里简单写一个文章总结一下。回想起来,TiDB 是最早定位为 HTAP 的通用分布式数据库之一,如果熟悉我们的老朋友一定知道,我们最早时候一直都是定位 NewSQL,当然现在也是。但是 NewSQL 这个词有个问题,到底 New 在哪,解决了哪些问题,很难一目了然,其实一开始我们就想解决一个 MySQL 分库分表的问题,但是后来慢慢随着我们的用户越来越多,使用的场景也越来越清晰,很多用户的场景已经开始超出了一个「更大的 MySQL 」的使用范围,于是我们从实验室和学术界找到了我们觉得更加清晰的定义:HTAP,希望能构建一个融合 OLTP 和 OLAP 通用型分布式数据库。但是要达成这个目标非常复杂,我们的判断是如果不是从最底层重新设计,很难达到我们的目标,我们认为这是一条更困难但是正确的路,现在看来,这条路是走对了,而且未来会越走越快,越走越稳。在 SQL 层这边,TiDB 选择了 MySQL 的协议兼容,一方面持续的加强语法兼容性,另一方面选择自研优化器和执行器,带来的好处就是没有任何历史负担持续优化。回顾今年最大的一个工作应该是重构了执行器框架,TiDB的 SQL 层还是经典的 Volcano 模型,我们引入了新的内存数据结构 Chunk 来批量处理多行数据,并对各个算子都实现了基于 Chunk 的迭代器接口,这个改进对于 OLAP 请求的改进非常明显,在 TiDB 的 TPC-H 测试集上能看出来(https://github.com/pingcap/docs-cn/blob/master/benchmark/tpch.md),Chunk 的引入为我们全面的向量化执行和 CodeGen 支持打下了基础。目前在 TiKV 内部对于下推算子的执行还没有使用 Chunk 改造,不过这个已经在计划中,在 TiKV 中这个改进,预期对查询性能的提升也将非常显著。另一方面,一个数据库查询引擎最核心的组件之一:优化器,在今年也有长足的进步。我们在 2017 年就已经全面引入了基于代价的 SQL 优化(CBO,Cost-Based Optimization),我们在今年改进了我们的代价评估模型,加入了一些新的优化规则,同时实现了 Join Re-Order 等一系列优化,从结果上来看,目前在 TPC-H 的测试集上,对于所有 Query,TiDB 的 SQL 优化器大多已给出了最优的执行计划。CBO 的另一个关键模块是统计信息收集,在今年,我们引入了自动的统计信息收集算法,使优化器的适应性更强。另外针对 OLTP 的场景 TiDB 仍然保留了轻量的 RBO 甚至直接 Bypass 优化器,以提升 OLTP 性能。另外,感谢三星韩国研究院的几位工程师的贡献,他们给 TiDB 引入了 Query Plan Cache,对高并发场景下查询性能的提升也很明显。另外在功能上,我们引入了 Partition Table 的支持,对于一些 Partition 特性很明显的业务,TiDB 能够更加高效的调度数据的写入读取和更新。一直以来,TiDB 的 SQL 层作为纯 Go 语言实现的最完备的 MySQL 语法兼容层,很多第三方的 MySQL 工具在使用着 TiDB 的 SQL Parser,其中的优秀代表比如小米的 Soar(https://github.com/XiaoMi/soar)。为了方便第三方更好的复用 TiDB Parser,我们在 2018 年将 Parser 从主项目中剥离了出来,成为了一个独立的项目:pingcap/parser,希望能帮到更多的人。说到 TiDB 的底层存储 TiKV 今年也有很多让人眼前一亮的更新。在 TiKV 的基石——一致性算法 Raft 这边,大家知道 TiKV 采用的是 Multi-Raft 的架构,内部通过无数个 Raft Group 动态的分裂、合并、移动以达到动态伸缩和动态负载均衡。我们在今年仍然持续在扩展 Multi-Raft 的边界,我们今年加入了动态的 Raft Group 合并,以减轻元信息存储和心跳通信的负担;给 Raft 扩展了 Learner 角色(只同步 Log 不投票的角色) 为 OLAP Read 打下基础;给 Raft 的基础算法加入了 Pre-Vote 的阶段,让整个系统在异常网络状态下可靠性更高。Raft Group Merge在性能方面,我们花了很大的精力重构了我们单机上多 Raft Group 的线程模型(https://github.com/tikv/tikv/pull/3568), 虽然还没有合并到 master 分支,在我们测试中,这个优化带来了两倍以上的吞吐提升,同时写入延迟降低至现在的版本的 1⁄2 ,预计在这两周我们会完成这个巨大的 PR 的 Code Review,各位同学可以期待一下 :)第三件事情是我们开始将 TiKV 的本地存储引擎的接口彻底抽象出来,目标是能做到对 RocksDB 的弱耦合,这点的意义很大,不管是社区还是我们自己,对新的单机存储引擎支持将变得更加方便。在 TiKV 社区这边,今年的另外一件大事是加入了 CNCF,变成了 CNCF 的托管项目,也是 CNCF 基金会第一个非结构化数据库项目。 后来很多朋友问我,为什么捐赠的是 TiKV 而不是 TiDB,其实主要的原因就像我在当天的一条 Tweet 说的,TiKV 更像是的一个更加通用的组件,当你有一个可以弹性伸缩的,支持跨行 ACID 事务的 Key-Value 数据库时,你会发现构建其他很多可靠的分布式系统会容易很多,这在我们之后的 TiDB Hackathon 中得到了很好的体现。另外社区已经开始出现基于 TiKV 构建的 Redis 协议支持,以及分布式队列系统,例如 meitu/titan 项目。作为一个基金会项目,社区不仅仅可以直接使用,更能够将它作为构建其他系统的基石,我觉得更加有意义。类似的,今年我们将我们的 Raft 实现从主项目中独立了出来(pingcap/raft-rs),也是希望更多的人能从中受益。 “……其 KV与 SQL分层的方式,刚好符合我们提供 NoSQL 存储和关系型存储的需求,另外,PingCAP 的文档齐全,社区活跃,也已经在实际应用场景有大规模的应用,公司在北京,技术交流也非常方便,事实证明,后面提到的这几个优势都是对的……”——美图公司 Titan 项目负责人任勇全对 TiKV 的评论 在 TiDB 的设计之初,我们坚定将调度和元信息从存储层剥离出来(PD),现在看来,好处正渐渐开始显示出来。今年在 PD 上我们花了很大精力在处理热点探测和快速热点调度,调度和存储分离的架构让我们不管是在开发,测试还是上线新的调度策略时效率很高。瞬时热点一直是分布式存储的最大敌人,如何快速发现和处理,我们也有计划尝试将机器学习引入 PD 的调度中,这是 2019 会尝试的一个事情。总体来说,这个是一个长期的课题。我在几个月前的一篇文章提到过 TiDB 为什么从 Day-1 起就 All-in Kubernetes (《十问 TiDB:关于架构设计的一些思考》),今年很欣喜的看到,Kubernetes 及其周边生态已经渐渐成熟,已经开始有很多公司用 Kubernetes 来运行 Mission-critical 的系统,这也佐证了我们当年的判断。2018 年下半年,我们也开源了我们的 TiDB Operator(https://github.com/pingcap/tidb-operator),这个项目并不止是一个简单的在 K8s 上自动化运维 TiDB 的工具,在我们的战略里面,是作为 Cloud TiDB 的重要基座,过去设计一个完善的多租户系统是一件非常困难的事情,同时调度对象是数据库这种带状态服务,更是难上加难,TiDB-Operator 的开源也是希望能够借助社区的力量,一起将它做好。多租户 TiDB今年还做了一件很大的事情,我们成立了一个新的部门 TEP(TiDB Enterprise Platform)专注于商业化组件及相关的交付质量控制。作为一个企业级的分布式数据库,TiDB 今年完成了商业化从0到1的跨越,越来越多的付费客户证明 TiDB 的核心的成熟度已经可以委以重任,成立 TEP 小组也是希望在企业级产品方向上继续发力。从 TiDB-Lightning(MySQL 到 TiDB 高速离线数据导入工具)到 TiDB-DM(TiDB-DataMigration,端到端的数据迁移-同步工具)能看到发力的重点在让用户无缝的从上游迁移到 TiDB 上。另一方面,TiDB-Binlog 虽然不是今年的新东西,但是今年这一年在无数个社区用户的场景中锻炼,越来越稳定。做工具可能在很多人看来并不是那么「高科技」, 很多时候也确实是脏活累活,但是这些经过无数用户场景打磨的周边工具和生态才是一个成熟的基础软件的护城河和竞争壁垒,在 PingCAP 内部,负责工具和外围系统研发的团队规模几乎和内核团队是 1:1 的配比,重要性可见一斑。在使用场景上,TiDB 的使用规模也越来越大,下面这张图是我们统计的我们已知 TiDB 的用户,包括上线和准上线的用户,从 1.0 GA 后,几乎是以一个指数函数的曲线在增长,应用的场景也从简单的 MySQL Sharding 替代方案变成横跨 OLTP 到实时数据中台的通用数据平台组件。TiDB 的用户数统计今年几个比较典型的 用户案例,从 美团 的横跨 OLTP 和实时数仓的深度实践,到 转转 的 All-in TiDB 的体验,再到 TiDB 支撑的北京银行的核心交易系统。可以看到,这些案例从互联网公司的离线线数据存储到要求极端 SLA 的传统银行核心交易系统,TiDB 在这些场景里面都发光发热,甚至有互联网公司(转转)都喊出了 All-in TiDB 的口号,我们非常珍视这份信任,一定尽全力做出漂亮的产品,高质量的服务好我们的用户和客户。另一方面,TiDB 也慢慢开始产生国际影响力的,在线视频巨头葫芦软件(Hulu.com),印度最大的在线票务网站 BookMyShow,东南亚最大的电商之一 Shopee 等等都在大规模的使用 TiDB,在北美和欧洲也已经不少准上线和测试中的的巨头互联网公司。简单回顾了一下过去的 2018 年,我们看看未来在哪里。其实从我们在 2018 年做的几个比较大的技术决策就能看到,2019 年将是上面几个方向的延续。大的方向的几个指导思想是: Predicable. (靠谱,在更广泛的场景中,做到行为可预测。) Make it right before making it fast.(稳定,先做稳,再做快。) Ease of use. (好用,简单交给用户,复杂留给自己。) 对于真正的 HTAP 场景来说,最大的挑战的是如何很好的做不同类型的 workload 隔离和数据结构根据访问特性自适应。我们在这个问题上给出了自己的答案:通过拓展 Raft 的算法,将不同的副本存储成异构的数据结构以适应不同类型的查询。这个方法有以下好处: 本身在 Multi-Raft 的层面上修改,不会出现由数据传输组件造成的瓶颈(类似 Kafka 或者 DTS),因为 Multi-Raft 本身就是可扩展的,数据同步的单位从 binlog,变成 Raft log,这个效率会更高,进一步降低了同步的延迟。 更好的资源隔离,通过 PD 的调度,可以真正将不同的副本调度到隔离的物理机器上,真正做到互不影响。 TiDB 2019 年会变成这个样子Learner 在 HTAP 中的应用在执行器方面,我们会继续推进向量化,不出意外的话,今年会完成所有算子的全路径的向量化执行。这个 HTAP 方案的另一个关键是存储引擎本身。2019 年,我们会引入新的存储引擎,当然第一阶段仍然会继续在 RocksDB 上改进,改进的目标仍然是减小 LSM-Tree 本身的写放大问题。选用的模型是 WiscKey(FAST16),WiscKey 的核心思想是将 Value 从 LSM-Tree 中剥离出来,以减少写放大,如果关注 TiKV 的朋友,已经能注意到我们已经在前几天将一个新存储引擎 Titan(PingCAP 的 Titan,很遗憾和美图那个项目重名了)合并到了 TiKV 的主干分支,这个 Titan 是我们在 RocksDB 上的 WiscKey 模型的一个实现,除了 WiscKey 的核心本身,我们还加入了对小 KV 的 inline 等优化,Titan 在我们的内部测试中效果很好,对长度随机的 key-value 写入的吞吐基本能达到原生 RocksDB 的 2 - 3 倍,当然性能提升并不是我最关注的,这个引擎对于 TiDB 最大的意义就是,这个引擎将让 TiDB 适应性更强,做到更加稳定,更加「可预测」。TiKV 新的本地存储引擎 Titan在 Titan 走向稳定的同时,我们也在调研从头构建一个更适合 TiDB 的 OLTP workload 的存储引擎,前面说到 2018 年做了抽象 TiKV 的本地存储引擎的事情就是为了这个打基础,当然我们仍然会走 LSM-Tree 的路线。这里多提一句,其实很多人都误解了 LSM-Tree 模型的真正优势,在我看来并不是性能,而是:做到可接受的性能的同时,LSM-Tree 的实现非常简单可维护,只有简单的东西才可以依赖,这个决定和我们在 Raft 与 Paxos 之间的选择偏好也是一致的。另外 LSM-Tree 的设计从宏观上来说,更加符合「冷热分层」以适配异构存储介质的想法,这个我相信是未来在存储硬件上的大趋势。至于在 OLAP 的存储引擎这边,我们走的就是纯列式存储的路线了,但是会和传统的 Columnar 数据结构的设计不太一样,这块的进展,我们会在 1 月 19 号的 TiDB DevCon 上首秀,这里先卖个关子。另一个大的方向是事务模型,目前来说,TiDB 从诞生起,事务模型就没有改变过,走的是传统的 Percolator 的 2PC。这个模型的好处是简单,吞吐也不是瓶颈,但是一个比较大的问题是延迟,尤其在跨数据中心的场景中,这里的延迟主要表现在往 TSO 拿时间戳的网络 roundtrip 上,当然了,我目前仍然认为时钟(TSO)是一个必不可少组件,在不降低一致性和隔离级别的大前提下也是目前我们的最好选择,另外 Percolator 的模型也不是没有办法对延迟进行优化,我们其实在 2018 年,针对 Percolator 本身做了一些理论上的改进,减少了几次网络的 roundtrip,也在年中书写了新的 2PC 改进的 完整的 TLA+ 的证明),证明了这个新算法的正确性,2019 年在这块还会有比较多的改进,其实我们一直在思考,怎么样能够做得更好,选择合适的时机做合适的优化。另外一方面,在事务模型这方面,2PC 在理论和工程上还有很多可以改进的空间,但是现在的当务之急继续的优化代码结构和整体的稳定性,这部分的工作在未来一段时间还是会专注在理论和证明上。另外一点大家可以期待的是,2019 年我们会引入安全的 Follower/Learner Read,这对保持一致性的前提下读的吞吐会提升,另外在跨数据中心的场景,读的延迟会更小。差不多就这些吧,最后放一句我特别喜欢的丘吉尔的一句名言作为结尾。Success is not final, failure is not fatal: it is the courage to continue that counts.成功不是终点,失败也并非终结,最重要的是继续前进的勇气。"}, {"url": "https://pingcap.com/blog-cn/tidb-hackathon-2018-06/", "title": "TBSSQL 的那些事 | TiDB Hackathon 2018", "content": " 本文作者是来自 TiBoys 队的崔秋同学,他们的项目 TBSSQL 在 TiDB Hackathon 2018 中获得了一等奖。TiDB Batch and Streaming SQL(简称 TBSSQL)扩展了 TiDB 的 SQL 引擎,支持用户以类似 StreamSQL 的语法将 Kafka、Pulsar 等外部数据源以流式表的方式接入 TiDB。通过简单的 SQL 语句,用户可以实现对流式数据的过滤,流式表与普通表的 Join(比如流式事实表与多个普通维度表),甚至通过 CREATE TABLE AS SELECT 语法将处理过的流式数据写入普通表中。此外,针对流式数据的时间属性,我们实现了基于时间窗口的聚合/排序算子,使得我们可以对流式数据进行时间维度的聚合/排序。 序 算起来这应该是第三次参加的 Hackathon 了,第一次参加的时候还是在小西天的豌豆荚,和东旭一起,做跨平台数据传输的工具,两天一夜;第二次和奇叔一起在 3W 咖啡,又是两天一夜;这次在自己家举办 Hackathon 比赛,下定决心一定要佛性一些,本着能抱大腿就不单干的心态,迅速决定拉唐长老(唐刘)下水。接下来就计划着折腾点啥,因为我们两个前端都不怎么样,所以只能硬核一些,于是拍了两个方案。方案一:之前跟唐长老合作过很长一段时间,我们两个对于测试质量之类的事情也都非常关注,所以想着能不能在 Chaos 系统上做一些文章,把一些前沿的测试理论和经验方法结合到系统里面来,做一套通用的分布式系统测试框架,就像 Jepsen 那样,用这套系统去测试和验证主流的开源分布式项目。方案二:越接近于业务实时性的数据处理越有价值,不管是 Kafka/KSQL,Flink/Spark Streaming 都是在向着实时流计算领域方向进行未来的探索。TiDB 虽然已经能够支持类 Real Time OLAP 的场景,但是对于更实时的流式数据处理方面还没有合适的解决方案,不过 TiDB 具有非常好的 Scale 能力,天然的能存储海量的数据库表数据,所以在 Streaming Event 和 Table 关联的场景下具有非常明显的优势。如果在 TiDB 上能够实现一个 Streaming SQL 的引擎,实现 Batch/Streaming 的计算融合,那将会是一件非常有意思的事情。因为打 Hackathon 比赛主要是希望折腾一些新的东西,所以我们两个简单讨论完了之后还是倾向于方案二,当然做不做的出来另说。当我们正准备做前期调研和设计的时候,Hackathon 主办方把唐长老拉去做现场导师,参赛规则规定导师不能下场比赛,囧,于是就这样被被动放了鸽子。好在后来遇到了同样被霸哥(韩飞)当导师而放鸽子的川总(杜川),川总对于 Streaming SQL 非常感兴趣,于是难兄难弟一拍即合,迅速决定抱团取暖。随后,Robot 又介绍了同样还没有组队的社区小伙伴 GZY(高志远),这样算是凑齐了三个人,但是一想到没有前端肯定搞不定,于是就拜托娘家人(Dashbase)的交际小王子 WPH(王鹏翰)出马,帮助去召唤一个靠谱的前端小伙伴,后来交际未果直接把自己卖进了队伍,这样终于凑齐了四后端,不,应该是三后端 + 一伪前端的组合。因为马上要准备提交项目和团队名称,大家都一致觉得方案二非常有意思,所以就选定了更加儒雅的 TBSSQL(TiDB Batch and Streaming SQL)作为项目名称,TSBSQL 遗憾落选。在团队名称方面,打酱油老男孩 / Scboy / TiStream / 养生 Hackathon / 佛系 Hackathon 都因为不够符合气质被遗憾淘汰,最后代表更有青春气息的 TiBoys 入选(跟着我左手右手一个慢动作,逃……前期准备 所谓 “三军未动, 粮草先行”,既然已经报名了,还是要稍作准备,虽然已经确定了大的方向,但是具体的落地方案还没有细化,而且人员的分工也不是太明确。又经过一轮简单的讨论之后,明确了大家的职责方向,我这边主要负责项目整体设计,进度管理以及和 TiDB 核心相关的代码,川总主要负责 TiDB 核心技术攻关,GZY 负责流数据源数据的采集部分,WPH 负责前端展现以及 Hackathon 当天的 Demo 演示,分工之后大家就开始分头调研动工。作为这两年来基本没怎么写过代码的退役型选手来说,心里还是非常没底的,也不知道现在 TiDB 代码结构和细节变成什么样了,不求有功,但求别太拖后腿。对于项目本身的典型应用场景,大家还是比较明确的,觉得这个方向是非常有意义的。 应用层系统:实时流事件和离线数据的关联查询,比如在线广告推荐系统,在线推荐系统,在线搜索,以及实时反欺诈系统等。 内部数据系统: 实时数据采样统计,比如内部监控系统; 时间窗口数据分析系统,比如实时的数据流数据分析(分析一段时间内异常的数据流量和系统指标),用于辅助做 AI Ops 相关的事情(比如根据数据流量做节点自动扩容/自动提供参数调优/异常流量和风险报告等等)。 业界 Streaming 相关的系统很多,前期我这边快速地看了下能不能站在巨人的肩膀上做事情,有没有可借鉴或者可借用的开源项目。 Apache Beam本质上 Apache Beam 还是一个批处理和流处理融合的 SDK Model,用户可以在应用层使用更简单通用的函数接口实现业务的处理,如果使用 Beam 的话,还需要实现自定义的 Runner,因为 TiDB 本身主要的架构设计非常偏重于数据库方向,内部并没有特别明确的通用型计算引擎,所以现阶段基本上没有太大的可行性。当然也可以选择用 Flink 作为 Runner 连接 TiDB 数据源,但是这就变成了 Flink&TiDB 的事情了,和 Beam 本身关系其实就不大了。 Apache Flink / Spark StreamingFlink 是一个典型的流处理系统,批处理可以用流处理来模拟出来。本身 Flink 也是支持 SQL 的,但是是一种嵌入式 SQL,也就是 SQL 和应用程序代码写在一起,这种做法的好处是可以直接和应用层进行整合,但是不好的地方在于,接口不是太清晰,有业务侵入性。阿里内部有一个增强版的 Flink 项目叫 Blink,在这个领域比较活跃。如果要实现批处理和流处理融合的话,需要内部定制和修改 Flink 的代码,把 TiDB 作为数据源对接起来,还有可能需要把一些环境信息提交给 TiDB 以便得到更好的查询结果,当然或许像 TiSpark 那样,直接 Flink 对接 TiKV 的数据源应该也是可以的。因为本身团队对于 Scala/Java 代码不是很熟悉,而且 Flink 的模式会有一定的侵入性,所以就没有在这方面进行更多的探索。同理,没有选择 Spark Streaming 也是类似的原因。当然有兴趣的小伙伴可以尝试下这个方向,也是非常有意思的。 Kafka SQL因为 Kafka 本身只是一个 MQ,以后会向着流处理方向演进,但是目前并没有实现批处理和流处理统一的潜力,所以更多的我们只是借鉴 Kafka SQL 的语法。目前 Streaming SQL 还没有一个统一的标准 SQL,Kafka SQL 也只是一个 SQL 方言,支持的语法还比较简单,但是非常实用,而且是偏交互式的,没有业务侵入性。非常适合在 Hackathon 上做 Demo 演示,我们在项目实现中也是主要参考了 Kafka SQL 的定义,当然,Flink 和 Calcite 也有自己定义的 Streaming 语法,这里就不再讨论了。 调研准备工作讨论到这里基本上也就差不多了,于是我们开始各自备(hua)战(shui),出差的出差,加班的加班,接客户的接客户,学 Golang 的学 Golang,在这种紧(fang)张(fei)无(zi)比(wo)的节奏中,迎来了 Hackathon 比赛的到来。Hackathon 流水账 具体的技术实现方面都是比较硬核的东西,细节也比较多,扔在最后面写,免的大家看到一半就点×了。至于参加 Hackathon 的感受,因为不像龙哥那么文豪,也不像马老师那么俏皮,而且本来读书也不多,所以也只能喊一句“黑客马拉松真是太好玩了”! Day 1 3:30 AM 由于飞机晚点,川总这个点儿才辗转到酒店。睡觉之前非常担心一觉睡过头,让这趟 Hackathon 之旅还没开始就结束了,没想到躺下以后满脑子都是技术细节,怎么都睡不着。漫漫长夜,无眠。7:45 AM 川总早早来到 Hackathon 现场。由于来太早,其他选手都还没到,所以他提前刺探刺探敌情的计划也泡汤了,只好在赛场瞎晃悠一番熟悉熟悉环境,顺道跟大奖合了个影。11:00 AM 简单的开幕式之后,Hackathon 正式开始。我们首先搞定的是 Streaming SQL 的语法定义以及 Parser 相关改动。这一部分在之前就经过比较详细的在线讨论了,所以现场只需要根据碰头后统一的想法一顿敲敲敲就搞定了。快速搞定这一块以后,我们就有了 SQL 语法层面的 Streaming 实现。当然此时 Streaming 也仅限于语法层面,Streaming 在 SQL 引擎层面对应的其实还是普通的TiDB Table。接下来是 DDL 部分。这一块我们已经想好了要复用 TiDB Table 的 Meta 结构 TableInfo ,因此主要工作就是按照 DDL源码解析 依葫芦画瓢,难度也不大,以至于我们还有闲心纠结一下 SHOW TABLES 语法里到底要不要屏蔽掉 Streaming Table 的问题。整体上来看上午的热身活动还是进行的比较顺利的,起码 Streaming DDL 这块没有成为太大的问题。这里面有个插曲就是我在 Hackathon 之前下载编译 TiDB,结果发现 TiDB 的 parser 已经用上时髦的 go module 了(也是好久好久没看 TiDB 代码),折腾好半天,不过好处就是 Hackathon 当天的时候改起来 parser 就比较轻车熟路了,所以赛前编译一个 TiDB 还是非常有必要的。15:30 PM 随着热身的结束,马上迎来了稳定的敲敲敲阶段。川总简单弄了一个 Mock 的 StreamReader 然后丢给了我,因为我之前写 TiDB 的时候,时代比较遥远,那时候都还在用周 sir 的 Datum,现在一看,为了提高内存效率和性能,已经换成了高大上的 Chunk,于是一个很常见的问题:如何用最正确的做法把一个传过来的 Json 数据格式化成 Table Row 数据放到 Chunk 里面,让彻底我懵逼了。这里面倒不是技术的问题,主要是类型太多,如果枚举所有类型,搞起来很麻烦,按道理应该有更轻快的办法,但是翻了源代码还是没找到解决方案。这个时候果断去求助现场导师,也顺便去赛场溜(ci)达(tan)一(di)圈(qing)。随便扫了一眼,惊呆了,龙哥他们竟然已经开始写 PPT 了,之前知道龙哥他们强,但是没想到强到这个地步,还让不让大家一块欢快地玩耍了。同时,也了解到了不少非常有意思的项目,比如用机器学习方法去自动调节 TiDB 的调度参数,用 Lua 给 TiKV 添加 UDF 之类的,在 TiDB 上面实现异构数据库的关联查询(简直就是 F1 的大一统,而且听小道消息,他们都已经把 Join 推到 PG 上面去了,然而我们还没开始进入到核心开发流程),在 TiKV 上面实现时序数据库和 Memcached 协议等等,甚至东旭都按捺不住自己 Hackathon 起来了(嘻嘻,可以学学我啊 ;D )。本来还想去聊聊各个项目的具体实现方案,但是一想到自己挖了一堆坑还没填,只能默默回去膜拜 TiNiuB 项目。看起来不能太佛系了,于是乎我赶紧召开了一次内部团队 sync 的 catch up,明确下分工,川总开始死磕 TBSSQL 的核心逻辑 Streaming Aggregation 的实现,我这边继续搞不带 Aggregation 的 Streaming SQL 的其他实现,GZY 已经部署起来了 Pulsar,开始准备 Mock 数据,WPH 辅助 GZY 同时也快速理解我们的 Demo 场景,着手设计实现前端展现。18:00 PM 我这边和面带慈父般欣慰笑容的老师(张建)进行了一些技术方案实现上的交流后,了解到目前社区小伙伴已经在搞 CREATE TABLE AS SELECT 的重要信息(后续证明此信息值大概一千块 RMB)。此时,在解决了之前的问题之后,TBSSQL 终于能跑通简单的 SELECT 语句了。我们心里稍微有点底了,于是一鼓作气,顺路也实现了带 Where 条件的 Stream Table 的 SELECT,以及 Stream Table 和 TiDB Table 的多表 Join,到这里,此时,按照分工,我这边的主体工作除了 Streaming Position 的持久化支持以外,已经写的差不多了,剩下就是去实现一些 Nice to have 的 DDL 的语法支持。川总这里首先要搞的是基于时间窗口的 Streaming Aggregation。按照我们的如意算盘,这里基本上可以复用 TiDB 现有的 Hash Aggregation 的计算逻辑,只需要加上窗口的处理就完事儿了。不过实际下手的时候仔细一研究代码,发现 Aggregation 这一块代码在川总疏于研究这一段时间已经被重构了一把,加上了一个并发执行的分支,看起来还挺复杂。于是一不做二不休,川总把 Hash Aggregation 的代码拷了一份,删除了并发执行的逻辑,在比较简单的非并发分支加上窗口相关实现。不过这种方法意味着带时间窗口的 Aggregation 得单独出 Plan,Planner 上又得改一大圈。这一块弄完以后,还没来得及调试,就到吃晚饭的点儿了。21:00 PM 吃完晚饭,因为下午死磕的比较厉害,我和张建、川总出门去园区溜达了一圈。期间张建问我们搞得咋样了,我望了一眼川总,语重心长地说主要成败已经不在我了(后续证明这句语重心长至少也得值一千块 RMB),川总果断信心满满地说问题不大,一切尽在掌握之中。没想到这个 Flag 刚立起来还是温的,就立马被打脸了。问题出在吃饭前搞的聚合那块(具体细节可以看下后面的坑系列),为了支持时间窗口,我们必须确保 Streaming 上的窗口列能透传到聚合算子当中,为此我们屏蔽了优化器中窗口聚合上的列裁剪规则。可是实际运行当中,我们的修改并没有生效???而此时,川总昨天一整晚没睡觉的副作用开始显现出来了,思路已经有点不太清醒了。于是我们把张建拖过来一起 debug。然后我这边也把用 TiDB Global Variable 控制 Streaming Position 的功能实现了,并且和 GZY 这边也实现了 Mock 数据。之后,我也顺路休息休息,毕竟川总这边搞不定,我们这边搞的再好也没啥用。除了观摩川总和张建手把手,不,肩并肩结对小黑屋编程之外,我也顺便申请了部署 Kafka 联调的机器。23:00 PM 我们这边最核心的功能还没突破,亮眼的 CREATE TABLE AS SELECT Streaming 也还没影,其实中期进度还是偏慢了(或者说之前我设计实现的功能的工作量太大了,看起来今天晚上只能死磕了,囧)。我调试 Kafka 死活调不通,端口可以 Telnet 登陆,但是写入和获取数据的时候一直报超时错误,而且我这边已经开始困上来了,有点扛不动了,后来在 Kafka 老司机 WPH 一起看了下配置参数,才发现 Advertise URL 设置成了本地地址,换成对外的 IP 就好了,当然为了简单方便,我们设置了单 Partition 的 Topic,这样 collector 的 Kafka 部分就搞的差不多了,剩下就是实现一个 http 的 restful api 来提供给 TiDB 的 StreamReader 读取,整个连通工作就差不多了。Day 2 00:00 AM 这时候川总那边也传来了好消息,终于从 Streaming Aggregation 这个大坑里面爬出来了,后面也比较顺利地搞定了时间窗口上的聚合这块。此时时间已经到了 Hackathon 的第二天,不少其他项目的小伙伴已经收摊回家了。不过我们抱着能多做一个 Feature 是一个的心态,决定挑灯夜战。首先,川总把 Sort Executor 改了一把以支持时间窗口,可能刚刚的踩坑经历为我们攒了人品,Sort 上的改动竟然一次 AC 了。借着这股劲儿,我们又回头优化了一把 SHOW CREATE STREAM 的输出。这里有个插曲就是为了近距离再回味和感受下之前的开发流程,我们特意在 TiDB 的 repo 里面开了一个 tiboys/hackathon 的分支,然后提交的时候用了标准的 Pull Request 的方式,点赞了才能 merge(后来想想打 Hackathon 不是太可取,没什么用,还挺耽误时间,不知道当时怎么想的),所以在 master 分支和 tiboys/hackathon 分支看的时候都没有任何提交记录。嘻嘻,估计龙哥也没仔细看我们的 repo,所以其实在龙哥的激励下,我们的效率还是可以的 :) 。2:30 AM GZY 和 WPH 把今天安排的工作完成的差不多了,而且第二天还靠他们主要准备 Demo Show,就去睡觉了,川总也已经困得不行了,准备打烊睡觉。我和川总合计了一下,还差一个最重要的 Feature,抱着就试一把,不行就手工的心态,我们把社区的小伙伴王聪(bb7133)提的支持 CREATE TABLE AS SELECT 语法的 PR 合到了我们的分支,冲突竟然不是太多,然后稍微改了一下来支持 Streaming,结果一运行奇迹般地发现竟然能够运行,RP 全面爆发了,于是我们就近乎免费地增加了一个 Feature。改完这个地方,川总实在坚持不住了,就回去睡了。我这边的 http restful api 也搞的差不多了,准备联调一把,StreamReader 通过 http client 从 collector 读数据,collector 通过 kafka consumer 从 kafka broker 获取数据,结果获取的 Json 数据序列化成 TiDB 自定义的 Time 类型老是出问题,于是我又花了一些时间给 Time 增加了 Marshall 和 Unmarshal 的格式化支持,到这里基本上可以 work 了,看了看时间,凌晨四点半,我也准备去睡了。期间好几次看到霸哥(韩飞)凌晨还在一直帮小(tian)伙(zi)伴(ji)查(wa)问(de)题(keng),其实霸哥认真的时候还是非常靠谱的。7:30 AM 这个时候人陆陆续续地来了,我这边也进入了打酱油的角色,年纪大了确实刚不动了,吃了早餐之后,开始准备思考接下来的分工。因为大家都是临时组队,到了 Hackathon 才碰面,基本上没有太多磨合,而且普遍第二天状态都不大好。虽然大家都很努力,但是在我之前设计的宏大项目面前,还是感觉人力不太够,所以早上 10 …"}, {"url": "https://pingcap.com/blog-cn/tidb-ecosystem-tools-3/", "title": "TiDB Ecosystem Tools 原理解读系列(三)TiDB-DM 架构设计与实现原理", "content": " 简介 TiDB-DM(Data Migration)是用于将数据从 MySQL/MariaDB 迁移到 TiDB 的工具。该工具既支持以全量备份文件的方式将 MySQL/MariaDB 的数据导入到 TiDB,也支持通过解析执行 MySQL/MariaDB binlog 的方式将数据增量同步到 TiDB。特别地,对于有多个 MySQL/MariaDB 实例的分库分表需要合并后同步到同一个 TiDB 集群的场景,DM 提供了良好的支持。如果你需要从 MySQL/MariaDB 迁移到 TiDB,或者需要将 TiDB 作为 MySQL/MariaDB 的从库,DM 将是一个非常好的选择。架构设计 DM 是集群模式的,其主要由 DM-master、DM-worker 与 DM-ctl 三个组件组成,能够以多对多的方式将多个上游 MySQL 实例的数据同步到多个下游 TiDB 集群,其架构图如下: DM-master:管理整个 DM 集群,维护集群的拓扑信息,监控各个 DM-worker 实例的运行状态;进行数据同步任务的拆解与分发,监控数据同步任务的执行状态;在进行合库合表的增量数据同步时,协调各 DM-worker 上 DDL 的执行或跳过;提供数据同步任务管理的统一入口。 DM-worker:与上游 MySQL 实例一一对应,执行具体的全量、增量数据同步任务;将上游 MySQL 的 binlog 拉取到本地并持久化保存;根据定义的数据同步任务,将上游 MySQL 数据全量导出成 SQL 文件后导入到下游 TiDB,或解析本地持久化的 binlog 后增量同步到下游 TiDB;编排 DM-master 拆解后的数据同步子任务,监控子任务的运行状态。 DM-ctl:命令行交互工具,通过连接到 DM-master 后,执行 DM 集群的管理与数据同步任务的管理。 实现原理 数据迁移流程 单个 DM 集群可以同时运行多个数据同步任务;对于每一个同步任务,可以拆解为多个子任务同时由多个 DM-worker 节点承担,其中每个 DM-worker 节点负责同步来自对应的上游 MySQL 实例的数据。对于单个 DM-worker 节点上的单个数据同步子任务,其数据迁移流程如下,其中上部的数据流向为全量数据迁移、下部的数据流向为增量数据同步:在每个 DM-worker 节点内部,对于特定的数据同步子任务,主要由 dumper、loader、relay 与 syncer(binlog replication)等数据同步处理单元执行具体的数据同步操作。 对于全量数据迁移,DM 首先使用 dumper 单元从上游 MySQL 中将表结构与数据导出成 SQL 文件;然后使用 loader 单元读取这些 SQL 文件并同步到下游 TiDB。 对于增量数据同步,首先使用 relay 单元作为 slave 连接到上游 MySQL 并拉取 binlog 数据后作为 relay log 持久化存储在本地,然后使用 syncer 单元读取这些 relay log 并解析构造成 SQL 语句后同步到下游 TiDB。这个增量同步的过程与 MySQL 的主从复制类似,主要区别在于在 DM 中,本地持久化的 relay log 可以同时供多个不同子任务的 syncer 单元所共用,避免了多个任务需要重复从上游 MySQL 拉取 binlog 的问题。 数据迁移并发模型 为加快数据导入速度,在 DM 中不论是全量数据迁移,还是增量数据同步,都在其中部分阶段使用了并发处理。对于全量数据迁移,在导出阶段,dumper 单元调用 mydumper 导出工具执行实际的数据导出操作,对应的并发模型可以直接参考 mydumper 的源码。在使用 loader 单元执行的导入阶段,对应的并发模型结构如下:使用 mydumper 执行导出时,可以通过 --chunk-filesize 等参数将单个表拆分成多个 SQL 文件,这些 SQL 文件对应的都是上游 MySQL 某一个时刻的静态快照数据,且各 SQL 文件间的数据不存在关联。因此,在使用 loader 单元执行导入时,可以直接在一个 loader 单元内启动多个 worker 工作协程,由各 worker 协程并发、独立地每次读取一个待导入的 SQL 文件进行导入。即 loader 导入阶段,是以 SQL 文件级别粒度并发进行的。在 DM 的任务配置中,对于 loader 单元,其中的 pool-size 参数即用于控制此处 worker 协程数量。对于增量数据同步,在从上游拉取 binlog 并持久化到本地的阶段,由于上游 MySQL 上 binlog 的产生与发送是以 stream 形式进行的,因此这部分只能串行处理。在使用 syncer 单元执行的导入阶段,在一定的限制条件下,可以执行并发导入,对应的模型结构如下:当 syncer 读取与解析本地 relay log 时,与从上游拉取 binlog 类似,是以 stream 形式进行的,因此也只能串行处理。当 syncer 解析出各 binlog event 并构造成待同步的 job 后,则可以根据对应行数据的主键、索引等信息经过 hash 计算后分发到多个不同的待同步 job channel 中;在 channel 的另一端,与各个 channel 对应的 worker 协程并发地从 channel 中取出 job 后同步到下游的 TiDB。即 syncer 导入阶段,是以 binlog event 级别粒度并发进行的。在 DM 的任务配置中,对于 syncer 单元,其中的 worker-count 参数即用于控制此处 worker 协程数量。但 syncer 并发同步到下游 TiDB 时,存在一些限制,主要包括: 对于 DDL,由于会变更下游的表结构,因此必须确保在旧表结构对应的 DML 都同步完成后,才能进行同步。在 DM 中,当解析 binlog event 得到 DDL 后,会向每一个 job channel 发送一个特殊的 flush job;当各 worker 协程遇到 flush job 时,会立刻向下游 TiDB 同步之前已经取出的所有 job;等各 job channel 中的 job 都同步到下游 TiDB 后,开始同步 DDL;等待 DDL 同步完成后,继续同步后续的 DML。即 DDL 不能与 DML 并发同步,且 DDL 之前与之后的 DML 也不能并发同步。sharding 场景下 DDL 的同步处理见后文。 对于 DML,多条 DML 可能会修改同一行的数据,甚至是主键。如果并发地同步这些 DML,则可能造成同步后数据的不一致。DM 中对于 DML 之间的冲突检测与处理,与 TiDB-Binlog 中的处理类似,具体原理可以阅读《TiDB EcoSystem Tools 原理解读(一)TiDB-Binlog 架构演进与实现原理》中关于 Drainer 内 SQL 之间冲突检测的讨论。 合库合表数据同步 在使用 MySQL 支撑大量数据时,经常会选择使用分库分表的方案。但当将数据同步到 TiDB 后,通常希望逻辑上进行合库合表。DM 为支持合库合表的数据同步,主要实现了以下的一些功能。table router 为说明 DM 中 table router(表名路由)功能,先看如下图所示的一个例子:在这个例子中,上游有 2 个 MySQL 实例,每个实例有 2 个逻辑库,每个库有 2 个表,总共 8 个表。当同步到下游 TiDB 后,希望所有的这 8 个表最终都合并同步到同一个表中。但为了能将 8 个来自不同实例、不同库且有不同名的表同步到同一个表中,首先要处理的,就是要能根据某些定义好的规则,将来自不同表的数据都路由到下游的同一个表中。在 DM 中,这类规则叫做 router-rules。对于上面的示例,其规则如下:name-of-router-rule: schema-pattern: "schema_*" table-pattern: "table_*" target-schema: "schema" target-table: "table" name-of-router-rule:规则名,用户指定。当有多个上游实例需要使用相同的规则时,可以只定义一条规则,多个不同的实例通过规则名进行引用。 schema-pattern:用于匹配上游库(schema)名的模式,支持在尾部使用通配符(*)。这里使用 schema_* 即可匹配到示例中的两个库名。 table-pattern:用于匹配上游表名的模式,与 schema-pattern 类似。这里使用 table_* 即可匹配到示例中的两个表名。 target-schema:目标库名。对于库名、表名匹配的数据,将被路由到这个库中。 target-table:目标表名。对于库名、表名匹配的数据,将被路由到 target-schema 库下的这个表中。 在 DM 内部实现上,首先根据 schema-pattern / table-pattern 构造对应的 trie 结构,并将规则存储在 trie 节点中;当有 SQL 需要同步到下游时,通过使用上游库名、表名查询 trie 即可得到对应的规则,并根据规则替换原 SQL 中的库名、表名;通过向下游 TiDB 执行替换后的 SQL 即完成了根据表名的路由同步。有关 router-rules 规则的具体实现,可以阅读 TiDB-Tools 下的 table-router pkg 源代码。column mapping 有了 table router 功能,已经可以完成基本的合库合表数据同步了。但在数据库中,我们经常会使用自增类型的列作为主键。如果多个上游分表的主键各自独立地自增,将它们合并同步到下游后,就很可能会出现主键冲突,造成数据的不一致。我们可看一个如下的例子:在这个例子中,上游 4 个需要合并同步到下游的表中,都存在 id 列值为 1 的记录。假设这个 id 列是表的主键。在同步到下游的过程中,由于相关更新操作是以 id 列作为条件来确定需要更新的记录,因此会造成后同步的数据覆盖前面已经同步过的数据,导致部分数据的丢失。在 DM 中,我们通过 column mapping 功能在数据同步的过程中依据指定规则对相关列的数据进行转换改写来避免数据冲突与丢失。对于上面的示例,其中 MySQL 实例 1 的 column mapping 规则如下:mapping-rule-of-instance-1: schema-pattern: "schema_*" table-pattern: "table_*" expression: "partition id" source-column: "id" target-column: "id" arguments: ["1", "schema_", "table_"] mapping-rule-of-instance-1:规则名,用户指定。由于不同的上游 MySQL 实例需要转换得到不同的值,因此通常每个 MySQL 实例使用一条专有的规则。 schema-pattern / table-pattern:上游库名、表名匹配模式,与 router-rules 中的对应配置项一致。 expression:进行数据转换的表达式名。目前常用的表达式即为 "partition id",有关该表达式的具体说明见下文。 source-column:转换表达式的输入数据对应的来源列名,"id" 表示这个表达式将作用于表中名为 id 的列。暂时只支持对单个来源列进行数据转换。 target-column:转换表达式的输出数据对应的目标列名,与 source-column 类似。暂时只支持对单个目标列进行数据转换,且对应的目标列必须已经存在。 arguments:转换表达式所依赖的参数。参数个数与含义依具体表达式而定。 partition id 是目前主要受支持的转换表达式,其通过为 bigint 类型的值增加二进制前缀来解决来自不同表的数据合并同步后可能产生冲突的问题。partition id 的 arguments 包括 3 个参数,分别为: MySQL 实例 ID:标识数据的来源 MySQL 实例,用户自由指定。如 "1" 表示匹配该规则的数据来自于 MySQL 实例 1,且这个标识将被转换成数值后以二进制的形式作为前缀的一部分添加到转换后的值中。 库名前缀:标识数据的来源逻辑库。如 "schema_" 应用于 schema_2 逻辑库时,表示去除前缀后剩下的部分(数字 2)将以二进制的形式作为前缀的一部分添加到转换后的值中。 表名前缀:标识数据的来源表。如 "table_" 应用于 table_3 表时,表示去除前缀后剩下的部分(数字 3)将以二进制的形式作为前缀的一部分添加到转换后的值中。 各部分在经过转换后的数值中的二进制分布如下图所示(各部分默认所占用的 bits 位数如图所示):假如转换前的原始数据为 123,且有如上的 arguments 参数设置,则转换后的值为:1<<(64-1-4) | 2<<(64-1-4-7) | 3<<(64-1-4-7-8) | 123 另外,arguments 中的 3 个参数均可设置为空字符串(""),即表示该部分不被添加到转换后的值中,且不占用额外的 bits。比如将其设置为["1", "", "table_"],则转换后的值为:1 << (64-1-4) | 3<< (64-1-4-8) | 123 有关 column mapping 功能的具体实现,可以阅读 TiDB-Tools 下的 column-mapping pkg 源代码。sharding DDL 有了 table router 和 column mapping 功能,DML 的合库合表数据同步已经可以正常进行了。但如果在增量数据同步的过程中,上游待合并的分表上执行了 DDL 操作,则可能出现问题。我们先来看一个简化后的在分表上执行 DDL 的例子。在上图的例子中,分表的合库合表简化成了上游只有两个 MySQL 实例,每个实例内只有一个表。假设在开始数据同步时,将两个分表的表结构 schema 的版本记为 schema V1,将 DDL 执行完成后的表结构 schema 的版本记为 schema V2。现在,假设数据同步过程中,从两个上游分表收到的 binlog 数据有如下的时序: 开始同步时,从两个分表收到的都是 schema V1 的 DML。 在 t1 时刻,收到实例 1 上分表的 DDL。 从 t2 时刻开始,从实例 1 收到的是 schema V2 的 DML;但从实例 2 收到的仍是 schema V1 的 DML。 在 t3 时刻,收到实例 2 上分表的 DDL。 从 t4 时刻开始,从实例 2 收到的也是 schema V2 的 DML。 假设在数据同步过程中,不对分表的 DDL 进行处理。当将实例 1 的 DDL 同步到下游后,下游的表结构会变更成为 schema V2。但对于实例 2,在 t2 时刻到 t3 时刻这段时间内收到的仍然是 schema V1 的 DML。当尝试把这些与 schema V1 对应的 DML 同步到下游时,就会由于 DML 与表结构的不一致而发生错误,造成数据无法正确同步。继续使用上面的例子,来看看我们在 DM 中是如何处理合库合表过程中的 DDL 同步的。在这个例子中,DM-worker-1 用于同步来自 MySQL 实例 1 的数据,DM-worker-2 用于同步来自 MySQL 实例 2 的数据,DM-master 用于协调多个 DM-worker 间的 DDL 同步。从 DM-worker-1 收到 DDL 开始,简化后的 DDL 同步流程为: DM-worker-1 在 t1 时刻收到来自 MySQL 实例 1 的 DDL,自身暂停该 DDL 对应任务的 DDL 及 DML 数据同步,并将 DDL 相关信息发送给 DM-master。 DM-master 根据 DDL 信息判断需要协调该 DDL 的同步,为该 DDL 创建一个锁,并将 DDL 锁信息发回给 DM-worker-1,同时将 DM-worker-1 标记为这个锁的 owner。 DM-worker-2 继续进行 DML 的同步,直到在 t3 时刻收到来自 MySQL 实例 2 的 DDL,自身暂停该 DDL 对应任务的数据同步,并将 DDL 相关信息发送给 DM-master。 DM-master 根据 DDL 信息判断该 DDL 对应的锁信息已经存在,直接将对应锁信息发回给 DM-worker-2。 DM-master 根据启动任务时的配置信息、上游 MySQL 实例分表信息、部署拓扑信息等,判断得知已经收到了需要合表的所有上游分表的该 DDL,请求 DDL 锁的 owner(DM-worker-1)向下游同步执行该 DDL。 DM-worker-1 根据 step 2 时收到的 DDL 锁信息验证 DDL 执行请求;向下游执行 DDL,并将执行结果反馈给 DM-master;若执行 DDL 成功,则自身开始继续同步后续的(从 t2 时刻对应的 binlog 开始的)DML。 DM-master 收到来自 owner 执行 DDL 成功的响应,请求在等待该 DDL 锁的所有其他 DM-worker(DM-worker-2)忽略该 DDL,直接继续同步后续的(从 t4 时刻对应的 binlog 开始的)DML。 根据上面 DM 处理多个 DM-worker 间的 DDL 同步的流程,归纳一下 DM 内处理多个 DM-worker 间 sharding DDL 同步的特点: 根据任务配置与 DM 集群部署拓扑信息,在 DM-master 内建立一个需要协调 DDL 同步的逻辑 sharding group,group 中的成员为处理该任务拆解后各子任务的 DM-worker。 各 DM-worker 在从 binlog event 中获取到 DDL 后,会将 DDL 信息发送给 DM-master。 DM-master 根据来自 DM-worker 的 DDL 信息及 sharding group 信息创建/更新 DDL 锁。 如果 sharding group 的所有成员都收到了某一条 DDL,则表明上游分表在该 DDL 执行前的 DML 都已经同步完成,可以执行 DDL,并继续后续的 DML 同步。 上游分表的 DDL …"}, {"url": "https://pingcap.com/blog/pingcap-2018-year-in-review/", "title": "PingCAP 2018 Year in Review", "content": ""}, {"url": "https://pingcap.com/weekly/2018-12-24-tidb-weekly/", "title": "Weekly update (December 17 ~ December 23, 2018)", "content": " Weekly update in TiDB Last week, we landed 48 PRs in the TiDB repository.Added Add the CFB mode for the AES encryption Implement the basic CreateView feature Add the HTTP API to query hot tables/indexes Improved Make Admin Check Table only check the public index Handle non-BMP characters in the UTF-8 charset Specify the sort order for the columns in the physical property Refactor error handling of transactions Close all connections directly when terminating TiDB Ignore the unknown hint and return a warning Support specifying the ending of a range to be scanned Add the extra information message to be sent to the MySQL client Fixed Fix the wrong output of Show Master Status Fix the incorrect result related to the Duration columns Fix the compatibility problem of renaming tables Correct the column name with the unary plus sign Handle corner cases for auto_increment columns Weekly update in TiKV and PD Last week, we landed 29 PRs in the TiKV and PD repositories.Added Add lpad and lpad_binary built-in functions Add add_datetime_and_duration, add_datetime_and_string and add_time_datetime_null built-in functions Add an HTTP port for Prometheus Introduce the Raftstore router Improved Check overlapped Regions for the new Region Remove the disturbing log when the store is tombstone Fixed Fix the possible panic issue caused by Approximate Size Split Fix a bug about Region merge in the case of multiple snapshots New contributors (Thanks!) tidb-operator: queenliuxx tidb: cuining kjzz parser: TennyZhuang caohe exialin hanchuanchuan honestold3 kangkaisen knarfeh tony612 "}, {"url": "https://pingcap.com/blog-cn/tidb-source-code-reading-22/", "title": "TiDB 源码阅读系列文章(二十二)Hash Aggregation", "content": " 聚合算法执行原理 在 SQL 中,聚合操作对一组值执行计算,并返回单个值。TiDB 实现了 2 种聚合算法:Hash Aggregation 和 Stream Aggregation。我们首先以 AVG 函数为例(案例参考 Stack Overflow),简述这两种算法的执行原理。假设表 t 如下: 列 a 列 b 1 9 1 -8 2 -7 2 6 1 5 2 4 SQL: select avg(b) from t group by a, 要求将表 t 的数据按照 a 的值分组,对每一组的 b 值计算平均值。不管 Hash 还是 Stream 聚合,在 AVG 函数的计算过程中,我们都需要维护 2 个中间结果变量 sum 和 count。Hash 和 Stream 聚合算法的执行原理如下。Hash Aggregate 的执行原理 在 Hash Aggregate 的计算过程中,我们需要维护一个 Hash 表,Hash 表的键为聚合计算的 Group-By 列,值为聚合函数的中间结果 sum 和 count。在本例中,键为 列 a 的值,值为 sum(b) 和 count(b)。计算过程中,只需要根据每行输入数据计算出键,在 Hash 表中找到对应值进行更新即可。对本例的执行过程模拟如下。 输入数据 a b Hash 表 [key] (sum, count) 1 9 [1] (9, 1) 1 -8 [1] (1, 2) 2 -7 [1] (1, 2) [2] (-7, 1) 2 6 [1] (1, 2) [2] (-1, 2) 1 5 [1] (6, 3) [2] (-1, 2) 2 4 [1] (6, 3) [2] (3, 3) 输入数据输入完后,扫描 Hash 表并计算,便可以得到最终结果: Hash 表 avg(b) [1] (6, 3) 2 [2] (3, 3) 1 Stream Aggregation 的执行原理 Stream Aggregate 的计算需要保证输入数据按照 Group-By 列有序。在计算过程中,每当读到一个新的 Group 的值或所有数据输入完成时,便对前一个 Group 的聚合最终结果进行计算。对于本例,我们首先对输入数据按照 a 列进行排序。排序后,本例执行过程模拟如下。 输入数据 是否为新 Group 或所有数据输入完成 (sum, count) avg(b) 1 9 是 (1, 9) 前一个 Group 为空,不进行计算 1 -8 否 (2, 1) 1 5 否 (3, 6) 2 -7 是 (1, -7) 2 2 6 否 (2, -1) 2 4 否 (3, 3) 是 1 因为 Stream Aggregate 的输入数据需要保证同一个 Group 的数据连续输入,所以 Stream Aggregate 处理完一个 Group 的数据后可以立刻向上返回结果,不用像 Hash Aggregate 一样需要处理完所有数据后才能正确的对外返回结果。当上层算子只需要计算部分结果时,比如 Limit,当获取到需要的行数后,可以提前中断 Stream Aggregate 后续的无用计算。当 Group-By 列上存在索引时,由索引读入数据可以保证输入数据按照 Group-By 列有序,此时同一个 Group 的数据连续输入 Stream Aggregate 算子,可以避免额外的排序操作。TiDB 聚合函数的计算模式 由于分布式计算的需要,TiDB 对于聚合函数的计算阶段进行划分,相应定义了 5 种计算模式:CompleteMode,FinalMode,Partial1Mode,Partial2Mode,DedupMode。不同的计算模式下,所处理的输入值和输出值会有所差异,如下表所示: AggFunctionMode 输入值 输出值 CompleteMode 原始数据 最终结果 FinalMode 中间结果 最终结果 Partial1Mode 原始数据 中间结果 Partial2Mode 中间结果 进一步聚合的中间结果 DedupMode 原始数据 去重后的原始数据 以上文提到的 select avg(b) from t group by a 为例,通过对计算阶段进行划分,可以有多种不同的计算模式的组合,如: CompleteMode此时 AVG 函数的整个计算过程只有一个阶段,如图所示: Partial1Mode –> FinalMode此时我们将 AVG 函数的计算过程拆成两个阶段进行,如图所示: 除了上面的两个例子外,还可能有如下的几种计算方式: 聚合被下推到 TiKV 上进行计算(Partial1Mode),并返回经过预聚合的中间结果。为了充分利用 TiDB server 所在机器的 CPU 和内存资源,加快 TiDB 层的聚合计算,TiDB 层的聚合函数计算可以这样进行:Partial2Mode –> FinalMode。 当聚合函数需要对参数进行去重,也就是包含 DISTINCT 属性,且聚合算子因为一些原因不能下推到 TiKV 时,TiDB 层的聚合函数计算可以这样进行:DedupMode –> Partial1Mode –> FinalMode。 聚合函数分为几个阶段执行, 每个阶段对应的模式是什么,是否要下推到 TiKV,使用 Hash 还是 Stream 聚合算子等都由优化器根据数据分布、估算的计算代价等来决定。TiDB 并行 Hash Aggregation 的实现 如何构建 Hash Aggregation 执行器 构建逻辑执行计划 时,会调用 NewAggFuncDesc 将聚合函数的元信息封装为一个 AggFuncDesc。 其中 AggFuncDesc.RetTp 由 AggFuncDesc.typeInfer 根据聚合函数类型及参数类型推导而来;AggFuncDesc.Mode 统一初始化为 CompleteMode。 构建物理执行计划时,PhysicalHashAgg 和 PhysicalStreamAgg 的 attach2Task 方法会根据当前 task 的类型尝试进行下推聚合计算,如果 task 类型满足下推的基本要求,比如 copTask,接着会调用 newPartialAggregate 尝试将聚合算子拆成 TiKV 上执行的 Partial 算子和 TiDB 上执行的 Final 算子,其中 AggFuncToPBExpr 函数用来判断某个聚合函数是否可以下推。若聚合函数可以下推,则会在 TiKV 中进行预聚合并返回中间结果,因此需要将 TiDB 层执行的 Final 聚合算子的 AggFuncDesc.Mode 修改为 FinalMode,并将其 AggFuncDesc.Args 修改为 TiKV 预聚合后返回的中间结果,TiKV 层的 Partial 聚合算子的 AggFuncDesc 也需要作出对应的修改,这里不再详述。若聚合函数不可以下推,则 AggFuncDesc.Mode 保持不变。 构建 HashAgg 执行器时,首先检查当前 HashAgg 算子是否可以并行执行。目前当且仅当两种情况下 HashAgg 不可以并行执行: 存在某个聚合函数参数为 DISTINCT 时。TiDB 暂未实现对 DedupMode 的支持,因此对于含有 DISTINCT 的情况目前仅能单线程执行。 系统变量 tidb_hashagg_partial_concurrency 和 tidb_hashagg_final_concurrency 被同时设置为 1 时。这两个系统变量分别用来控制 Hash Aggregation 并行计算时候,TiDB 层聚合计算 partial 和 final 阶段 worker 的并发数。当它们都被设置为 1 时,选择单线程执行。 若 HashAgg 算子可以并行执行,使用 AggFuncDesc.Split 根据 AggFuncDesc.Mode 将 TiDB 层的聚合算子的计算拆分为 partial 和 final 两个阶段,并分别生成对应的 AggFuncDesc,设为 partialAggDesc 和 finalAggDesc。若 AggFuncDesc.Mode == CompleteMode,则将 TiDB 层的计算阶段拆分为 Partial1Mode --> FinalMode;若 AggFuncDesc.Mode == FinalMode,则将 TiDB 层的计算阶段拆分为 Partial2Mode --> FinalMode。进一步的,我们可以根据 partialAggDesc 和 finalAggDesc 分别 构造出对应的执行函数。并行 Hash Aggregation 执行过程详述 TiDB 的并行 Hash Aggregation 算子执行过程中的主要线程有:Main Thead,Data Fetcher,Partial Worker,和 Final Worker: Main Thread 一个: 启动 Input Reader,Partial Workers 及 Final Workers 等待 Final Worker 的执行结果并返回 Data Fetcher 一个: 按 batch 读取子节点数据并分发给 Partial Worker Partial Worker 多个: 读取 Data Fetcher 发送来的数据,并做预聚合 将预聚合结果根据 Group 值 shuffle 给对应的 Final Worker Final Worker 多个: 读取 PartialWorker 发送来的数据,计算最终结果,发送给 Main Thread Hash Aggregation 的执行阶段可分为如下图所示的 5 步: 启动 Data Fetcher,Partial Workers 及 Final Workers。这部分工作由 prepare4Parallel 函数完成。该函数会启动一个 Data Fetcher,多个 Partial Worker 以及 多个 Final Worker。Partial Worker 和 Final Worker 的数量可以分别通过 tidb_hashgg_partial_concurrency 和 tidb_hashagg_final_concurrency 系统变量进行控制,这两个系统变量的默认值都为 4。 DataFetcher 读取子节点的数据并分发给 Partial Workers。这部分工作由 fetchChildData 函数完成。 Partial Workers 预聚合计算,及根据 Group Key shuffle 给对应的 Final Workers。这部分工作由 HashAggPartialWorker.run 函数完成。该函数调用 updatePartialResult 函数对 DataFetcher 发来数据执行 预聚合计算,并将预聚合结果存储到 partialResultMap 中。其中 partialResultMap 的 key 为根据 Group-By 的值 encode 的结果,value 为 PartialResult 类型的数组,数组中的每个元素表示该下标处的聚合函数在对应 Group 中的预聚合结果。shuffleIntermData 函数完成根据 Group 值 shuffle 给对应的 Final Worker。 Final Worker 计算最终结果,发送给 Main Thread。这部分工作由 HashAggFinalWorker.run 函数完成。该函数调用 consumeIntermData 函数 接收 PartialWorkers 发送来的预聚合结果,进而 合并 得到最终结果。getFinalResult 函数完成发送最终结果给 Main Thread。 Main Thread 接收最终结果并返回。 TiDB 并行 Hash Aggregation 的性能提升 此处以 TPC-H query-17 为例,测试并行 Hash Aggregation 相较于单线程计算时的性能提升。引入并行 Hash Aggregation 前,它的计算瓶颈在 HashAgg_35。该查询执行计划如下:在 TiDB 中,使用 EXPLAIN ANALYZE 可以获取 SQL 的执行统计信息。因篇幅原因此处仅贴出 TPC-H query-17 部分算子的 EXPLAIN ANALYZE 结果。HashAgg 单线程计算时:查询总执行时间 23 分 24 秒,其中 HashAgg 执行时间约 17 分 9 秒。HashAgg 并行计算时(此时 TiDB 层 Partial 和 Final 阶段的 worker 数量都设置为 16):总查询时间 8 分 37 秒,其中 HashAgg 执行时间约 1 分 4 秒。并行计算时,Hash Aggregation 的计算速度提升约 16 倍。"}, {"url": "https://pingcap.com/blog-cn/support-ast-restore-to-sql-text/", "title": "十分钟成为 Contributor 系列 | 支持 AST 还原为 SQL", "content": " 背景知识 SQL 语句发送到 TiDB 后首先会经过 parser,从文本 parse 成为 AST(抽象语法树),AST 节点与 SQL 文本结构是一一对应的,我们通过遍历整个 AST 树就可以拼接出一个与 AST 语义相同的 SQL 文本。对 parser 不熟悉的小伙伴们可以看 TiDB 源码阅读系列文章(五)TiDB SQL Parser 的实现。为了控制 SQL 文本的输出格式,并且为方便未来新功能的加入(例如在 SQL 文本中用 “*” 替代密码),我们引入了 RestoreFlags 并封装了 RestoreCtx 结构(相关源码):// `RestoreFlags` 中的互斥组: // [RestoreStringSingleQuotes, RestoreStringDoubleQuotes] // [RestoreKeyWordUppercase, RestoreKeyWordLowercase] // [RestoreNameUppercase, RestoreNameLowercase] // [RestoreNameDoubleQuotes, RestoreNameBackQuotes] // 靠前的 flag 拥有更高的优先级。 const ( RestoreStringSingleQuotes RestoreFlags = 1 << iota ... ) // RestoreCtx is `Restore` context to hold flags and writer. type RestoreCtx struct { Flags RestoreFlags In io.Writer } // WriteKeyWord 用于向 `ctx` 中写入关键字(例如:SELECT)。 // 它的大小写受 `RestoreKeyWordUppercase`,`RestoreKeyWordLowercase` 控制 func (ctx *RestoreCtx) WriteKeyWord(keyWord string) { ... } // WriteString 用于向 `ctx` 中写入字符串。 // 它是否被引号包裹及转义规则受 `RestoreStringSingleQuotes`,`RestoreStringDoubleQuotes`,`RestoreStringEscapeBackslash` 控制。 func (ctx *RestoreCtx) WriteString(str string) { ... } // WriteName 用于向 `ctx` 中写入名称(库名,表名,列名等)。 // 它是否被引号包裹及转义规则受 `RestoreNameUppercase`,`RestoreNameLowercase`,`RestoreNameDoubleQuotes`,`RestoreNameBackQuotes` 控制。 func (ctx *RestoreCtx) WriteName(name string) { ... } // WritePlain 用于向 `ctx` 中写入普通文本。 // 它将被直接写入不受 flag 影响。 func (ctx *RestoreCtx) WritePlain(plainText string) { ... } // WritePlainf 用于向 `ctx` 中写入普通文本。 // 它将被直接写入不受 flag 影响。 func (ctx *RestoreCtx) WritePlainf(format string, a ...interface{}) { ... } 我们在 ast.Node 接口中添加了一个 Restore(ctx *RestoreCtx) error 函数,这个函数将当前节点对应的 SQL 文本追加至参数 ctx 中,如果节点无效则返回 error。type Node interface { // Restore AST to SQL text and append them to `ctx`. // return error when the AST is invalid. Restore(ctx *RestoreCtx) error ... } 以 SQL 语句 SELECT column0 FROM table0 UNION SELECT column1 FROM table1 WHERE a = 1 为例,如下图所示,我们通过遍历整个 AST 树,递归调用每个节点的 Restore() 方法,即可拼接成一个完整的 SQL 文本。值得注意的是,SQL 文本与 AST 是一个多对一的关系,我们不可能从 AST 结构中还原出与原 SQL 完全一致的文本, 因此我们只要保证还原出的 SQL 文本与原 SQL 语义相同 即可。所谓语义相同,指的是由 AST 还原出的 SQL 文本再被解析为 AST 后,两个 AST 是相等的。我们已经完成了接口设计和测试框架,具体的Restore() 函数留空。因此只需要选择一个留空的 Restore() 函数实现,并添加相应的测试数据,就可以提交一个 PR 了!实现 Restore() 函数的整体流程 请先阅读 Proposal、Issue 在 Issue 中找到未实现的函数 在 Issue-pingcap/tidb#8532 中找到一个没有被其他贡献者认领的任务,例如 ast/expressions.go: BetweenExpr。 在 pingcap/parser 中找到任务对应文件 ast/expressions.go。 在文件中找到 BetweenExpr 结构的 Restore 函数: // Restore implements Node interface. func (n *BetweenExpr) Restore(ctx *RestoreCtx) error { return errors.New("Not implemented") } 实现 Restore() 函数根据 Node 节点结构和 SQL 语法实现函数功能。 参考 MySQL 5.7 SQL Statement Syntax 写单元测试参考示例在相关文件下添加单元测试。 运行 make test,确保所有的 test case 都能跑过。 提交 PRPR 标题统一为:parser: implement Restore for XXX请在 PR 中关联 Issue: pingcap/tidb#8532 示例 这里以实现 BetweenExpr 的 Restore 函数 PR 为例,进行详细说明: 首先看 ast/expressions.go: 我们要实现一个 ast.Node 结构的 Restore 函数,首先清楚该结构代表什么短语,例如 BetweenExpr 代表 expr [NOT] BETWEEN expr AND expr (参见:MySQL 语法 - 比较函数和运算符)。 观察 BetweenExpr 结构: // BetweenExpr is for "between and" or "not between and" expression. type BetweenExpr struct { exprNode // 被检查的表达式 Expr ExprNode // AND 左侧的表达式 Left ExprNode // AND 右侧的表达式 Right ExprNode // 是否有 NOT 关键字 Not bool } 实现 BetweenExpr 的 Restore 函数: // Restore implements Node interface. func (n *BetweenExpr) Restore(ctx *RestoreCtx) error { // 调用 Expr 的 Restore,向 ctx 写入 Expr if err := n.Expr.Restore(ctx); err != nil { return errors.Annotate(err, "An error occurred while restore BetweenExpr.Expr") } // 判断是否有 NOT,并写入相应关键字 if n.Not { ctx.WriteKeyWord(" NOT BETWEEN ") } else { ctx.WriteKeyWord(" BETWEEN ") } // 调用 Left 的 Restore if err := n.Left.Restore(ctx); err != nil { return errors.Annotate(err, "An error occurred while restore BetweenExpr.Left") } // 写入 AND 关键字 ctx.WriteKeyWord(" AND ") // 调用 Right 的 Restore if err := n.Right.Restore(ctx); err != nil { return errors.Annotate(err, "An error occurred while restore BetweenExpr.Right ") } return nil } 接下来给函数实现添加单元测试, ast/expressions_test.go:// 添加测试函数 func (tc *testExpressionsSuite) TestBetweenExprRestore(c *C) { // 测试用例 testCases := []NodeRestoreTestCase{ {"b between 1 and 2", "`b` BETWEEN 1 AND 2"}, {"b not between 1 and 2", "`b` NOT BETWEEN 1 AND 2"}, {"b between a and b", "`b` BETWEEN `a` AND `b`"}, {"b between '' and 'b'", "`b` BETWEEN '' AND 'b'"}, {"b between '2018-11-01' and '2018-11-02'", "`b` BETWEEN '2018-11-01' AND '2018-11-02'"}, } // 为了不依赖父节点实现,通过 extractNodeFunc 抽取待测节点 extractNodeFunc := func(node Node) Node { return node.(*SelectStmt).Fields.Fields[0].Expr } // Run Test RunNodeRestoreTest(c, testCases, "select %s", extractNodeFunc) } 至此 BetweenExpr 的 Restore 函数实现完成,可以提交 PR 了。为了更好的理解测试逻辑,下面我们看 RunNodeRestoreTest:// 下面是测试逻辑,已经实现好了,不需要 contributor 实现 func RunNodeRestoreTest(c *C, nodeTestCases []NodeRestoreTestCase, template string, extractNodeFunc func(node Node) Node) { parser := parser.New() for _, testCase := range nodeTestCases { // 通过 template 将测试用例拼接为完整的 SQL sourceSQL := fmt.Sprintf(template, testCase.sourceSQL) expectSQL := fmt.Sprintf(template, testCase.expectSQL) stmt, err := parser.ParseOneStmt(sourceSQL, "", "") comment := Commentf("source %#v", testCase) c.Assert(err, IsNil, comment) var sb strings.Builder // 抽取指定节点并调用其 Restore 函数 err = extractNodeFunc(stmt).Restore(NewRestoreCtx(DefaultRestoreFlags, &sb)) c.Assert(err, IsNil, comment) // 通过 template 将 restore 结果拼接为完整的 SQL restoreSql := fmt.Sprintf(template, sb.String()) comment = Commentf("source %#v; restore %v", testCase, restoreSql) // 测试 restore 结果与预期一致 c.Assert(restoreSql, Equals, expectSQL, comment) stmt2, err := parser.ParseOneStmt(restoreSql, "", "") c.Assert(err, IsNil, comment) CleanNodeText(stmt) CleanNodeText(stmt2) // 测试解析的 stmt 与原 stmt 一致 c.Assert(stmt2, DeepEquals, stmt, comment) } } 不过对于 ast.StmtNode(例如:ast.SelectStmt)测试方法有些不一样, 由于这类节点可以还原为一个完整的 SQL,因此直接在 parser_test.go 中测试。下面以实现 UseStmt 的 Restore 函数 PR 为例,对测试进行说明: Restore 函数实现过程略。 给函数实现添加单元测试,参见 parser_test.go:在这个示例中,只添加了几行测试数据就完成了测试:// 添加 testCase 结构的测试数据 {"use `select`", true, "USE `select`"}, {"use `sel``ect`", true, "USE `sel``ect`"}, {"use select", false, "USE `select`"}, 我们看 testCase 结构声明:type testCase struct { // 原 SQL src string // 是否能被正确 parse ok bool // 预期的 restore SQL restore string } 测试代码会判断原 SQL parse 出 AST 后再还原的 SQL 是否与预期的 restore SQL 相等,具体的测试逻辑在 parser_test.go 中 RunTest()、RunRestoreTest() 函数,逻辑与前例类似,此处不再赘述。 加入 TiDB Contributor Club,无门槛参与开源项目,改变世界从这里开始吧(萌萌哒)。"}, {"url": "https://pingcap.com/blog-cn/tidb-ecosystem-tools-2/", "title": "TiDB Ecosystem Tools 原理解读系列(二)TiDB-Lightning Toolset 介绍", "content": " 简介 TiDB-Lightning Toolset 是一套快速全量导入 SQL dump 文件到 TiDB 集群的工具集,自 2.1.0 版本起随 TiDB 发布,速度可达到传统执行 SQL 导入方式的至少 3 倍、大约每小时 100 GB,适合在上线前用作迁移现有的大型数据库到全新的 TiDB 集群。设计 TiDB 从 2017 年开始提供全量导入工具 Loader,它以多线程操作、错误重试、断点续传以及修改一些 TiDB 专属配置来提升数据导入速度。然而,当我们全新初始化一个 TiDB 集群时,Loader 这种逐条 INSERT 指令在线上执行的方式从根本上是无法尽用性能的。原因在于 SQL 层的操作有太强的保证了。在整个导入过程中,TiDB 需要: 保证 ACID 特性,需要执行完整的事务流程。 保证各个 TiKV 服务器数据量平衡及有足够的副本,在数据增长的时候需要不断的分裂、调度 Regions。 这些动作确保 TiDB 整段导入的期间是稳定的,但在导入完毕前我们根本不会对外提供服务,这些保证就变成多此一举了。此外,多线程的线上导入也代表资料是乱序插入的,新的数据范围会与旧的重叠。TiKV 要求储存的数据是有序的,大量的乱序写入会令 TiKV 要不断地移动原有的数据(这称为 Compaction),这也会拖慢写入过程。TiKV 是使用 RocksDB 以 KV 对的形式储存数据,这些数据会压缩成一个个 SST 格式文件。TiDB-Lightning Toolset使用新的思路,绕过SQL层,在线下将整个 SQL dump 转化为 KV 对、生成排好序的 SST 文件,然后直接用 Ingestion 推送到 RocksDB 里面。这样批量处理的方法略过 ACID 和线上排序等耗时步骤,让我们提升最终的速度。架构 TiDB-Lightning Toolset 包含两个组件:tidb-lightning 和 tikv-importer。Lightning 负责解析 SQL 成为 KV 对,而 Importer 负责将 KV 对排序与调度、上传到 TiKV 服务器。为什么要把一个流程拆分成两个程式呢? Importer 与 TiKV 密不可分、Lightning 与 TiDB 密不可分,Toolset 的两者皆引用后者为库,而这样 Lightning 与 Importer 之间就出现语言冲突:TiKV 是使用 Rust 而 TiDB 是使用 Go 的。把它们拆分为独立的程式更方便开发,而双方都需要的 KV 对可以透过 gRPC 传递。 分开 Importer 和 Lightning 也使横向扩展的方式更为灵活,例如可以运行多个 Lightning,传送给同一个 Importer。 以下我们会详细分析每个组件的操作原理。Lightning Lightning 现时只支持经 mydumper 导出的 SQL 备份。mydumper 将每个表的内容分别储存到不同的文件,与 mysqldump 不同。这样不用解析整个数据库就能平行处理每个表。首先,Lightning 会扫描 SQL 备份,区分出结构文件(包含 CREATE TABLE 语句)和数据文件(包含 INSERT 语句)。结构文件的内容会直接发送到 TiDB,用以建立数据库构型。然后 Lightning 就会并发处理每一张表的数据。这里我们只集中看一张表的流程。每个数据文件的内容都是规律的 INSERT 语句,像是:INSERT INTO `tbl` VALUES (1, 2, 3), (4, 5, 6), (7, 8, 9); INSERT INTO `tbl` VALUES (10, 11, 12), (13, 14, 15), (16, 17, 18); INSERT INTO `tbl` VALUES (19, 20, 21), (22, 23, 24), (25, 26, 27); Lightning 会作初步分析,找出每行在文件的位置并分配一个行号,使得没有主键的表可以唯一的区分每一行。此外亦同时将文件分割为大小差不多的区块(默认 256 MiB)。这些区块也会并发处理,让数据量大的表也能快速导入。以下的例子把文件以 20 字节为限分割成 5 块:Lightning 会直接使用 TiDB 实例来把 SQL 转换为 KV 对,称为「KV 编码器」。与外部的 TiDB 集群不同,KV 编码器是寄存在 Lightning 进程内的,而且使用内存存储,所以每执行完一个 INSERT 之后,Lightning 可以直接读取内存获取转换后的 KV 对(这些 KV 对包含数据及索引)。得到 KV 对之后便可以发送到 Importer。Importer 因异步操作的缘故,Importer 得到的原始 KV 对注定是无序的。所以,Importer 要做的第一件事就是要排序。这需要给每个表划定准备排序的储存空间,我们称之为 engine file。对大数据排序是个解决了很多遍的问题,我们在此使用现有的答案:直接使用 RocksDB。一个 engine file 就相等于本地的 RocksDB,并设置为优化大量写入操作。而「排序」就相等于将 KV 对全写入到 engine file 里,RocksDB 就会帮我们合并、排序,并得到 SST 格式的文件。这个 SST 文件包含整个表的数据和索引,比起 TiKV 的储存单位 Regions 实在太大了。所以接下来就是要切分成合适的大小(默认为 96 MiB)。Importer 会根据要导入的数据范围预先把 Region 分裂好,然后让 PD 把这些分裂出来的 Region 分散调度到不同的 TiKV 实例上。最后,Importer 将 SST 上传到对应 Region 的每个副本上。然后通过 Leader 发起 Ingest 命令,把这个 SST 文件导入到 Raft group 里,完成一个 Region 的导入过程。我们传输大量数据时,需要自动检查数据完整,避免忽略掉错误。Lightning 会在整个表的 Region 全部导入后,对比传送到 Importer 之前这个表的 Checksum,以及在 TiKV 集群里面时的 Checksum。如果两者一样,我们就有信心说这个表的数据没有问题。一个表的 Checksum 是透过计算 KV 对的哈希值(Hash)产生的。因为 KV 对分布在不同的 TiKV 实例上,这个 Checksum 函数应该具备结合性;另外,Lightning 传送 KV 对之前它们是无序的,所以 Checksum 也不应该考虑顺序,即服从交换律。也就是说 Checksum 不是简单的把整个 SST 文件计算 SHA-256 这样就了事。我们的解决办法是这样的:先计算每个 KV 对的 CRC64,然后用 XOR 结合在一起,得出一个 64 位元的校验数字。为减低 Checksum 值冲突的概率,我们目时会计算 KV 对的数量和大小。若速度允许,将来会加入更先进的 Checksum 方式。总结和下一步计划 从这篇文章大家可以看到,Lightning 因为跳过了一些复杂、耗时的步骤使得整个导入进程更快,适合大数据量的初次导入,接下来我们还会做进一步的改进。提升导入速度 现时 Lightning 会原封不动把整条 SQL 命令抛给 KV 编码器。所以即使我们省去执行分布式 SQL 的开销,但仍需要进行解析、规划及优化语句这些不必要或未被专门化的步骤。Lightning 可以调用更底层的 TiDB API,缩短 SQL 转 KV 的行程。并行导入 另一方面,尽管我们可以不断的优化程序代码,单机的性能总是有限的。要突破这个界限就需要横向扩展:增加机器来同时导入。如前面所述,只要每套 TiDB-Lightning Toolset 操作不同的表,它们就能平行导进同一个集群。可是,现在的版本只支持读取本机文件系统上的 SQL dump,设置成多机版就显得比较麻烦了(要安装一个共享的网络盘,并且手动分配哪台机读取哪张表)。我们计划让 Lightning 能从网路获取 SQL dump(例如通过 S3 API),并提供一个工具自动分割数据库,降低设置成本。在线导入 TiDB-Lightning 在导入时会把集群切换到一个专供 Lightning 写入的模式。目前来说 Lightning 主要用于在进入生产环境之前导入全量数据,所以在此期间暂停对外提供服务还可以接受。但我们希望支持更多的应用场景,例如回复备份、储存 OLAP 的大规模计算结果等等,这些都需要维持集群在线上。所以接下来的一大方向是考虑怎样降低 Lightning 对集群的影响。"}, {"url": "https://pingcap.com/weekly/2018-12-17-tidb-weekly/", "title": "Weekly update (December 10 ~ December 16, 2018)", "content": " Weekly update in TiDB Last week, we landed 47 PRs in the TiDB repository.Added Propose the design for the SQL plan management Support the interactive_timeout system variable Add a batch commit session variable for large transactions Improved Print the error log if the transaction state is unexpected when calling Commit Raise an error or warning for unsupported isolation levels Support ALTER TABLE TRUNCATE PARTITION Support altering the character set to utf8 or utf8mb4 Fixed Make the join reorder solver stateless Fix the unexpected data truncation error when the plan cache is enabled Do not build dual for AntiSemiJoin when the condition is constant false Fix the wrong result when the client uses comStmtSendLongData Fix the optimizer failure for generating a plan when the TIDB_SMJ hint is specified Fix the wrong result caused by the abs function pushdown Fix the panic when adding an index of the generated column Preserve the precision information of timestamp columns in the plan cache Fix data race caused by the flag of JSON columns Move some session variables to the statement context for the correct retry Weekly update in TiSpark Last week, we landed 2 PRs in the TiSpark repository.Added Support the desc table command Fixed Fix the issue that ScanIterator fails to read from adjacent empty Regions Weekly update in TiKV and PD Last week, we landed 36 PRs in the TiKV and PD repositories.Added Add rpad and rpad_binary built-in functions Add year_week_with_mode and year_week_without_mode built-in functions Improved Change the default PD node name to pd-{hostname} Fix the redundant header when PD sends commands to TiKV Check and report undefined PD configuration items Fixed Set retryable instead of the abort error when TiKV exits Fix the issue that PD RaftCluster cannot be stopped Fix a bug about Region merge when the Raftstore thread is very slow New contributors (Thanks!) tikv: AbnerDBFan parser: feloxx haplone "}, {"url": "https://pingcap.com/blog/5-key-differences-between-mysql-and-tidb-for-scaling-in-the-cloud/", "title": "5 Key Differences Between MySQL and TiDB for Scaling in the Cloud", "content": " As businesses adopt cloud-native architectures, conversations will naturally lead to what we can do to make the database horizontally scalable. The answer will likely be to take a closer look at TiDB.TiDB is an open source NewSQL database released under the Apache 2.0 License. Because it speaks the MySQL protocol, your existing applications will be able to connect to it using any MySQL connector, and most SQL functionality remains identical (joins, subqueries, transactions, etc.).Step under the covers, however, and there are differences. If your architecture is based on MySQL with Read Replicas, you’ll see things work a little bit differently with TiDB. In this post, I’ll go through the top five key differences I’ve found between TiDB and MySQL.1. TiDB natively distributes query execution and storage With MySQL, it is common to scale-out via replication. Typically you will have one MySQL master with many slaves, each with a complete copy of the data. Using either application logic or technology like ProxySQL, queries are routed to the appropriate server (offloading queries from the master to slaves whenever it is safe to do so).Scale-out replication works very well for read-heavy workloads, as the query execution can be divided between replication slaves. However, it becomes a bottleneck for write-heavy workloads, since each replica must have a full copy of the data. Another way to look at this is that MySQL Replication scales out SQL processing, but it does not scale out the storage. (By the way, this is true for traditional replication as well as newer solutions such as Galera Cluster and Group Replication.)TiDB works a little bit differently: Query execution is handled via a layer of TiDB servers. Scaling out SQL processing is possible by adding new TiDB servers, which is very easy to do using Kubernetes ReplicaSets. This is because TiDB servers are stateless; its TiKV storage layer is responsible for all of the data persistence. The data for tables is automatically sharded into small chunks and distributed among TiKV servers. Three copies of each data Region (the TiKV name for a shard) are kept in the TiKV cluster, but no TiKV server requires a full copy of the data. To use MySQL terminology: Each TiKV server is both a master and a slave at the same time, since for some data Regions it will contain the primary copy, and for others, it will be secondary. TiDB supports queries across data Regions or, in MySQL terminology, cross-shard queries. The metadata about where the different Regions are located is maintained by the Placement Driver, the management server component of any TiDB Cluster. All operations are fully ACID compliant, and an operation that modifies data across two Regions uses a two-phase commit. For MySQL users learning TiDB, a simpler explanation is the TiDB servers are like an intelligent proxy that translates SQL into batched key-value requests to be sent to TiKV. TiKV servers store your tables with range-based partitioning. The ranges automatically balance to keep each partition at 96MB (by default, but configurable), and each range can be stored on a different TiKV server. The Placement Driver server keeps track of which ranges are located where and automatically rebalances a range if it becomes too large or too hot.This design has several advantages of scale-out replication: It independently scales the SQL Processing and Data Storage tiers. For many workloads, you will hit one bottleneck before the other. It incrementally scales by adding nodes (for both SQL and Data Storage). It utilizes hardware better. To scale out MySQL to one master and four replicas, you would have five copies of the data. TiDB would use only three replicas, with hotspots automatically rebalanced via the Placement Driver. 2. TiDB’s storage engine is RocksDB MySQL’s default storage engine has been InnoDB since 2010. Internally, InnoDB uses a B+tree data structure, which is similar to what traditional commercial databases use.By contrast, TiDB uses RocksDB as the storage engine with TiKV. RocksDB has advantages for large datasets because it can compress data more effectively and insert performance does not degrade when indexes can no longer fit in memory.Note that both MySQL and TiDB support an API that allows new storage engines to be made available. For example, Percona Server and MariaDB both support RocksDB as an option.3. TiDB gathers metrics in Prometheus/Grafana Tracking key metrics is an important part of maintaining database health. MySQL centralizes these fast-changing metrics in Performance Schema. Performance Schema is a set of in-memory tables that can be queried via regular SQL queries.With TiDB, rather than retaining the metrics inside the server, a strategic choice was made to ship the information to a best-of-breed service. Prometheus+Grafana is a common technology stack among operations teams today, and the included graphs make it easy to create your own or configure thresholds for alarms.4. TiDB handles DDL significantly better If we ignore for a second that not all data definition language (DDL) changes in MySQL are online, a larger challenge when running a distributed MySQL system is externalizing schema changes on all nodes at the same time. Think about a scenario where you have 10 shards and add a column, but each shard takes a different length of time to complete the modification. This challenge still exists without sharding, since replicas will process DDL after a master.TiDB implements online DDL using the protocol introduced by the Google F1 paper. In short, DDL changes are broken up into smaller transition stages so they can prevent data corruption scenarios, and the system tolerates an individual node being behind up to one DDL version at a time.5. TiDB is designed for HTAP workloads The MySQL team has traditionally focused its attention on optimizing performance for online transaction processing (OLTP) queries. That is, the MySQL team spends more time making simpler queries perform better instead of making all or complex queries perform better. There is nothing wrong with this approach since many applications only use simple queries.TiDB is designed to perform well across hybrid transaction/analytical processing (HTAP) queries. This is a major selling point for those who want real-time analytics on their data because it eliminates the need for batch loads between their MySQL database and an analytics database.Conclusion These are my top five observations based on 15 years in the MySQL world and coming to TiDB. While many of them refer to internal differences, I recommend checking out the TiDB documentation on MySQL Compatibility. It describes some of the finer points about any differences that may affect your applications.Note: The original version of this article was published on opensource.com"}, {"url": "https://pingcap.com/blog-cn/tidb-source-code-reading-21/", "title": "TiDB 源码阅读系列文章(二十一)基于规则的优化 II", "content": " 在 TiDB 源码阅读系列文章(七)基于规则的优化 一文中,我们介绍了几种 TiDB 中的逻辑优化规则,包括列剪裁,最大最小消除,投影消除,谓词下推和构建节点属性,本篇将继续介绍更多的优化规则:聚合消除、外连接消除和子查询优化。聚合消除 聚合消除会检查 SQL 查询中 Group By 语句所使用的列是否具有唯一性属性,如果满足,则会将执行计划中相应的 LogicalAggregation 算子替换为 LogicalProjection 算子。这里的逻辑是当聚合函数按照具有唯一性属性的一列或多列分组时,下层算子输出的每一行都是一个单独的分组,这时就可以将聚合函数展开成具体的参数列或者包含参数列的普通函数表达式,具体的代码实现在 rule_aggregation_elimination.go 文件中。下面举一些具体的例子。例一:下面这个 Query 可以将聚合函数展开成列的查询:select max(a) from t group by t.pk; 被等价地改写成:select a from t; 例二:下面这个 Query 可以将聚合函数展开为包含参数列的内置函数的查询:select count(a) from t group by t.pk; 被等价地改写成:select if(isnull(a), 0, 1) from t; 这里其实还可以做进一步的优化:如果列 a 具有 Not Null 的属性,那么可以将 if(isnull(a), 0, 1) 直接替换为常量 1(目前 TiDB 还没做这个优化,感兴趣的同学可以来贡献一个 PR)。另外提一点,对于大部分聚合函数,参数的类型和返回结果的类型一般是不同的,所以在展开聚合函数的时候一般会在参数列上构造 cast 函数做类型转换,展开后的表达式会保存在作为替换 LogicalAggregation 算子的 LogicalProjection 算子中。这个优化过程中,有一点非常关键,就是如何知道 Group By 使用的列是否满足唯一性属性,尤其是当聚合算子的下层节点不是 DataSource 的时候?我们在 (七)基于规则的优化 一文中的“构建节点属性”章节提到过,执行计划中每个算子节点会维护这样一个信息:当前算子的输出会按照哪一列或者哪几列满足唯一性属性。因此,在聚合消除中,我们可以通过查看下层算子保存的这个信息,再结合 Group By 用到的列判断当前聚合算子是否可以被消除。外连接消除 不同于 (七)基于规则的优化 一文中“谓词下推”章节提到的将外连接转换为内连接,这里外连接消除指的是将整个连接操作从查询中移除。外连接消除需要满足一定条件: 条件 1 : LogicalJoin 的父亲算子只会用到 LogicalJoin 的 outer plan 所输出的列 条件 2 : 条件 2.1 : LogicalJoin 中的 join key 在 inner plan 的输出结果中满足唯一性属性 条件 2.2 : LogicalJoin 的父亲算子会对输入的记录去重 条件 1 和条件 2 必须同时满足,但条件 2.1 和条件 2.2 只需满足一条即可。满足条件 1 和 条件 2.1 的一个例子:select t1.a from t1 left join t2 on t1.b = t2.pk; 可以被改写成:select t1.a from t1; 满足条件 1 和条件 2.2 的一个例子:select distinct(t1.a) from t1 left join t2 on t1.b = t2.b; 可以被改写成:select distinct(t1.a) from t1; 具体的原理是,对于外连接,outer plan 的每一行记录肯定会在连接的结果集里出现一次或多次,当 outer plan 的行不能找到匹配时,或者只能找到一行匹配时,这行 outer plan 的记录在连接结果中只出现一次;当 outer plan 的行能找到多行匹配时,它会在连接结果中出现多次;那么如果 inner plan 在 join key 上满足唯一性属性,就不可能存在 outer plan 的行能够找到多行匹配,所以这时 outer plan 的每一行都会且仅会在连接结果中出现一次。同时,上层算子只需要 outer plan 的数据,那么外连接可以直接从查询中被去除掉。同理就可以很容易理解当上层算子只需要 outer plan 的去重后结果时,外连接也可以被消除。这部分优化的具体代码实现在 rule_join_elimination.go 文件中。子查询优化 / 去相关 子查询分为非相关子查询和相关子查询,例如:-- 非相关子查询 select * from t1 where t1.a > (select t2.a from t2 limit 1); -- 相关子查询 select * from t1 where t1.a > (select t2.a from t2 where t2.b > t1.b limit 1); 对于非相关子查询, TiDB 会在 expressionRewriter 的逻辑中做两类操作: 子查询展开即直接执行子查询获得结果,再利用这个结果改写原本包含子查询的表达式;比如上述的非相关子查询,如果其返回的结果为一行记录 “1” ,那么整个查询会被改写为:select * from t1 where t1.a > 1; 详细的代码逻辑可以参考 expression_rewriter.go 中的 handleScalarSubquery 和 handleExistSubquery 函数。 子查询转为 Join对于包含 IN (subquery) 的查询,比如:select * from t1 where t1.a in (select t2.a from t2); 会被改写成:select t1.* from t1 inner join (select distinct(t2.a) as a from t2) as sub on t1.a = sub.a; 如果 t2.a 满足唯一性属性,根据上面介绍的聚合消除规则,查询会被进一步改写成:select t1.* from t1 inner join t2 on t1.a = t2.a; 这里选择将子查询转化为 inner join 的 inner plan 而不是执行子查询的原因是:以上述查询为例,子查询的结果集可能会很大,展开子查询需要一次性将 t2 的全部数据从 TiKV 返回到 TiDB 中缓存,并作为 t1 扫描的过滤条件;如果将子查询转化为 inner join 的 inner plan ,我们可以更灵活地对 t2 选择访问方式,比如我们可以对 join 选择 IndexLookUpJoin 实现方式,那么对于拿到的每一条 t1 表数据,我们只需拿 t1.a 作为 range 对 t2 做一次索引扫描,如果 t1 表很小,相比于展开子查询返回 t2 全部数据,我们可能总共只需要从 t2 返回很少的几条数据。注意这个转换的结果不一定会比展开子查询更好,其具体情况会受 t1 表和 t2 表数据的影响,如果在上述查询中, t1 表很大而 t2 表很小,那么展开子查询再对 t1 选择索引扫描可能才是最好的方案,所以现在有参数控制这个转化是否打开,详细的代码可以参考 expression_rewriter.go 中的 handleInSubquery 函数。 对于相关子查询,TiDB 会在 expressionRewriter 中将整个包含相关子查询的表达式转化为 LogicalApply 算子。LogicalApply 算子是一类特殊的 LogicalJoin ,特殊之处体现在执行逻辑上:对于 outer plan 返回的每一行记录,取出相关列的具体值传递给子查询,再执行根据子查询生成的 inner plan ,即 LogicalApply 在执行时只能选择类似循环嵌套连接的方式,而普通的 LogicalJoin 则可以在物理优化阶段根据代价模型选择最合适的执行方式,包括 HashJoin,MergeJoin 和 IndexLookUpJoin,理论上后者生成的物理执行计划一定会比前者更优,所以在逻辑优化阶段我们会检查是否可以应用“去相关”这一优化规则,试图将 LogicalApply 转化为等价的 LogicalJoin 。其核心思想是将 LogicalApply 的 inner plan 中包含相关列的那些算子提升到 LogicalApply 之中或之上,在算子提升后如果 inner plan 中不再包含任何的相关列,即不再引用任何 outer plan 中的列,那么 LogicalApply 就会被转换为普通的 LogicalJoin ,这部分代码逻辑实现在 rule_decorrelate.go 文件中。具体的算子提升方式分为以下几种情况: inner plan 的根节点是 LogicalSelection则将其过滤条件添加到 LogicalApply 的 join condition 中,然后将该 LogicalSelection 从 inner plan 中删除,再递归地对 inner plan 提升算子。以如下查询为例:select * from t1 where t1.a in (select t2.a from t2 where t2.b = t1.b); 其生成的最初执行计划片段会是:LogicalSelection 提升后会变成如下片段:到此 inner plan 中不再包含相关列,于是 LogicalApply 会被转换为如下 LogicalJoin : inner plan 的根节点是 LogicalMaxOneRow即要求子查询最多输出一行记录,比如这个例子:select *, (select t2.a from t2 where t2.pk = t1.a) from t1; 因为子查询出现在整个查询的投影项里,所以 expressionRewriter 在处理子查询时会对其生成的执行计划在根节点上加一个 LogicalMaxOneRow 限制最多产生一行记录,如果在执行时发现下层输出多于一行记录,则会报错。在这个例子中,子查询的过滤条件是 t2 表的主键上的等值条件,所以子查询肯定最多只会输出一行记录,而这个信息在“构建节点属性”这一步时会被发掘出来并记录在算子节点的 MaxOneRow 属性中,所以这里的 LogicalMaxOneRow 节点实际上是冗余的,于是我们可以将其从 inner plan 中移除,然后再递归地对 inner plan 做算子提升。 inner plan 的根节点是 LogicalProjection则首先将这个投影算子从 inner plan 中移除,再根据 LogicalApply 的连接类型判断是否需要在 LogicalApply 之上再加上一个 LogicalProjection ,具体来说是:对于非 semi-join 这一类的连接(包括 inner join 和 left join ),inner plan 的输出列会保留在 LogicalApply 的结果中,所以这个投影操作需要保留,反之则不需要。最后,再递归地对删除投影后的 inner plan 提升下层算子。 inner plan 的根节点是 LogicalAggregation 首先我们会检查这个聚合算子是否可以被提升到 LogicalApply 之上再执行。以如下查询为例:select *, (select sum(t2.b) from t2 where t2.a = t1.pk) from t1; 其最初生成的执行计划片段会是:将聚合提升到 LogicalApply 后的执行计划片段会是:即先对 t1 和 t2 做连接,再在连接结果上按照 t1.pk 分组后做聚合。这里有两个关键变化:第一是不管提升前 LogicalApply 的连接类型是 inner join 还是 left join ,提升后必须被改为 left join ;第二是提升后的聚合新增了 Group By 的列,即要按照 outer plan 传进 inner plan 中的相关列做分组。这两个变化背后的原因都会在后面进行阐述。因为提升后 inner plan 不再包含相关列,去相关后最终生成的执行计划片段会是:聚合提升有很多限定条件: LogicalApply 的连接类型必须是 inner join 或者 left join 。 LogicalApply 是根据相关子查询生成的,只可能有 3 类连接类型,除了 inner join 和 left join 外,第三类是 semi join (包括 SemiJoin,LeftOuterSemiJoin,AntiSemiJoin,AntiLeftOuterSemiJoin),具体可以参考 expression_rewriter.go 中的代码,限于篇幅在这里就不对此做展开了。对于 semi join 类型的 LogicalApply ,因为 inner plan 的输出列不会出现在连接的结果中,所以很容易理解我们无法将聚合算子提升到 LogicalApply 之上。 LogicalApply 本身不能包含 join condition 。以上面给出的查询为例,可以看到聚合提升后会将子查询中包含相关列的过滤条件 (t2.a = t1.pk) 添加到 LogicalApply 的 join condition 中,如果 LogicalApply 本身存在 join condition ,那么聚合提升后聚合算子的输入(连接算子的输出)就会和在子查询中时聚合算子的输入不同,导致聚合算子结果不正确。 子查询中用到的相关列在 outer plan 输出里具有唯一性属性。以上面查询为例,如果 t1.pk 不满足唯一性,假设 t1 有两条记录满足 t1.pk = 1,t2 只有一条记录 { (t2.a: 1, t2.b: 2) },那么该查询会输出两行结果 { (sum(t2.b): 2), (sum(t2.b): 2) };但对于聚合提升后的执行计划,则会生成错误的一行结果{ (sum(t2.b): 4) }。当 t1.pk 满足唯一性后,每一行 outer plan 的记录都对应连接结果中的一个分组,所以其聚合结果会和在子查询中的聚合结果一致,这也解释了为什么聚合提升后需要按照 t1.pk 做分组。 聚合函数必须满足当输入为 null 时输出结果也一定是 null 。这是为了在子查询中没有匹配的特殊情况下保证结果的正确性,以上面查询为例,当 t2 表没有任何记录满足 t2.a = t1.pk 时,子查询中不管是什么聚合函数都会返回 null 结果,为了保留这种特殊情况,在聚合提升的同时, LogicalApply 的连接类型会被强制改为 left join(改之前可能是 inner join ),所以在这种没有匹配的情况下,LogicalApply 输出结果中 inner plan 部分会是 null ,而这个 null 会作为新添加的聚合算子的输入,为了和提升前结果一致,其结果也必须是 null 。 对于根据上述条件判定不能提升的聚合算子,我们再检查这个聚合算子的子节点是否为 LogicalSelection ,如果是,则将其从 inner plan 中移除并将过滤条件添加到 LogicalApply 的 join condition 中。这种情况下 LogicalAggregation 依然会被保留在 inner plan 中,但会将 LogicalSelection 过滤条件中涉及的 inner 表的列添加到聚合算子的 Group By 中。比如对于查询:select *, (select count(*) from t2 where t2.a = t1.a) from t1; 其生成的最初的执行计划片段会是:因为聚合函数是 count(*) ,不满足当输入为 null 时输出也为 null 的条件,所以它不能被提升到 LogicalApply 之上,但它可以被改写成:注意 LogicalAggregation 的 Group By 新加了 t2.a ,这一步将原本的先做过滤再做聚合转换为了先按照 t2.a 分组做聚合,再将聚合结果与 t1 做连接。 LogicalSelection 提升后 inner plan 已经不再依赖 outer plan 的结果了,整个查询去相关后将会变为: 总结 这是基于规则优化的第二篇文章,后续我们还将介绍更多逻辑优化规则:聚合下推,TopN 下推和 Join Reorder 。"}, {"url": "https://pingcap.com/weekly/2018-12-10-tidb-weekly/", "title": "Weekly update (December 03 ~ December 09, 2018)", "content": " Weekly update in TiDB Last week, we landed 48 PRs in the TiDB repository.Added Add the HTTP API to query the DDL history Add two metrics gauges to show CPU and memory usage Propose the design to restore the SQL text from the AST tree Add the implementation phase framework of the cascades planner Add the ddl_reorg_batch_size variable to control the batch size of the DDL worker Add the gc_enable variable to enable or disable GC Add the transform phase framework of the cascades planner Improved Speed up execution of unit tests for the statistics package Disable the global variable cache when running unit tests Do the DDL check for Create Index before putting it to the job queue Speed up execution of unit tests for the tikv package Improve compatibility when casting string as datetime Support Show Create Table for hash partitioned tables Support batchInsert of values for the Insert statement Improve the current greedy join reorder algorithm to leverage cost estimation Support Select/Insert for hash partitioned tables Support Truncate for hash partitioned tables Support Alter Table Add Partition for hash partitioned tables Support ? in Order By/Group By/Limit Offset clauses Fixed Set correct concurrency for Projection below Aggregation Handle corrupted length parameters for the uncompress built-in function Fix failure of Grant in the ANSI_QUOTES SQL mode Fix incorrect date arithmetics with the negative interval parameter Fix the bug of cancelling Drop Index Weekly update in TiSpark Last week, we landed 4 PRs in the TiSpark repository.Fixed Fix the unresolved column name when using table.column Fix the LockResolverTest error when sending requests using callWithRetry Weekly update in TiKV and PD Last week, we landed 22 PRs in the TiKV and PD repositories.Added Add StoreNotMatch details Add the strcmp built-in function Add the week_day and the week_of_year built-in functions Add the compress, uncompress and uncompressed_length built-in functions Add the end_key support for raw_scan Add the concat_ws built-in function Improved Replace FxHashMap with Hashbrown Make DeleteRange safe again Fixed Reject transferring the leader to the recently added peers Change the merge match peers strategy New contributors (Thanks!) tidb: lonnng ziyi-yan tikv: kg88 AbnerZheng docs-cn: beckxie "}, {"url": "https://pingcap.com/blog-cn/tidb-ecosystem-tools-1/", "title": "TiDB Ecosystem Tools 原理解读系列(一):TiDB-Binlog 架构演进与实现原理", "content": " 简介 TiDB-Binlog 组件用于收集 TiDB 的 binlog,并提供实时备份和同步功能。该组件在功能上类似于 MySQL 的主从复制,MySQL 的主从复制依赖于记录的 binlog 文件,TiDB-Binlog 组件也是如此,主要的不同点是 TiDB 是分布式的,因此需要收集各个 TiDB 实例产生的 binlog,并按照事务提交的时间排序后才能同步到下游。如果你需要部署 TiDB 集群的从库,或者想订阅 TiDB 数据的变更输出到其他的系统中,TiDB-Binlog 则是必不可少的工具。架构演进 TiDB-Binlog 这个组件已经发布了 2 年多时间,经历过几次架构演进,去年十月到现在大规模使用的是 Kafka 版本,架构图如下:Kafka 版本的 TiDB-Binlog 主要包括两个组件:Pump:一个守护进程,在每个 TiDB 主机的后台运行。其主要功能是实时记录 TiDB 产生的 binlog 并顺序写入 Kafka 中。Drainer: 从 Kafka 中收集 binlog,并按照 TiDB 中事务的提交顺序转化为指定数据库兼容的 SQL 语句或者指定格式的数据,最后同步到目的数据库或者写到顺序文件。这个架构的工作原理为: TiDB 需要与 Pump 绑定,即 TiDB 实例只能将它生成的 binlog 发送到一个指定的 Pump 中; Pump 将 binlog 先写到本地文件,再异步地写入到 Kafka; Drainer 从 Kafka 中读出 binlog,对 binlog 进行排序,对 binlog 解析后生成 SQL 或指定格式的数据再同步到下游。 根据用户的反馈,以及我们自己做的一些测试,发现该版本主要存在一些问题。首先,TiDB 的负载可能不均衡,部分 TiDB 业务较多,产生的 binlog 也比较多,对应的 Pump 的负载高,导致数据同步延迟高。其次,依赖 Kafka 集群,增加了运维成本;而且 TiDB 产生的单条 binlog 的大小可达 2G(例如批量删除数据、批量写入数据),需要配置 Kafka 的消息大小相关设置,而 Kafka 并不太适合单条数据较大的场景。最后,Drainer 需要读取 Kafka 中的 binlog、对 binlog 进行排序、解析 binlog,同步数据到下游等工作,可以看出 Drainer 的工作较多,而且 Drainer 是一个单点,所以往往同步数据的瓶颈都在 Drainer。以上这些问题我们很难在已有的框架下进行优化,因此我们对 TiDB-Binlog 进行了重构,最新版本的 TiDB-Binlog 的总体架构如下图所示:新版本 TiDB-Binlog 不再使用 Kafka 存储 binlog,仍然保留了 Pump 和 Drainer 两个组件,但是对功能进行了调整: Pump 用于实时记录 TiDB 产生的 binlog,并将 binlog 按照事务的提交时间进行排序,再提供给 Drainer 进行消费。 Drainer 从各个 Pump 中收集 binlog 进行归并,再将 binlog 转化成 SQL 或者指定格式的数据,最终同步到下游。 该版本的主要优点为: 多个 Pump 形成一个集群,可以水平扩容,各个 Pump 可以均匀地承担业务的压力。 TiDB 通过内置的 Pump Client 将 binlog 分发到各个 Pump,即使有部分 Pump 出现故障也不影响 TiDB 的业务。 Pump 内部实现了简单的 kv 来存储 binlog,方便对 binlog 数据的管理。 原来 Drainer 的 binlog 排序逻辑移到了 Pump 来做,而 Pump 是可扩展的,这样就能提高整体的同步性能。 Drainer 不再需要像原来一样读取一批 binlog 到内存里进行堆排序,只需要依次读取各个 Pump 的 binlog 进行归并排序,这样可以大大节省内存的使用,同时也更容易做内存控制。 由于该版本最大的特点是多个 Pump 组成了一个集群(cluster),因此该版本命名为 cluster 版本。下面我们以最新的 cluster 版本的架构来介绍 TiDB-Binlog 的实现原理。工作原理 binlog 首先我们先介绍一下 TiDB 中的 binlog,TiDB 的事务采用 2pc 算法,一个成功的事务会写两条 binlog,包括一条 Prewrite binlog 和 一条 Commit binlog;如果事务失败,会发一条 Rollback binlog。binlog 的结构定义为:// Binlog 记录事务中所有的变更,可以用 Binlog 构建 SQL message Binlog { // Binlog 的类型,包括 Prewrite、Commit、Rollback 等 optional BinlogType tp = 1 [(gogoproto.nullable) = false]; // Prewrite, Commit 和 Rollback 类型的 binlog 的 start_ts,记录事务开始的 ts optional int64 start_ts = 2 [(gogoproto.nullable) = false]; // commit_ts 记录事务结束的 ts,只记录在 commit 类型的 binlog 中 optional int64 commit_ts = 3 [(gogoproto.nullable) = false]; // prewrite key 只记录在 Prewrite 类型的 binlog 中, // 是一个事务的主键,用于查询该事务是否提交 optional bytes prewrite_key = 4; // prewrite_value 记录在 Prewrite 类型的 binlog 中,用于记录每一行数据的改变 optional bytes prewrite_value = 5; // ddl_query 记录 ddl 语句 optional bytes ddl_query = 6; // ddl_job_id 记录 ddl 的 job id optional int64 ddl_job_id = 7 [(gogoproto.nullable) = false]; } binlog 及相关的数据结构定义见: binlog.proto其中 start_ts 为事务开始时的 ts,commit_ts 为事务提交的 ts。ts 是由物理时间和逻辑时间转化而成的,在 TiDB 中是唯一的,由 PD 来统一提供。在开始一个事务时,TiDB 会请求 PD,获取一个 ts 作为事务的 start_ts,在事务提交时则再次请求 PD 获取一个 ts 作为 commit_ts。 我们在 Pump 和 Drainer 中就是根据 binlog 的 commit_ts 来对 binlog 进行排序的。TiDB 的 binlog 记录为 row 模式,即保存每一行数据的改变。数据的变化记录在 prewrite_value 字段中,该字段的数据主要由序列化后的 TableMutation 结构的数据组成。TableMutation 的结构如下所示:// TableMutation 存储表中数据的变化 message TableMutation { // 表的 id,唯一标识一个表 optional int64 table_id = 1 [(gogoproto.nullable) = false]; // 保存插入的每行数据 repeated bytes inserted_rows = 2; // 保存修改前和修改后的每行的数据 repeated bytes updated_rows = 3; // 已废弃 repeated int64 deleted_ids = 4; // 已废弃 repeated bytes deleted_pks = 5; // 删除行的数据 repeated bytes deleted_rows = 6; // 记录数据变更的顺序 repeated MutationType sequence = 7; } 下面以一个例子来说明 binlog 中是怎么存储数据的变化的。例如 table 的结构为:create table test (id int, name varchar(24), primary key id)按照顺序执行如下 SQL:begin; insert into test(id, name) values(1, "a"); insert into test(id, name) values(2, "b"); update test set name = "c" where id = 1; update test set name = "d" where id = 2; delete from test where id = 2; insert into test(id, name) values(2, "c"); commit; 则生成的 TableMutation 的数据如下所示:inserted_rows: 1, "a" 2, "b" 2, "c" updated_rows: 1, "a", 1, "c" 2, "b", 2, "d" deleted_rows: 2, "d" sequence: Insert, Insert, Update, Update, DeleteRow, Insert 可以从例子中看出,sequence 中保存的数据变更类型的顺序为执行 SQL 的顺序,具体变更的数据内容则保存到了相应的变量中。Drainer 在把 binlog 数据同步到下游前,就需要把上面的这些数据还原成 SQL,再同步到下游。另外需要说明的是,TiDB 在写 binlog 时,会同时向 TiKV 发起写数据请求和向 Pump 发送 Prewrite binlog,如果 TiKV 和 Pump 其中一个请求失败,则该事务失败。当 Prewrite 成功后,TiDB 向 TiKV 发起 Commit 消息,并异步地向 Pump 发送一条 Commit binlog。由于 TiDB 是同时向 TiKV 和 Pump 发送请求的,所以只要保证 Pump 处理 Prewrite binlog 请求的时间小于等于 TiKV 执行 Prewrite 的时间,开启 binlog 就不会对事务的延迟造成影响。Pump Client 从上面的介绍中我们知道由多个 Pump 组成一个集群,共同承担写 binlog 的请求,那么就需要保证 TiDB 能够将写 binlog 的请求尽可能均匀地分发到各个 Pump,并且需要识别不可用的 Pump,及时获取到新加入集群中 Pump 信息。这部分的工作是在 Pump Client 中实现的。Pump Client 以包的形式集成在 TiDB 中,代码链接:pump_client。Pump Client 维护 Pump 集群的信息,Pump 的信息主要来自于 PD 中保存的 Pump 的状态信息,状态信息的定义如下(代码链接:Status):type Status struct { // Pump/Drainer 实例的唯一标识 NodeID string `json:"nodeId"` // Pump/Drainer 的服务地址 Addr string `json:"host"` // Pump/Drainer 的状态,值可以为 online、pausing、paused、closing、offline State string `json:"state"` // Pump/Drainer 是否 alive(目前没有使用该字段) IsAlive bool `json:"isAlive"` // Pump的分数,该分数是由节点的负载、磁盘使用率、存储的数据量大小等因素计算得来的, // 这样 Pump Client 可以根据分数来选取合适的 Pump 发送 binlog(待实现) Score int64 `json:"score"` // Pump 的标签,可以通过 label 对 TiDB 和 Pump 进行分组, // TiDB 只能将 binlog 发送到相同 label 的 Pump(待实现) Label *Label `json:"label"` // Pump: 保存的 binlog 的最大的 commit_ts // Drainer:已消费的 binlog 的最大的 commit_ts MaxCommitTS int64 `json:"maxCommitTS"` // 该状态信息的更新时间对应的 ts. UpdateTS int64 `json:"updateTS"` } Pump Client 根据 Pump 上报到 PD 的信息以及写 binlog 请求的实际情况将 Pump 划分为可用 Pump 与不可用 Pump 两个部分。划分的方法包括: 初始化时从 PD 中获取所有 Pump 的信息,将状态为 online 的 Pump 加入到可用 Pump 列表中,其他 Pump 加入到非可用列表中。 Pump 每隔固定的时间会发送心跳到 PD,并更新自己的状态。Pump Client 监控 PD 中 Pump 上传的状态信息,及时更新内存中维护的 Pump 信息,如果状态由非 online 转换为 online 则将该 Pump 加入到可用 Pump 列表;反之加入到非可用列表中。 在写 binlog 到 Pump 时,如果该 Pump 在重试多次后仍然写 binlog 失败,则把该 Pump 加入到非可用 Pump 列表中。 定时发送探活请求(数据为空的 binlog 写请求)到非可用 Pump 列表中的状态为 online 的 Pump,如果返回成功,则把该 Pump 重新加入到可用 Pump 列表中。 通过上面的这些措施,Pump Client 就可以及时地更新所维护的 Pump 集群信息,保证将 binlog 发送到可用的 Pump 中。另外一个问题是,怎么保证 Pump Client 可以将 binlog 写请求均匀地分发到各个 Pump?我们目前提供了几种路由策略: range: 按照顺序依次选取 Pump 发送 binlog,即第一次选取第一个 Pump,第二次选取第二个 Pump… hash:对 binlog 的 start_ts 进行 hash,然后选取 hash 值对应的 Pump。 score:根据 Pump 上报的分数按照加权平均算法选取 Pump 发送 binlog(待实现)。 需要注意的地方是,以上的策略只是针对 Prewrite binlog,对于 Commit binlog,Pump Client 会将它发送到对应的 Prewrite binlog 所选择的 Pump,这样做是因为在 Pump 中需要将包含 Prewrite binlog 和 Commit binlog 的完整 binlog(即执行成功的事务的 binlog)提供给 Drainer,将 Commit binlog 发送到其他 Pump 没有意义。Pump Client 向 Pump 提交写 binlog 的请求接口为 pump.proto 中的 WriteBinlog,使用 grpc 发送 binlog 请求。Pump Pump 主要用来承担 binlog 的写请求,维护 binlog 数据,并将有序的 binlog 提供给 Drainer。我们将 Pump 抽象成了一个简单的 kv 数据库,key 为 binlog 的 start _ts(Priwrite binlog) 或者 commit_ts(Commit binlog),value 为 binlog 的元数据,binlog 的数据则存在数据文件中。Drainer 像查数据库一样的来获取所需要的 binlog。Pump 内置了 leveldb 用于存储 binlog 的元信息。在 Pump 收到 binlog 的写请求时,会首先将 binlog 数据以 append 的形式写到文件中,然后将 binlog 的 ts、类型、数据长度、所保存的文件以及在文件中的位置信息保存在 leveldb 中,如果为 Prewrite binlog,则以 start_ts作为 key;如果是 Commit binlog,则以 commit_ts 作为 key。当 Drainer 向 Pump 请求获取指定 ts 之后的 binlog 时,Pump 则查询 leveldb 中大于该 ts 的 binlog 的元数据,如果当前数据为 Prewrite binlog,则必须找到对应的 Commit binlog;如果为 Commit binlog 则继续向前推进。这里有个问题,在 binlog 一节中提到,如果 TiKV 成功写入了数据,并且 Pump 成功接收到了 Prewrite binlog,则该事务就提交成功了,那么如果在 TiDB 发送 Commit binlog 到 Pump 前发生了一些异常(例如 TiDB 异常退出,或者强制终止了 TiDB 进程),导致 Pump 没有接收到 Commit binlog,那么 Pump 中就会一直找不到某些 Prewrite binlog 对应的 Commit binlog。这里我们在 Pump 中做了处理,如果某个 Prewrite binlog 超过了十分钟都没有找到对应的 Commit binlog,则通过 binlog 数据中的 prewrite_key 去查询 TiKV 该事务是否提交,如果已经提交成功,则 TiKV 会返回该事务的 commit_ts;否则 Pump 就丢弃该条 Prewrite binlog。binlog 元数据中提供了数据存储的文件和位置,可以通过这些信息读取 binlog 文件的指定位置获取到数据。因为 binlog 数据基本上是按顺序写入到文件中的,因此我们只需要顺序地读 binlog 文件即可,这样就保证了不会因为频繁地读取文件而影响 Pump 的性能。最终,Pump 以 commit_ts 为排序标准将 binlog 数据传输给 Drainer。Drainer 向 Pump 请求 binlog 数据的接口为 pump.proto 中的 PullBinlogs,以 grpc streaming 的形式传输 binlog 数据。值得一提的是,Pump 中有一个 fake binlog 机制。Pump 会定时(默认三秒)向本 …"}, {"url": "https://pingcap.com/success-stories/tidb-in-meituan-dianping/", "title": "TiDB, the Key to a Better Life for Meituan-Dianping’s 290 Million Monthly Users", "content": " Industry: Search and Ecommerce PlatformAuthors: Yinggang Zhao (Researcher at Meituan-Dianping), Kun Li (Database expert at Meituan-Dianping) and Changjun Piao (Database expert at Meituan-Dianping)Introduction In Chinese, Meituan-Dianping means “better buying, better life,” and since it was formed in 2015 by the merger of two companies, the platform has facilitated billions of purchases of goods and services with built-in discounts. By gross merchandise volume, Meituan-Dianping is China’s largest group-buying website. Part Groupon, part Yelp, and part Uber Eats, we offer a range of localized services and entertainment, such as food delivery, restaurant reviews, haircuts and manicures, ticket bookings, bike-sharing, and more. In April 2018, we had 290 million monthly active users, and last year we generated more than 5.8 billion transactions with over $51 billion in gross transaction volume. On September 20, 2018, our company debuted on the Hong Kong stock exchange at an IPO price of HK$69 per share.As our business has grown rapidly, our data volume has also surged. This has placed tremendous pressure on the MySQL database system in our backend. Burdened by handling this immense data, we began to explore a better data storage solution. Fortunately, we found TiDB, a MySQL-compatible NewSQL hybrid transactional and analytical processing (HTAP) database, built and supported by PingCAP. Now we can harness our data with more confidence than ever before and provide better services for our users to enjoy a better life.At the beginning of 2018, our DBA (database administrator) team worked together with the architecture storage team to choose and implement a distributed database solution. Since November 2018, 10 TiDB clusters have been deployed in our production environment, with nearly 200 physical nodes. These clusters are deployed for six product divisions or platforms: delivery, transport, quick pass, accommodation, the Meituan platform, and the core development platform. Most of these applications are pure OLTP (online transaction processing) workloads. We are happy to report that all the clusters have been running smoothly since their deployment.In this post, we will share two of the scenarios for which we chose TiDB, how we are using it, some issues we’ve had and the corresponding solutions, as well as our experiences collaborating with PingCAP.Challenges Scenario 1: Offline Analytical Workload with Huge Writes and High Read QPS The scenario at Meituan-Dianping with the largest data size for analysis has up to 500GB writes every day. This scenario features: Stable write, with each transaction operating on 100 to 200 rows, and 60,000 writes per second. The daily write data of 300GB to 500GB, which will gradually increase to 3TB in the future. Regular read job with 5,000 QPS every 15 minutes (high frequency but a small amount of data). Irregular query (low frequency but a large amount of data). Previously, we used MySQL for data storage, but we hit capacity and performance bottlenecks—and we expect the data volume of our service to increase ten times in the future. We tested ClickHouse but found that it failed to cope well with high-frequency SQL queries in high concurrency situations, although it satisfied our demands for storage capacity and running low-frequency SQL statements. Besides, we thought that it was kind of an overkill to use ClickHouse only for full low-frequency SQL queries.Scenario 2: OLTP Workload Sensitive to Response Time In addition to offline services with massive data to analyze and query, we have lots of sharded services. Although there are multiple sharding policies used in the industry to overcome the bottlenecks of standalone machine performance and storage, these policies do have some drawbacks: No application-friendly distributed transactions. For queries across databases, the results of the queries are aggregated on the middleware, which is troublesome. If a single database is short of storage space, it needs to split again. The applications should consider the rules of data distribution, and although the middleware is applied, the problem cannot really be solved. Many of the applications and services in our environment were sharded, and some of them would soon exceed the storage capacity of a standalone machine or were in need of a new sharding policy. All of these services embodied the following characteristics: There weren’t too many SQL queries, but the execution of SQL queries was frequent. They called for strong consistency of data. Generally, some data had a time property. Exploration To overcome these challenges and lay the foundation for the future of our infrastructure, we started to explore a database solution with the following requirements: Compatibility with our existing software stack and ecosystem to minimize the migration cost and efforts. At Meituan-Dianping, MySQL was our primary database solution supporting most of our business scenarios. So compatibility with the MySQL protocol with secondary index support was a must-have feature. The solution also had to be able to deliver performant OLTP services with high concurrency. There are many product lines in Meituan-Dianping. The services have a huge volume and demand high-quality service from the storage system. We needed minimal transformation of current software stacks, such as service access, monitoring and alert system, and automated operations platform. Online scalability. Data sharding, merging, and migration need to be automatic and transparent to the online business. The solution should support shard splitting and automatic migration for data sharding, and the services should not be interrupted during data migration. Distributed transactions with strong consistency. A transaction can be executed across shards and nodes and must be strongly consistent. Service availability across data centers. Services can be automatically switched over when any data center is down. Cross-data center write into one table across data centers. Although it’s a thorny problem, supporting writing one table across data centers is an important requirement to support our current and next-phase business plan. Before diving deep into all kinds of database solutions, we did our homework, unraveling the details of suitable data storage structure and transaction algorithm through different papers, especially the following ones from Google: Spanner: Google’s Globally-Distributed Database Large-scale Incremental Processing Using Distributed Transactions and Notifications In Search of an Understandable Consensus Algorithm Online, Asynchronous Schema Change in F1 Naturally, TiDB, an open source, NewSQL, scalable hybrid transactional and analytical processing (HTAP) database built by the PingCAP team and the open source community, caught our eye. It eventually became our database of choice because of its compatibility with MySQL, cutting-edge technical architecture and foresight, and vibrant community. In the nearly three years between the release of TiDB Alpha and the end of July 2018, at least 200 users had deployed TiDB in their production environments. Many of these users are the leading enterprises in their respective industries.More specifically, compared with traditional solutions in the industry, TiDB is a perfect match for all the above requirements in that it is: Compatible with the MySQL protocol; Flexible in online scaling in and scaling out; Supports ACID transactions with strong consistency; Supports deployment and fault-tolerance across data centers and multi-node write; Handles services on TiDB just like on a standalone MySQL. Thus we began to test TiDB for these features.Evaluation To evaluate if TiDB’s performance and features can meet our requirements, regular functional and performance tests were carried out and compared to those of MySQL. One special test worth mentioning was to validate if each data center has 1 of the 3 replicas so that the crash of one …"}, {"url": "https://pingcap.com/blog/tidb-2.1-ga-Battle-tested-to-handle-an-unpredictable-world/", "title": "TiDB 2.1 GA: Battle-Tested to Handle an Unpredictable World", "content": " Today, we are proud to announce that TiDB 2.1 is ready for General Availability. TiDB is an open-source NewSQL Hybrid Transactional and Analytical Processing (HTAP) database – one of the most popular and active database products on GitHub. It is designed to provide elastic horizontal scalability, strong consistency, and high availability. TiDB is MySQL-compatible and serves as a single relational database solution for both OLTP (Online Transactional Processing) and OLAP (Online Analytical Processing) workloads.From 2.0 to 2.1 Since we launched TiDB 2.0 back in April 2018, we’ve seen an incredible pace of adoption. Hundreds of companies now use TiDB in production, serving millions of users in industries from banking, fintech, and insurance, to food delivery, ridesharing, and gaming. The largest cluster has more than 100 nodes storing 100+ TB of data. Workloads range from pure OLTP, to pure OLAP, to a hybrid mixture of both. In addition, some customers are taking advantage of TiDB’s modular architecture by just using TiKV, the distributed transactional key-value store (now a Cloud Native Computing Foundation member project) to unify data storage.We’ve also launched TiDB Academy, a series of self-paced technical training courses and certifications on TiDB and distributed databases, and TiDB Cloud, to enable more customers to easily use TiDB in any cloud environment, either as a fully-managed service delivered by PingCAP or on a public marketplace.What’s exciting isn’t just the rate of adoption, but also the multitude of real-world scenarios that TiDB is exposed to and must navigate with resilience and grace. In the last few months, TiDB has had to handle challenges like cross-data center disaster recovery, six-figure throughput requirement, massive traffic spike on Singles’ Day (one of the largest online shopping holidays in the world), hardware and network failures, and more.In short, the PingCAP team has seen a lot of unpredictable unknowns as we supported TiDB users, and the technology is battle-tested than ever before. These experiences shaped what we built in 2.1, so TiDB would always have your back and help you handle an unpredictable world.What’s New in TiDB 2.1 There are many new features, improvements, and enhancements in 2.1. To check out the full list, please see the official 2.1 GA release notes, but here are some major highlights:Smarter Optimizer The optimizer is the brain of the database. In 2.1, we’ve made significant improvements to make TiDB’s brain, its cost-based optimizer (CBO), smarter so it knows how to speed up more complex queries without human intervention. For example, the new CBO can make smarter index choices on Index Join, along with optimizations on outer table and correlated subquery, to speed up complex queries automatically.We also added additional knobs that you can turn manually as “hint”, for Join, UPDATE, DELETE, and other queries, so even if the CBO does not generate a good query plan, you can intervene to keep performance up to par and consistent.Faster Executor TiDB 2.1 includes major improvements to the execution of certain physical plans to increase performance, especially for hash aggregation and projection, by adding multi-thread execution. We also re-architected the aggregation framework to support vectorized computation.Because of these improvements, TiDB 2.1 performances much better in OLAP scenarios than 2.0, as shown in our latest TPC-H benchmark in the “Performance Benchmark” section below. This performance boost further strengthens TiDB’s capabilities as an HTAP database.New and Improved Raft The Raft consensus protocol inside TiKV is at the core of how TiDB ensures strong consistency and high availability of your data. Thus, constantly improving Raft has always been a high priority. In 2.1, we have incorporated three new Raft features: Raft PreVote – this feature pre-checks the likelihood of certain members of a Raft group becoming a Leader before voting takes place, which reduces performance fluctuation and improves stability when a TiKV node enters or returns to a cluster. Raft Learner – a Raft Learner node is a non-voting member of a Raft group. By adding a Learner first before other voting members are added, this feature improves data safety and availability, especially in a cross-data center deployment. Raft Region Merge – automatically merge many small regions into one larger region to reduce cost of cluster management, and improve overall performance and stability for large-scale clusters. Note: this feature is available in 2.1 but not enabled by default. Dynamic Statistics Update Timely update of the latest statistics to TiDB’s CBO is very important for generating the correct query plan. That’s why in 2.1, we added dynamic statistics update based on query feedback.Here’s how it works in brief: when TiDB first generates a query plan, it will do so based on existing statistics generated from previous queries to estimate the amount of data involved in the query to be processed. After this query is processed, TiDB will measure how much data was actually involved. Depending on the difference between the estimate and the actual, TiDB will automatically update the system, including both the histogram and the CM-sketch. Based on our internal testing, for a table with no previous statistics available, it takes about 10 rounds of queries worth of updates, before TiDB can generate the most optimal and efficient query plan consistently.Besides dynamic statistics update, 2.1 also adds additional support for auto analyze (see details in our documentation), so depending on the ratio of the number of modified rows to the total number of rows, TiDB can automatically execute ANALYZE to update the statistics of that table.Concurrent DDL In TiDB, all DDL is online. In previous versions, however, every DDL operation is serialized, even if DDL is performed on different tables with no relations to each other. That’s not ideal when you are doing Add Index on table A and also want to create table B, but table B creation must wait until Add Index on table A is finished.In 2.1, we have revamped TiDB’s online DDL process to completely separate Add Index with other DDL operations, so they can be executed concurrently. In TiDB, Add Index usually takes quite a long time, while other DDL operations can be completed within a few seconds, so with this improvements, most DDL operations no longer have to wait to be executed.Readable EXPLAIN and EXPLAIN ANALYZE EXPLAIN is a very important tool for debugging and diagnosing queries. Before 2.1, TiDB generally followed MySQL’s EXPLAIN format, but as queries become more complex, this format became less useful, because it doesn’t easily show each layer of subqueries to help with diagnosing issues.In 2.1, we improved TiDB’s EXPLAIN to display information in each layer of operation of a complex query in a format that’s more readable at a glance, so users can quickly spot, troubleshoot, and identify potential problems in their queries. This section of our documentation explains how the new EXPLAIN works in more detail.In addition, users can now also use EXPLAIN ANALYZE to see additional execution statistics while a query is being executed, to investigate every operation’s execution time and the amount of data involved. With these improvements, debugging and diagnosing query issues in TiDB is easier than ever before.Hotspot Scheduling Hotspot formation is one of the biggest enemies to a performant distributed database. It is also one of the most unpredictable – you never know when and how hotspots could form to create bottlenecks in your system.Thus, in this new version we did a lot of work to make TiDB smarter at detecting hotspot formation more quickly by aggregating additional system metadata to be monitored continuously. We also further optimized TiDB’s ability to execute hotspot scheduling policy – breaking up and distributing hotspots with …"}, {"url": "https://pingcap.com/weekly/2018-12-03-tidb-weekly/", "title": "Weekly update (November 26 ~ December 02, 2018)", "content": " Weekly update in TiDB Last week, we landed 72 PRs in the TiDB repository.Added Visualize the trace output using the HTTP interface Add the tidb_parse_tso built-in function Add the json_depth built-in function Close the client connection when the server waiting time exceeds wait_timeout Add a constraint propagation framework to be used by partition pruning Improved Release the datum memory after the transaction is finished Simplify the session level domain pool Record the current database information in the CRUCIAL OPERATION log Kill all connections when the server is not gracefully shut down Support PREPARE FROM @var_name Implement GoString() for TxnState to make the generated log more user-friendly Improve the privilege check for set password Return scanned rows of Coprocessor operators in EXPLAIN ANALYZE Improve the privilege check for use DB Improve the MySQL compatibility of SHOW commands Do not push down filters containing SetVar or GetVar Add a limit to constrain the maximum number of prepared statements Prevent Order By table_name.column_name for the Union statement Make round work when converting a float string to an integer string Add the correctness check for the validate_password_* system variables Fixed Fix a bug of wrong duplicate results in left outer join Set a default value for the Enum type correctly when inserting rows Fix an error message when the updated value overflows Fix a panic when dumping statistics for a dropped column Fix wrong result length of Union Prohibit the DML execution when TiDB loses connection to etcd Fix data race caused by concurrent access to do.infoHandle Fix a server hang issue when canceling the Add Index DDL job Weekly update in TiSpark Last week, we landed 2 PRs in the TiSpark repository.Fixed Fix NullPointException when counting empty tables Weekly update in TiKV and PD Last week, we landed 25 PRs in the TiKV and PD repositories.Added Add support for adding the learner operator to PD Add the week_with_mode built-in function Add the space built-in function Add the SubstringBinary2Args and SubstringBinary3Args built-in functions Support modifying TiKV’s maximum background jobs 2.1 cherry pick: Support ambiguous time Improved Collect component logs Improve tombstone command’s error message Improve tests: Move the tests directory Fix test_follower_slow_split Add more seek and seek_for_prev tests Provide the seeded KV generator Improve PD documentation: Update the API document Update the API HTML file Abandon the PD vendor directory Fixed Fix the TiKV redundant raftstore heartbeat Fix the issue of watching leader with invalid revision in PD Fix small bugs of tikv-ctl 2.1 cherry pick: Fix tikv-ctl help messages New contributors (Thanks!) docs: lucperkins tidb: alapha23 exialin leoppro pingyu "}, {"url": "https://pingcap.com/blog-cn/tidb-21-ga-release-notes/", "title": "TiDB 2.1 GA Release Notes", "content": " 2018 年 11 月 30 日,TiDB 发布 2.1 GA 版。相比 2.0 版本,该版本对系统稳定性、性能、兼容性、易用性做了大量改进。TiDB SQL 优化器 优化 Index Join 选择范围,提升执行性能 优化 Index Join 外表选择,使用估算的行数较少的表作为外表 扩大 Join Hint TIDB_SMJ 的作用范围,在没有合适索引可用的情况下也可使用 Merge Join 加强 Join Hint TIDB_INLJ 的能力,可以指定 Join 中的内表 优化关联子查询,包括下推 Filter 和扩大索引选择范围,部分查询的效率有数量级的提升 支持在 UPDATE 和 DELETE 语句中使用 Index Hint 和 Join Hint 支持更多函数下推:ABS/CEIL/FLOOR/IS TRUE/IS FALSE 优化内建函数 IF 和 IFNULL 的常量折叠算法 优化 EXPLAIN 语句输出格式, 使用层级结构表示算子之间的上下游关系 SQL 执行引擎 重构所有聚合函数,提升 Stream 和 Hash 聚合算子的执行效率 实现并行 Hash Aggregate 算子,部分场景下有 350% 的性能提升 实现并行 Project 算子,部分场景有 74% 的性能提升 并发地读取 Hash Join 的 Inner 表和 Outer 表的数据,提升执行性能 优化 REPLACE INTO 语句的执行速度,性能提升 10x 优化时间类型的内存占用,时间类型数据的内存使用降低为原来的一半 优化点查的查询性能, Sysbench 点查效率提升 60% TiDB 插入和更新宽表,性能提升接近 20 倍 支持在配置文件中设置单个查询的内存使用上限 优化 Hash Join 的执行过程,当 Join 类型为 Inner Join 或者 Semi Join 时,如果内表为空,不再读取外表数据,快速返回结果 支持 EXPLAIN ANALYZE 语句,用于查看 Query 执行过程中各个算子的运行时间,返回结果行数等运行时统计信息 统计信息 支持只在一天中的某个时间段开启统计信息自动 ANALYZE 的功能 支持根据查询的反馈自动更新表的统计信息 支持通过 ANALYZE TABLE WITH BUCKETS 语句配置直方图中桶的个数 优化等值查询和范围查询混合的情况下使用直方图估算 Row Count 的算法 表达式 支持内建函数: json_contains json_contains_path encode/decode Server 支持在单个 tidb-server 实例内部对冲突事务排队,优化事务间冲突频繁的场景下的性能 支持 Server Side Cursor 新增 HTTP 管理接口 打散 table 的 regions 在 TiKV 集群中的分布 控制是否打开 general log 在线修改日志级别 查询 TiDB 集群信息 添加 auto_analyze_ratio 系统变量控制自动 Analyze 的阈值 添加 tidb_retry_limit 系统变量控制事务自动重试的次数 添加 tidb_disable_txn_auto_retry 系统变量控制事务是否自动重试 支持使用 admin show slow 语句来获取慢查询语句 增加环境变量 tidb_slow_log_threshold 动态设置 slow log 的阈值 增加环境变量 tidb_query_log_max_len 动态设置日志中被截断的原始 SQL 语句的长度 DDL 支持 Add Index 语句与其他 DDL 语句并行执行,避免耗时的 Add Index 操作阻塞其他操作 优化 Add Index 的速度,在某些场景下速度大幅提升 支持 select tidb_is_ddl_owner() 语句,方便判断 TiDB 是否为 DDL Owner 支持 ALTER TABLE FORCE 语法 支持 ALTER TABLE RENAME KEY TO 语法 Admin Show DDL Jobs 输出结果中添加表名、库名等信息 支持使用 ddl/owner/resign HTTP 接口释放 DDL Owner 并开启新一轮 DDL Owner 选举 兼容性 支持更多 MySQL 语法 BIT 聚合函数支持 ALL 参数 支持 SHOW PRIVILEGES 语句 支持 LOAD DATA 语句的 CHARACTER SET 语法 支持 CREATE USER 语句的 IDENTIFIED WITH 语法 支持 LOAD DATA IGNORE LINES 语句 Show ProcessList 语句返回更准确信息 PD 可用性优化 引入 TiKV 版本控制机制,支持集群滚动兼容升级 PD 节点间 开启 Raft PreVote,避免网络隔离后恢复时产生的重新选举 开启 raft learner 功能,降低调度时出现宕机导致数据不可用的风险 TSO 分配不再受系统时间回退影响 支持 Region merge 功能,减少元数据带来的开销 调度器优化 优化 Down Store 的处理流程,加快发生宕机后补副本的速度 优化热点调度器,在流量统计信息抖动时适应性更好 优化 Coordinator 的启动,减少重启 PD 时带来的不必要调度 优化 Balance Scheduler 频繁调度小 Region 的问题 优化 Region merge,调度时考虑 Region 中数据的行数 新增一些控制调度策略的开关 完善调度模拟器,添加调度场景模拟 API 及运维工具 新增 GetPrevRegion 接口,用于支持 TiDB reverse scan 功能 新增 BatchSplitRegion 接口,用于支持 TiKV 快速 Region 分裂 新增 GCSafePoint 接口,用于支持 TiDB 并发分布式 GC 新增 GetAllStores 接口,用于支持 TiDB 并发分布式 GC pd-ctl 新增: 使用统计信息进行 Region split 调用 jq 来格式化 JSON 输出 查询指定 store 的 Region 信息 查询按 version 排序的 topN 的 Region 列表 查询按 size 排序的 topN 的 Region 列表 更精确的 TSO 解码 pd-recover 不再需要提供 max-replica 参数 监控 增加 Filter相关的监控 新增 etcd Raft 状态机相关监控 性能优化 优化处理 Region heartbeat 的性能,减少 heartbeat 带来的内存开销 优化 Region tree 性能 优化计算热点统计的性能问题 TiKV Coprocessor 新增支持大量内建函数 新增 Coprocessor ReadPool,提高请求处理并发度 修复时间函数解析以及时区相关问题 优化下推聚合计算的内存使用 Transaction 优化 MVCC 读取逻辑以及内存使用效率,提高扫描操作的性能,Count 全表性能比 2.0 版本提升 1 倍 折叠 MVCC 中连续的 Rollback 记录,保证记录的读取性能 新增 UnsafeDestroyRange API 用于在 drop table/index 的情况下快速回收空间 GC 模块独立出来,减少对正常写入的影响 kv_scan 命令支持设置 upper bound Raftstore 优化 snapshot 文件写入流程避免导致 RocksDB stall 增加 LocalReader 线程专门处理读请求,降低读请求的延迟 支持 BatchSplit 避免大量写入导致产生特别大的 Region 支持按照统计信息进行 Region Split,减少 IO 开销 支持按照 Key 的数量进行 Region Split,提高索引扫描的并发度 优化部分 Raft 消息处理流程,避免 Region Split 带来不必要的延迟 启用 PreVote 功能,减少网络隔离对服务的影响 存储引擎 修复 RocksDB CompactFiles 的 bug,可能影响 Lightning 导入的数据 升级 RocksDB 到 v5.15,解决 snapshot 文件可能会被写坏的问题 优化 IngestExternalFile,避免 flush 卡住写入的问题 tikv-ctl 新增 ldb 命令,方便排查 RocksDB 相关问题 compact 命令支持指定是否 compact bottommost 层的数据 Tools 全量数据快速导入工具 TiDB-Lightning 支持新版本 TiDB-Binlog 升级兼容性说明 由于新版本存储引擎更新,不支持在升级后回退至 2.0.x 或更旧版本 新版本默认开启 raft learner 功能,如果从 1.x 版本集群升级至 2.1 版本,须停机升级或者先滚动升级 TiKV,完成后再滚动升级 PD 从 2.0.6 之前的版本升级到 2.1.0 之前,最好确认集群中是否存在正在运行中的 DDL 操作,特别是耗时的 Add Index 操作 因为 2.1 版本启用了并行 DDL,对于早于 2.0.1 版本的集群,无法滚动升级到 2.1,可以选择下面两种方案: 停机升级,直接从早于 2.0.1 的 TiDB 版本升级到 2.1 先滚动升级到 2.0.1 或者之后的 2.0.x 版本,再滚动升级到 2.1 版本 "}, {"url": "https://pingcap.com/blog-cn/tidb-21-battle-tested-for-an-unpredictable-world/", "title": "TiDB 2.1:Battle-Tested for an Unpredictable World", "content": " TiDB 是由 PingCAP 开发的分布式关系型数据库,今天我们很高兴地推出 TiDB 2.1 正式版,提供更丰富的功能、更好的性能以及更高的可靠性。回顾 2.0 版本 今年 4 月份我们发布了 TiDB 2.0 版本,提升了稳定性、性能以及可运维性,这个版本在接下来的半年中得到了广泛的关注和使用。迄今为止 TiDB 已经在 数百家用户 的生产环境中稳定运行,涉及互联网、游戏、金融、保险、制造业、银行、证券等多个行业,最大集群包含数百个节点及数百 TB 数据,业务场景包含纯 OLTP、纯 OLAP 以及混合负载。另外,既有使用 TiDB 当做关系数据库的场景,也有只用 TiKV 作为分布式 Key Value 存储的场景。这几个月,在这些场景中,我们亲历了跨机房容灾需求、亲历了几十万级别的高吞吐业务、亲历了双十一的流量激增、亲历了高并发点查、高并发写入与上百行复杂 SQL 的混合负载、见到过多次的硬件/网络故障、见到过操作系统内核/编译器的 Bug。简而言之,我们的世界充满了未知,而分布式关系型数据库这样一种应用广泛、功能丰富且非常关键的基础软件,最大的困难就是这些“未知”。在 2.1 版本中,我们引入了不少新的特性来抵御这些未知,适配各种复杂的场景,提升性能和稳定性,帮助我们的用户更好地支撑复杂的业务。新特性 更全面的 Optimizer 在 2.1 版本中,我们对 TiDB 的 Cost-based Optimizer 做了改进,希望这个优化器能够处理各种复杂的 Query,尽量少的需要人工介入去处理慢 SQL。例如对 Index Join 选择索引、外表的优化,对关联子查询的优化,显著地提升了复杂 SQL 的查询效率。当然,除了自动的查询优化之外,2.1 也增加了更多的手动干预机制,比如对 Join 算子的 Hint、Update/Delete 语句的 Hint。用户可以在优化器没有指定合适的计划时,手动干预结果或者是用来确保查询计划稳定。更强大的执行引擎 在 2.1 版本中,我们对部分物理算子的执行效率进行了优化,特别是对 Hash Aggregation 和 Projection 这两个算子进行了并行化改造,另外重构了聚合算子的运行框架,支持向量化计算。得益于这些优化,在 TPC-H 这种 OLAP 的测试集上,2.1 比 2.0 版本有了显著的性能提升,让 2.1 版本更好的面对 HTAP 应用场景。Raft 新特性 在 2.1 版本中,我们引入了 Raft PreVote、Raft Learner、Raft Region Merge 三个新特性: PreVote 是在 Raft Group Member 发起投票之前,预先检查是否能被其他成员所支持,以避免集群中被网络隔离的节点重新接入集群中的时候引发性能抖动,提升集群稳定性。2.1 版本已经支持 PreVote 功能,并默认打开。 Learner 是只同步数据不参与投票的 Raft Group Member。在新加副本的时候,首先增加 Learner 副本,以避免添加副本过程中,部分 TiKV 节点故障引发丢失多数副本的情况发生,以提升集群的安全性。2.1 版本已经支持 Learner 功能,并默认打开。 Region Merge 用于将多个过小的 Region 合并为一个大的 Region,降低集群的管理成本,对于长期运行的集群以及数据规模较大的集群的性能、稳定性有帮助。2.1 版本已经支持 Region Merge 功能,尚未默认打开。 这些新特性的引入,有助于提升存储集群尤其是大规模集群的稳定性和性能。自动更新统计信息 统计信息的及时性对查询计划的正确性非常重要。在 2.1 版本中,我们提供了基于 Query Feedback 的动态增量更新机制。在制定查询计划时,会根据现有的统计信息估算出需要处理的数据量;在执行查询计划时,会统计出真实处理的数据量。TiDB 会根据这两个值之间的差距来更新统计信息,包括直方图和 CM-Sketch。在我们的测试中,对于一个完全没有统计信息的表,经过十轮左右的更新,可以达到统计信息基本稳定的状态。这对于维持正确的查询计划非常重要。除了动态增量更新之外,我们对自动全量 Analyze 也提供了更多支持,可以通过 系统变量 指定做自动 Analyze 的时间段。并行 DDL TiDB 所有的 DDL 操作都是 Online 进行,不过在 2.0 以及之前的版本中,所有的 DDL 操作都是串行执行,即使 DDL 所操作的表之间没有关联。比如在对 A 表 Add Index 时候,想创建一个 B 表,需要等待 Add Index 操作结束。这在一些场景下对用户使用造成了困扰。在 2.1 版本中,我们对 DDL 流程进行拆分,将 Add Index 操作和其他的 DDL 操作的处理分开。由于在 TiDB 的 DDL 操作中,只有 Add Index 操作需要去回填数据,耗时较长,其他的 DDL 操作正常情况下都可以在秒级别完成,所以经过这个拆分,可以保证大多数 DDL 操作能够不需要等待,直接执行。Explain 和 Explain Analyze Explain 对于理解查询计划至关重要,2.1 之前的版本,TiDB 追随 MySQL 的 Explain 输出格式来展示查询计划。但是当 SQL 比较复杂时,MySQL 的格式并不利于展示算子之间的层级关系,不利于用户定位问题。2.1 版本中,我们使用缩进来展示算子之间的层级关系,对每个算子的详细信息也做了优化,希望整个查询计划一目了然,帮助用户尽快定位问题。这篇文档 可以帮助用户了解 TiDB 的查询计划。用户除了通过 Explain 语句查看查询计划之外,在 2.1 版本中还可以通过 Explain Analyze 语句查看语句的运行时信息,包括每个算子运行时的处理时间以及处理的数据量。这样可以通过实际的运行结果,拿到更加精确的信息。热点调度 热点是分布式系统最大的敌人之一,并且用户的业务场景复杂多变,让热点问题捉摸不定,也是最狡猾的敌人。2.1 版本中,我们一方面增强热点检测能力,尽可能详细地统计系统负载,更快的发现热点;另一方面优化热点调度策略,用尽可能小的代价,尽快地打散热点。同时我们也提供了手动分裂 Region 的接口,让用户在特殊场景下将单点瓶颈手动分裂开,再由 PD 进行负载均衡。高效的 GC 机制 2.1 版本对 GC(垃圾回收) 模块进行优化。一方面减少对线上的写入的影响,另一方面加快了空间回收速度。在内部测试场景中,删除一个 1TB 的表,新的 GC 机制能够在 10 秒内回收 99% 左右的空间。更好的性能 OLTP 我们针对 OLTP 场景中,点查占多数的特点进行了针对性的优化。当通过 Unique Key 或者 Primary Key 进行数据访问时,在优化器和执行引擎中都做了改进,使得语句的执行效率更高,通过 2.1 和 2.0 版本的 Sysbench 对比 可以看到,点查性能提升 50%。OLAP 发布 2.0 的时候,我们同时发布了在 TPC-H Scale 50 的场景中 2.0 和 1.0 的对比结果。其中大多数 Query 都有数量级的提升,部分 Query 在 1.0 中跑不出结果,在 2.0 中可以顺利运行。不过对于 Query17 和 Query18,运行时间依然很长。我们在相同的场景下,对 2.1 和 2.0 进行了 对比测试。从下图可以看到(纵坐标是 Query 的响应时间,越低越好),之前的两个慢 Query 的运行时间大幅缩短,其他的 Query 也有一定程度的提升。这些提升一方面得益于查询优化器以及执行引擎的改进,另一方面 得益于 TiKV 对连续数据扫描的性能优化。完善的生态工具 为了让用户更方便的使用 TiDB,我们提供了三个工具: TiDB Lightning 用于将全量数据导入到 TiDB 中,这个工具可以提升全量数据导入速度,目前内部测试场景中,一小时可以导入 100GB 数据。 TiDB Binlog 用于将 TiDB 中的数据更新实时同步到下游系统中,可以用于做主从集群同步或者是将 TiDB 中的数据同步回 MySQL。 TiDB DM(Data-Migration)用于将 MySQL/MariaDB 中的数据通过 Binlog 实时同步到 TiDB 集群中,并且提供 Binlog 数据转换功能,可以将 Binlog 中的表/库名称进行修改,或者是对数据内容本身做修改和裁剪。 上述三个工具可以将 TiDB 和周边的系统打通,既能将数据同步进 TiDB,又可以将数据同步出来。所以无论是迁移、回退还是做数据热备,都有完整的解决方案。Open Source Community 我们相信战胜“未知”最好的武器就是社区的力量,基础软件需要坚定地走开源路线。为了让社区更深入的了解 TiDB 的技术细节并且更好地参与到项目中来,我们今年已经完成超过 20 篇源码阅读文章,项目的设计文档(TiDB 和 TiKV)已经在 GitHub 上面公开出来,项目的开发过程也尽量通过 Github Issue/Project 向社区展示。一些 Feature 设计方案的讨论也会通过在线视频会议的方式方便社区参与进来,这里 可以看到会议安排。从 TiDB 2.0 版发布到现在的半年多时间,TiDB 开源社区新增了 87 位 Contributor,其中 杜川 成为了 TiDB Committer,他已经贡献了 76 次 PR,还有一些活跃的 Contributor 有希望成为下一批 Committer。在这里我们对社区贡献者表示由衷的感谢,希望更多志同道合的人能加入进来,也希望大家在 TiDB 这个开源社区能够有所收获!"}, {"url": "https://pingcap.com/weekly/2018-11-26-tidb-weekly/", "title": "Weekly update (November 19 ~ November 25, 2018)", "content": " Weekly update in TiDB Last week, we landed 46 PRs in the TiDB repository.Added Add the http API to get database and table information Propose the table partition design Support creating hash partitioned tables Improved Add missing columns for information_schema.files Impose user authentication for unix socket connections Redesign the trace statement with JSON output Support JSON as the return type for the case expression Preallocate the columns array in MutRow to avoid array resizing Support subqueries in the Do statement Add the memory guard to prevent OOM caused by the plan cache Clean up the plan cache entry in the Deallocate statement Support ADMIN CHECK TABLE/ADMIN CHECK INDEX using specified tidb_snapshot Fixed Fix incorrect privilege check for the UPDATE statement Fix the bootstrap error when the SQL mode is set to ANSI Make sure goroutines of HashJoin exit before its Close returns Remove partition IDs for partition tables in DROP DATABASE Fix the panic caused by EOF when Coprocessor is in the streaming mode Weekly update in TiSpark Last week, we landed 2 PRs in the TiSpark repository.Added Support raw partition Read Weekly update in TiKV and PD Last week, we landed 20 PRs in the TiKV and PD repositories.Added Support interactive Region scan in pd-ctl Add the history index to sync when stream is established Add normal index scan benchmarks Improved Improve Region key print Move unrelated benchmarks into individual directories Check the conf version for split Fixed Fix a deadlock in GetOpInfluence Fix the issue that configurations cannot be set to zero values Fix go mod tidy in PD New contributor (Thanks!) docs-cn: bugwz"}, {"url": "https://pingcap.com/weekly/2018-11-19-tidb-weekly/", "title": "Weekly update (November 12 ~ November 18, 2018)", "content": " Weekly update in TiDB Last week, we landed 54 PRs in the TiDB repository.Added Add a variable max-txn-time-use to make maxTxnTimeUse configurable Improved Validate the variable value when you set tx_isolation Refine HashJoinExec of a specific JoinType for the nil outer/inner case Add SQL type labels to commit and retry logs Delay initializing Txn() to the statements that really need it Adjust the TIDB_INLJ Hint to specify the inner table Support the NO_AUTO_CREATE_USER SQL mode Validate specified values for the enum/set type column in DDL Fixed Clone AggDesc before modifying its Mode in AggDesc.Split Close the child executor before calling ExplainExec.explain.RenderResult() Escape backquotes in identifiers in SHOW CREATE TABLE properly Convert Zero input correctly for column type year Eliminate extra columns introduced by OrderBy upon Union Fix the error caused by different lengths between embedded and outer OrderByItems Consider null for comparing operators in expression rewriting Impose specified OrderBy on the union result of TableDual Use Column.UniqueID in conditionChecker of ranger Weekly update in TiSpark Last week, we landed 3 PRs in the TiSpark repository.Added Add the partition information in TiTableInfo Fixed Fix isolation level settings Weekly update in TiKV and PD Last week, we landed 29 PRs in the TiKV and PD repositories.Added Add a memory BTreeEngine for the local test Support reversing raw_scan and raw_batch_scan in storage Add the ldb argument in tikv-ctl to support the rocksdb command Support more functions in Coprocessor: ToBase64 and FromBase64 Substring2Args and Substring3Args DayName, DayOfMouth, DayOfWeek and DayOfYear Improved Use a block strategy for the file logger Use lifetime to manage the start and the stop of Storage Optimize ingesting snapshots Avoid large Write batch during the GC process of Raft logs Omit some logs about compact log Check the store state before creating operators Fixed Fix the issue about parsing ambiguous time New contributor (Thanks!) tikv: kamijin-fanta"}, {"url": "https://pingcap.com/blog/lease-read/", "title": "How TiKV Uses "Lease Read" to Guarantee High Performances, Strong Consistency and Linearizability", "content": " TiKV, an open source distributed transactional key-value store (also a Cloud Native Computing Foundation member project), uses the Raft consensus algorithm to ensure strong data consistency and high availability. Raft bears many similarities to other consensus algorithms like Paxos in its ability to ensure fault-tolerance and its performance implementations, but generally easier to understand and implement. While our team has written extensively on how Raft is used in TiKV (some examples: Raft in TiKV, the Design and Implementation of Multi-raft, Raft Optimization), one topic we haven’t discussed is when stale read happens due to a brain split within a Raft group, and the old Raft leader is not aware that a new leader is elected, what should we do? This post discusses three different approaches to this problem: Raft Log Read, ReadIndex Read, and Lease Read, and why TiKV adopts the Lease Read approach.Raft Log Read Because Raft is a consensus algorithm that is designed for distributed environments, one way we can resolve the stale read issue is by using the Raft process itself. Inside Raft, we can make the read request go through the Raft log. After the log is committed, we can then read data from the state machine during apply. This approach helps us make sure that the data we read is strongly consistent.However, one significant drawback is each read request needs to go through the entire Raft process, which could lead to severe performance issues, thus very few projects apply this approach.ReadIndex Read ReadIndex Read is a different approach and was originally proposed in the Raft paper. We know that inside Raft, a Region can be in 1 of 3 states: leader, candidate and follower. Any Raft write operation must go through the leader. Only when the leader replicates the corresponding Raft log to a majority of the Regions inside the same Raft group will we consider this write successful.Simply put, as long as the leader really is the leader, then we can directly read data from it. But how do we confirm that fact while handling the read request? Here’s the process that ReadIndex Read will go through: Record its current commit index into the local variable ReadIndex. Send a heartbeat message to other Regions. If the majority of Regions replies with the corresponding heartbeat response, then the leader confirms its state. Wait for the execution of its state machine until the apply index equals to or exceeds ReadIndex. By then, the data can be read consistently. Execute the read request and return the result to the client. You can see that unlike reading through the Raft log, ReadIndex Read uses heartbeats to make leader confirm its state, which is much easier. Although there is still network overhead for the heartbeats, the performance is better than the Raft Log Read.Lease Read In TiKV, we adopt a third and optimized way – Lease Read – another approach introduced in the Raft paper. When the leader sends a heartbeat, it records a timestamp start. When the majority of Regions in the group reply the heartbeat response, we think that the lease validity of the leader can last till start + election timeout / clock drift bound.The Lease Read implementation of TiKV is the same as that in the Raft paper in principle, with some optimizations included. In TiKV, the lease is updated through write operations instead of heartbeats. Since any write operation goes through Raft log, when we propose this write request, we record the current timestamp as start and wait for the corresponding apply before renewing the leader’s lease. A couple of additional implementation details worth noting: The election timeout is 10 seconds by default and we use the fixed max time value of 9 seconds to renew the lease. So even in case of split brain, we can guarantee that the older leader lease is expired when the next leader is elected. We use the monotonic raw clock instead of the monotonic clock. The reason is that the rate of the latter will be influenced by factors like NTP, even though it will not have the time jump back problem. With this approach the response to the client within the lease is initiated by the leader’s state machine. As long as the leader’s state machine is strongly consistent, so will the data that is read from that leader, regardless of when the read occurs."}, {"url": "https://pingcap.com/weekly/2018-11-12-tidb-weekly/", "title": "Weekly update (November 05 ~ November 11, 2018)", "content": " Weekly update in TiDB Last week, we landed 54 PRs in the TiDB repository.Added Provide the ADMIN SHOW NEXT_ROW_ID SQL interface Propose the VIEW design Implement outer join elimination in the logical optimization Improved Distinguish internal/general SQL statements for transaction related metrics Recover the panic in parallel aggregation and projection Add a variable to control the maximum length of the logged query string Add a variable to control whether writing _tidb_rowid is allowed Return an error on check for the missing user Support the plan cache for prepared INSERT/DELETE/UPDATE statements Add a variable to control the slow log threshold Ensure scan of tikv-client is not out of range Fixed Fix the bug of comparison when a row contains NULL Make affected rows of INSERT consistent with MySQL Correct the field name when IfNull is eliminated Fix the unexpected error for ORDER BY in UNION statements Fix a deadlock in the latch scheduler Fix a bug of converting duration to timestamp in the statistics component Return NULL for the values function in the non-INSERT statement Change the default charset and collation from utf8 utf8_bin to utf8mb4 utf8mb4_bin Weekly update in TiSpark Last week, we landed 3 PRs in the TiSpark repository.Added Add resolveLock implementation Fixed Fix the incorrect tso request generated by PDClient Weekly update in TiKV and PD Last week, we landed 28 PRs in the TiKV and PD repositories.Added Support the Time function in Coprocessor Improved Add sanity check for the count field of a request Record start_ts in the write conflict error Add the end_key limit to the kv_scan interface Fixed Fix the issue about the regions/check API Fix ScheduleConfig data race New contributors (Thanks!) tidb: lindali0331tidb-operator: kirinsedocs-cn: bianxindong ppiao "}, {"url": "https://pingcap.com/blog-cn/tidb-community-guide-1/", "title": "TiDB 开源社区指南(上)", "content": " 本系列文章旨在帮助社区开发者了解 TiDB 项目的全貌,更好的参与 TiDB 项目开发。大致会分两个角度进行描述: 从社区参与者的角度描述如何更好的参与 TiDB 项目开发; 从 PingCAP 内部团队的角度展示 TiDB 的开发流程,包括版本规划、开发流程、Roadmap 制定等。 希望通过一内一外两条线的描述,读者能在技术之外对 TiDB 有更全面的了解。本篇将聚焦在社区参与者的角度进行描述,也就是“外线”。了解 TiDB 参与一个开源项目第一步总是了解它,特别是对 TiDB 这样一个大型的项目,了解的难度比较高,这里列出一些相关资料,帮助 newcomers 从架构设计到工程实现细节都能有所了解: Overview How we build TiDB TiDB 源码阅读系列文章 Deep Dive TiKV (Work-In-Process) 当然,最高效地熟悉 TiDB 的方式还是使用它,在某些场景下遇到了问题或者是想要新的 feature,去跟踪代码,找到相关的代码逻辑,在这个过程中很容易对相关模块有了解,不少 Contributor 就是这样完成了第一次贡献。 我们还有一系列的 Infra Meetup,大约两周一次,如果方便到现场的同学可以听到这些高质量的 Talk。除了北京之外,其他的城市(上海、广州、成都、杭州)也开始组织 Meetup,方便更多的同学到现场来面基。发现可以参与的事情 对 TiDB 有基本的了解之后,就可以选一个入手点。在 TiDB repo 中我们给一些简单的 issue 标记了 for-new-contributors 标签,这些 issue 都是我们评估过容易上手的事情,可以以此为切入点。另外我们也会定期举行一些活动,把框架搭好,教程写好,新 Contributor 按照固定的模式即可完成某一特性开发。当然除了那些标记为 for-new-contributors 的 issue 之外,也可以考虑其他的 issue,标记为 help-wanted 标签的 issue 可以优先考虑。除此之外的 issue 可能会比较难解决,需要对 TiDB 有较深入的了解或者是对完成时间有较高的要求,不适合第一次参与的同学。当然除了现有的 issue 之外,也欢迎将自己发现的问题或者是想要的特性提为新的 issue,然后自投自抢 :) 。 当你已经对 TiDB 有了深入的了解,那么可以尝试从 Roadmap 上找到感兴趣的事项,和我们讨论一下如何参与。讨论方案 找到一个感兴趣的点之后,可以在 issue 中进行讨论,如果是一个小的 bug-fix 或者是小的功能点,可以简单讨论之后开工。即使再简单的问题,也建议先进行讨论,以免出现解决方案有问题或者是对问题的理解出了偏差,做了无用功。但是如果要做的事情比较大,可以先写一个详细的设计文档,提交到 docs/design 目录下面,这个目录下有设计模板以及一些已有的设计方案供你参考。一篇好的设计方案要写清楚以下几点: 背景知识 解决什么问题 方案详细设计 对方案的解释说明,证明正确性和可行性 和现有系统的兼容性 方案的具体实现  用一句话来总结就是写清楚“你做了什么,为什么要做这个,怎么做的,为什么要这样做”。如果对自己的方案不太确定,可以先写一个 Google Doc,share 给我们简单评估一下,再提交 PR。提交 PR 按照方案完成代码编写后,就可以提交 PR。当然如果开发尚未完成,在某些情况下也可以先提交 PR,比如希望先让社区看一下大致的解决方案,这个时候请将 PR 标记为 WIP。对于 PR 我们有一些要求: 需要能通过 make dev 的测试,跑过基本的单元测试; 必须有测试,除非只是改动文档或者是依赖包,其他情况需要有充足的理由说明没有测试的原因; 代码以及注释的质量需要足够高,这里 有一些关于编码风格和 commit message 的 guide; 请尽可能详细的填写 PR 的描述,并打上合适的 label。 对于 PR 的描述,我们提供了一个模板,希望大家能够认真填写,一个好的描述能够加速 PR 的 review 过程。通过这个模板能够向 reviewers 以及社区讲明白: 这个PR 解决什么问题:相关的问题描述或者是 issue 链接; 如何解决:具体的解决方法,reviewers 会根据这里的描述去看代码变动,所以请将这一段写的尽可能详细且有帮助; 测试的情况; 其他相关信息(如果需要):benchmark 结果、兼容性问题、是否需要更新文档。 最后再说几句测试,正确性是数据库安身立命之本,怎么强调测试都不为过。PR 中的测试不但需要充足,覆盖到所做的变动,还需要足够清晰,通过代码或者注释来表达测试的目的,帮助 reviewer 以及今后可能变动/破坏相关逻辑的人能够容易的理解这段测试。一段完善且清晰的测试也有利于让 reviewer 相信这个 Patch 是正确的。PR review PR review 的过程就是 reviewer 不断地提出 comment,PR 作者持续解决 comment 的过程。每个 PR 在合并之前都需要至少得到两个 Committer/Maintainer 的 LGTM,一些重要的 PR 需要得到三个,比如对于 DDL 模块的修改,默认都需要得到三个 LGTM。Tips: 提了PR 之后,可以 at 一下相关的同学来 review; Address comment 之后可以 at 一下之前提过 comment 的同学,标准做法是 comment 一下 “PTAL @xxx”,这样我们内部的 Slack 中可以得到通知,相关的同学会受到提醒,让整个流程更紧凑高效。 与项目维护者之间的交流 目前标准的交流渠道是 GitHub issue,请大家优先使用这个渠道,我们有专门的同学来维护这个渠道,其他渠道不能保证得到研发同学的及时回复。这也是开源项目的标准做法。无论是遇到 bug、讨论具体某一功能如何做、提一些建议、产品使用中的疑惑,都可以来提 issue。在开发过程中遇到了问题,也可以在相关的 issue 中进行讨论,包括方案的设计、具体实现过程中遇到的问题等等。最后请大家注意一点,除了 pingcap/docs-cn 这个 repo 之外,请大家使用英文。更进一步 当你完成上面这些步骤的之后,恭喜你已经跨过第一个门槛,正式进入了 TiDB 开源社区,开始参与 TiDB 项目开发,成为 TiDB Contributor。如果想更进一步,深入了解 TiDB 的内部机制,掌握一个分布式数据库的核心模块,并能做出改进,那么可以了解更多的模块,提更多的 PR,进一步向 Committer 发展(这里 解释了什么是 Committer)。目前 TiDB 社区的 Committer 还非常少,我们希望今后能出现更多的 Committer 甚至是 Maintainer。从 Contributor 到 Committer 的门槛比较高,比如今年的新晋 Committer 杜川同学,在成为 Committer 的道路上给 tidb/tikv 项目提交了大约 80 个 PR,并且对一些模块有非常深入的了解。当然,成为 Committer 之后,会有一定的权利,比如对一些 PR 点 LGTM 的权利,参加 PingCAP 内部的技术事项、开发规划讨论的权利,参加定期举办的 TechDay/DevCon 的权利。目前社区中还有几位贡献者正走在从 Contributor 到 Committer 的道路上。"}, {"url": "https://pingcap.com/weekly/2018-11-05-tidb-weekly/", "title": "Weekly update (October 29 ~ November 04, 2018)", "content": " Weekly update in TiDB Last week, we landed 49 PRs in the TiDB repository.Added Propose the window function design Introduce a new join reorder framework in the DP-subset algorithm Add a document about online DDL architecture Improved Try PointGetPlan when the plan cache is enabled Make a query plan containing non-deterministic functions cacheable Add validation check when setting the max_allowed_packet system variable Use module of Go 1.11 for dependency management Impose check when adding the foreign key Eliminate ifnull() if the argument can never be null Convert IN subquery to Aggregation with the inner join Fixed Specially handle HOUR in date arithmetic functions Treat _tidb_rowid conditions of index scan as index filters Avoid using columnEvaluator for Projection built by buildProjtion4Union Fix selectivity estimation inaccuracy for non-integer primary key Fix wrong index resolution for PhysicalIndexReader Fix a panic caused by the wrong default value for table information_schema.profiling Fix a panic caused by nil Backoff.vars Fix a panic caused by type mismatch in SHOW COLUMNS Refine ResolveIndices for sequential Projections to avoid panics Fix a panic caused by type mismatch in UPDATE Avoid precision loss when casting JSON to decimal Reset the statement context before PREPARE to avoid panics Change the privilege component to use Auth* portion of identity Weekly update in TiSpark Last week, we landed 5 PRs in the TiSpark repository.Added Support cache table commands Weekly update in TiKV and PD Last week, we landed 5 PRs in the TiKV and PD repositories.Added Support the SubstringIndex function in Coprocessor Improved Make pdctl escape the key before querying the corresponding Region New contributors (Thanks!) tidb: iamzhoug37 imiskolee docs: ppiao docs-cn: exialin tidb-operator: anywhy "}, {"url": "https://pingcap.com/blog/architecture-and-use-cases-of-a-cloud-native-newsql-database/", "title": "TiDB: Architecture and Use Cases of A Cloud-Native NewSQL Database", "content": " TiDB is an open source cloud-native distributed database that handles hybrid transactional and analytical processing (HTAP) workloads–a member of the NewSQL class of databases that’s reinventing how a relational database can be designed, built, and deployed at massive scale. (“Ti” for those of you wondering stands for “Titanium”.) Since PingCAP started building TiDB just three and a half years ago, it has become one of the fastest-growing databases in the world, supported by a strong, vibrant community (at time of writing: 15,000+ GitHub stars, 200+ contributors, 7200+ commits, 2000+ forks). TiDB was recently recognized by InfoWorld’s Bossie Awards 2018, as one of the best open source software projects in the data storage and analytics space.In this article, I’ll walk through the core features and architectural design of TiDB, the three main use cases that TiDB is fulfilling for its 300+ production users, and a preview of its cloud-based product offering.Core Features TiDB’s core features include elastic horizontal scalability, distributed transactions with ACID guarantee, high availability, and real-time analysis on live transaction data. While these terms are commonly thrown out as marketing speaks in the database industry, they are actually difficult technical challenges that our team and community have been working hard on since day 1. Here’s how TiDB’s unique architecture and implementation deliver on these features.The entire TiDB platform has the following components: TiDB: stateless SQL layer that is MySQL compatible, built in Go TiKV: distributed transactional key-value store (now a Cloud Native Computing Foundation (CNCF) project), built in Rust TiSpark: an Apache Spark plugin that works within the TiDB platform and can connect to TiKV or another specialized, columnar storage engine (something we are working on…stay tuned.) Placement Driver (PD): a metadata cluster powered by etcd that manages and schedules TiKV TiDB Platform Architecture How they work together TiKV is the foundational layer, where all the data is persistent, broken up into smaller chunks (we call them “Region”), and automatically replicated and made strongly consistent by executing the Raft consensus protocol. Working with PD, it can replicate data across nodes, datacenters, and geographical locations. It can also dynamically remove hotspots as them form, and split or merge Regions to improve performance and storage usage. We implement range-based sharding inside TiKV instead of hash-based, because our goal from the beginning is to support a full-featured relational database, thus must support various types of Scan operations, like Table Scan, Index Scan, etc.TiDB’s stateless SQL layer handles 100% of your Online Transaction Processing (OLTP) workloads and 80% of the common ad-hoc Online Analytical Processing (OLAP) workloads, with constant performance improvements (see our latest TPC-H benchmarks). This stateless SQL layer leverages the distributed nature of TiKV to execute parallel processing via a Coprocessor layer, by pushing down partial queries to different TiKV nodes simultaneously to retrieve results; that’s why our performance is so good!For more complex OLAP workloads, say constantly iterative analysis for training machine learning models or real-time business intelligence gathering throughout the day, TiSpark fills the void by drawing data directly from TiKV.The interface is good ol’ SQL that many people know, love, and miss. (TiDB speaks MySQL, TiSpark exposes SparkSQL).Modular, Cloud-Native Architecture As you might have noticed, the entire TiDB platform’s design is modularized–all components are in separate code bases and are loosely coupled. A user can deploy the entire TiDB platform as a complete package (most of our users do!), or just parts of it depending on their needs. This modular architecture is intentional: it empowers users to have maximum flexibility and fits perfectly with the standard of a cloud-native architecture (per the CNCF’s official definition of “cloud-native”, cloud-native techniques are ones that “enable loosely coupled systems that are resilient, manageable, and observable”).As a TiDB user, you can scale your stateless SQL server or TiSpark (i.e. your compute resources) out or in independent of scaling TiKV (i.e. your storage capacity), so you can make the most out of the resources you are consuming to fit your workloads. You can almost analogize TiDB stateless SQL servers as a microservice that sits on top of TiKV, which is a stateful application where your data is persisted. This design also makes isolating bugs easier, and rolling upgrades and maintenance quicker and less disruptive.One initial trade-off is some added complexity to deployment and monitoring–there are just more pieces to keep track of. However, with the rise of Kubernetes and the Operator pattern (pioneered by CoreOS), deploying and managing TiDB is simple, straightforward, and increasingly automated.That’s why we built TiDB Operator, and recently open-sourced it, so you can deploy, scale, upgrade, and maintain TiDB in any cloud environment–public, private or hybrid. TiDB installs Prometheus and Grafana by default, so monitoring comes “out of the box”. (Here’s a tutorial on TiDB Operator.) Sample Grafana Dashboard Monitoring a TiDB Deployment Ultimately, flexible scalability for your technical needs is crucial for business success. It’s the difference between becoming the next Facebook versus Friendster. That’s the value that TiDB brings to our users, so they can focus on delivering the best product for their users.And the three main use cases where TiDB shines are: MySQL Scalability, HTAP real-time analytics, and unifying data storage.Use Case 1: MySQL Scalability for explosive business growth Because TiDB speaks MySQL–compatible with both its wire protocol and ecosystem tools like MyDumper and MyLoader–it’s a natural fit for MySQL users who have trouble scaling. To be clear, TiDB is not a replacement of MySQL; it complements MySQL. MySQL is still a great option as a single instance database, so if your data size or workload is small, stick with MySQL. But, as our co-founder and CTO Ed Huang talked about in another post, if you are scratching your heads thinking about the following: Considering how to replicate, migrate, or scale your database for extra capacity; Looking for ways to optimize your existing storage capacity; Getting concerned about slow query performance; Researching middleware scaling solutions or implementing manual sharding policy; That’s the right time to think about using TiDB, which takes care of all these concerns out of the box for you. That’s why Mobike, one of the world’s largest dockless bikesharing platforms, uses TiDB (read case study here). Operating 9 million smart bikes in 200+ cities serving 200 million users, it’s not hard to imagine the scaling bottlenecks their team was experiencing when their business took off like wildfire. Luckily, TiDB came to the rescue and by deploying TiDB along with PingCAP’s suite of enterprise tools like Syncer, which automatically syncs MySQL masters with a TiDB cluster (almost acting like MySQL slaves), the architects and infrastructure engineers at Mobike can now rest easy, knowing that their data management capacity will just grow as the business grows.Another key differentiator between TiDB and other MySQL compatible databases is that we built TiDB’s MySQL layer from scratch, instead of just using a MySQL fork which is what databases like AWS’s Aurora have done. We chose the hard way, because MySQL is a 20-year-plus technology that was never meant for and thus cannot take advantage of the power of a distributed system. For example, MySQL cannot generate query plans that push down partial queries into multiple machines simultaneously to do parallel processing, but TiDB can! TiDB’s …"}, {"url": "https://pingcap.com/blog/announcing-tidb-cloud-managed-as-a-service-and-in-the-marketplace/", "title": "Announcing TiDB Cloud, Managed as a Service and in the Marketplace", "content": " Today, we are excited to announce that TiDB Cloud is now available for public preview. It is a suite of product offerings that enables customers to easily use TiDB in any cloud environment, either as a fully-managed service delivered by PingCAP or on a self-served marketplace. TiDB is the first open source, NewSQL, hybrid transactional and analytical processing (HTAP) database in the market that’s available in either public, private, or hybrid cloud setting. TiDB Platform Architecture Product Offerings The TiDB Cloud offerings we are launching today have two options: PingCAP Managed TiDB Cloud (public preview): available on any public or private cloud. This is a comprehensive, fully-managed solution, where the PingCAP cloud team will deliver a full suite of services and enterprise-grade tools to deploy, manage, maintain, backup, and upgrade a TiDB deployment for you. This option is for companies who want to get the most value out of TiDB for their specific use cases, with the least amount of operational overhead and cost. TiDB on GCP Marketplace: available on Google Cloud Platform (GCP) Marketplace using Google Kubernetes Engine (GKE). This is a production-ready standard TiDB deployment that can be launched with just a few clicks on the GCP Marketplace. (We will bring this option to more public cloud marketplaces in the near future.) This option is simple, low-cost, and uses GCP’s persistent disks. Key Features Always Online: With TiDB Cloud, your database is always online, 24 / 7, with no need to schedule downtime for maintenance. While online, it supports rolling upgrades, online DDL, cluster resizing, and automatic data rebalancing with hotspots removal. Flexible Scaling: TiDB has a cloud-native architectural design, where the stateless computing resources (TiDB, TiSpark) and the stateful storage layer (TiKV) are loosely coupled and can be scaled out (or in) depending on your use case and workloads. Thus, in TiDB Cloud, you have the ultimate pay-per-usage control over your database resources. Cross-Cloud Experience: By leveraging Kubernetes and the TiDB Operator, TiDB Cloud delivers a consistent user experience and simple portability between different cloud platforms. There’s no cloud vendor lock-in; total independence. Cloud Native, Customer First As a NewSQL database with a cloud-native architecture, the cloud is TiDB’s natural habitat. In the future, more and more of our services, tools, and core technology innovation will be focused on making TiDB a joy to use in the cloud. As the core team building TiDB from day 1, PingCAP has accumulated a wealth of expertise in architecting, tuning, and operating a distributed database in the cloud. We are ready to deliver that expertise and value to all our customers, from e-commerce platforms to SaaS solutions to social networks. We will work hard to provide a world-class infrastructure solution that will set our customers up to become the next big thing. You can sign up for TiDB Cloud now, and we look forward to delivering TiDB in your favorite cloud environment."}, {"url": "https://pingcap.com/blog-cn/pingcap-university-tidb-dba-plan/", "title": "PingCAP University · TiDB DBA 官方培训认证计划启动", "content": " 伴随着产品的成熟,TiDB 在越来越多样化的应用场景中落地。在落地过程中,大家遇到问题会寻求官方的答疑和支持,但由于咨询量很大,我们有时无法及时响应。因此,为了赋能社区,提升社区用户满意度,避免因测试用户过多官方无法及时响应的问题,同时打造活跃的 TiDB 技术社区,培养熟悉分布式系统、能独立运维 TiDB 的一流 NewSQL 人才,我们宣布正式成立 PingCAP University。PingCAP University 是 PingCAP 官方设立的对企业和个人进行 TiDB 全线产品培训并认证的部门,其培训讲师团队由来自 PingCAP 官方的资深解决方案架构师、顶尖核心技术研发工程师和高级资深 TiDB DBA 组成,拥有丰富且专业的 TiDB 实践经验和培训经验。PingCAP University 也在今天正式启动 TiDB DBA 官方培训认证计划。通过该培训认证计划,大家可以: 深度理解 TiDB 架构、原理及最佳实践,具备独立部署、运维和调优 TiDB 的能力 提升分布式计算和存储领域的技术前沿视野 获得来自 PingCAP 官方的专业技术能力认可,提升个人技术竞争力 培训特色 理论与实践结合,强调动手能力(实践超过 50%),提供累计 4 个半天实战 课程滚动更新,包含大量前沿技术解读及实践分享 TiDB DBA 官方培训认证总览 初级 TiDB DBA:PCTA(PingCAP Certified TiDB Associate)培训及认证 高级 TiDB DBA:PCTP(PingCAP Certified TiDB Professional) 培训及认证 培训及考试安排 PCTA:线上培训及考试 PCTP:线下小班集中培训及考试,时间地点由 PingCAP 统一安排 垂询及报名方式 点击 这里 直接填写报名信息 或联系您的客户总监 或发送邮件至 university-cn@pingcap.com 交流 P.S. 2018 年 11 月 30 日前报名还有【官方技术支持服务礼包】赠送~"}, {"url": "https://pingcap.com/meetup/meetup-20181030-no78/", "title": "【Infra Meetup No.78】Bigdata@Bilibili & Chaos Practice in TiDB", "content": " 上周六在上海举办的 Infra Meetup No.78 上,B 站数据平台技术经理薛赵明老师和我司首架唐刘老师带来了精彩分享,以下是视频&文字回顾~##《B 站大数据建设实践》 视频 | Infra Meetup No.78 - 薛赵明 - B 站大数据建设实践 PPT 下载链接 本次分享薛赵明老师主要介绍了 B 站在大数据建设方面的历程及不同时期做的选择和其中犯的错误。主要涉及我们在存储、调度、计算、分布式队列方面的一些技术选型。我们在离线存储上采用的还是社区的 HDFS,大数据的 KV 存储上我们尝试了 HBase、ES 等组件,同时对于业务属性分为了 online 和 offline 集群。在随着集群规模的扩大上, namenode 也遇到了不少的挑战,例如内存过大,队列过长、存储空间等方面。调度层选择的 YARN,不过基于该组件我们在外围做了一些保障性的工作,例如队列资源的利用率,自动调整分配,作业执行成功率,提交成功率等。薛赵明,Bilibili(哔哩哔哩)数据平台技术经理计算层区分了批量计算(Hive,MR,Spark)、流式计算(Flink,Spark streaming)、ad-hoc(Presto)、OLAP(Kylin)。平台层提供计算方式,业务方自己选择符合合适的计算场景。消息队列上采用的是 kafka,在 0.10.1.1 这个版本上我们遇见了不少问题,例如 conusmer log skew, produce block , multiple Kafka controllers等。经过近两年的使用,最近计划迁移到最新的 2.0 版本。上层服务上,基于我们的大数据套件,针对不同的用户,我开发了相应的大数据工具和数据产品,例如开发 IDE,报表工具,监控系统,数据交换工具等等。《Chaos Practice in TiDB》 视频 | Infra Meetup No.78 - 唐刘 - Chaos Practice in TiDB PPT 下载链接 构造一个健壮的分布式数据库系统是一件非常困难的事情,因为我们需要做非常多的工作来保证用户数据安全,不允许数据丢失或者损坏。而在 TiDB 里面,我们是通过实践 Chaos Engineering 来保证。在本次分享中,我司首席架构师唐刘首先提出了 Chaos 测试的必要性:“虽然我们有 unit test,integration test 这些,但他们都是有局限性的,为了更好的模拟系统实际的情况,我们需要 Chaos。”唐刘,我司首席架构师那么在 TiDB 里面是如何做 Chaos 的?在这其中有三个关键技术,monitor,fault injection 以及 automation。现场重点讲解了 fault injection,包括进程干扰,网络干扰,文件干扰等,以及一些集群工具。同时介绍了在 TiDB 里面如何将所有这些进行整合,也就是 Schrodinger 平台,通过 Schrodinger,我们能自动化的进行 Chaos test。最后,唐刘老师还为大家介绍了一些 PingCAP 现在的研究方向,譬如使用 TLA+ 来证明我们程序的正确性,以及使用 automating fault injection 来自动的分析系统,进行 fault injection。 PingCAP Infra Meetup作为一个基础架构领域的前沿技术公司,PingCAP 希望能为国内真正关注技术本身的 Hackers 打造一个自由分享的平台。自 2016 年 3 月 5 日开始,我们定期在周末举办 Infra Meetup,与大家深度探讨基础架构领域的前瞻性技术思考与经验,目前已落地北京、上海、广州、成都、杭州。在这里,我们希望提供一个高水准的前沿技术讨论空间,让大家真正感受到自由的开源精神魅力。 "}, {"url": "https://pingcap.com/weekly/2018-10-29-tidb-weekly/", "title": "Weekly update (October 22 ~ October 28, 2018)", "content": " Weekly update in TiDB Last week, we landed 52 PRs in the TiDB repository.Added Support ShowStats for the partitioned tables Support := in the set syntax Enable range typed table partition Add the proposal for the column pool Add the log for the binary executed statement Add the slow log for the commit statement Add the proposal of maintaining histograms in the plan Improved Use the Pump client to write binlogs Export the function init() to Init() in the planner package Support _tidb_rowid for table scan range Move the parser package to a separate repository Update the error rate for the partitioned tables in statistics Refine the built-in function truncate to support the uint argument Split unit tests to the corresponding files in the executor/aggfuncs package Add the unit test for the executor/aggfuncs package Use the local feedback for the partitioned tables in statistics Support GC for partition table statistics Make INFORMATION_SCHEMA the first one in show databases Improve the Insert and Update performance for wide tables Use rowDecoder to decode data and evaluate the generated column for AdminCheck Fixed Disable the plan cache for queries containing SubqueryExpr Fix the issue of executing DDL after executing the SQL failure in a transaction Fix the wrong result when the index join operation is performed on union scan Fix a panic of the prepared statement with IndexScan when using the prepared plan cache Fix estimation for the out of range point queries in statistics Clone the schema of projection for different children in the buildProj4Union function Correct the schema after the execution of operations is cancelled halfway Fix the bug that the reassigned partition ID in truncate table does not take effect Weekly update in TiKV and PD Last week, we landed 31 PRs in the TiKV and PD repositories.Added Support more functions in Coprocessor: Trim Conv Support producing an Alpine Linux image Fixed Avoid unsafe mutation for scan_mode Fix data race in PD RaftCluster Improved Add on_stall_conditions_changed to EventListener in TiKV Support adding more schedulers by pd-ctl Add tikv_raftstore_event_duration to metrics Support more server configuration parameters in the PD simulator Support more Region key formats in the pd-ctl detach mode Use the same initial cluster configuration to restart the joined member Support the day format in ReadableDuration New contributors (Thanks!) tikv: killme2008 tidb: HaraldNordgren parastorli yu34po tidb-operator: liufuyang "}, {"url": "https://pingcap.com/blog-cn/tidb-source-code-reading-20/", "title": "TiDB 源码阅读系列文章(二十)Table Partition", "content": " Table Partition 什么是 Table Partition Table Partition 是指根据一定规则,将数据库中的一张表分解成多个更小的容易管理的部分。从逻辑上看只有一张表,但是底层却是由多个物理分区组成。相信对有关系型数据库使用背景的用户来说可能并不陌生。TiDB 正在支持分区表这一特性。在 TiDB 中分区表是一个独立的逻辑表,但是底层由多个物理子表组成。物理子表其实就是普通的表,数据按照一定的规则划分到不同的物理子表类内。程序读写的时候操作的还是逻辑表名字,TiDB 服务器自动去操作分区的数据。分区表有什么好处? 优化器可以使用分区信息做分区裁剪。在语句中包含分区条件时,可以只扫描一个或多个分区表来提高查询效率。 方便地进行数据生命周期管理。通过创建、删除分区、将过期的数据进行 高效的归档,比使用 Delete 语句删除数据更加优雅,打散写入热点,将一个表的写入分散到多个物理表,使得负载分散开,对于存在 Sequence 类型数据的表来说(比如 Auto Increament ID 或者是 create time 这类的索引)可以显著地提升写入吞吐。 分区表的限制 TiDB 默认一个表最多只能有 1024 个分区 ,默认是不区分表名大小写的。 Range, List, Hash 分区要求分区键必须是 INT 类型,或者通过表达式返回 INT 类型。但 Key 分区的时候,可以使用其他类型的列(BLOB,TEXT 类型除外)作为分区键。 如果分区字段中有主键或者唯一索引的列,那么有主键列和唯一索引的列都必须包含进来。即:分区字段要么不包含主键或者索引列,要么包含全部主键和索引列。 TiDB 的分区适用于一个表的所有数据和索引。不能只对表数据分区而不对索引分区,也不能只对索引分区而不对表数据分区,也不能只对表的一部分数据分区。 常见分区表的类型 Range 分区:按照分区表达式的范围来划分分区。通常用于对分区键需要按照范围的查询,分区表达式可以为列名或者表达式 ,下面的 employees 表当中 p0, p1, p2, p3 表示 Range 的访问分别是 (min, 1991), [1991, 1996), [1996, 2001), [2001, max) 这样一个范围。CREATE TABLE employees ( id INT NOT NULL, fname VARCHAR(30), separated DATE NOT NULL ) PARTITION BY RANGE ( YEAR(separated) ) ( PARTITION p0 VALUES LESS THAN (1991), PARTITION p1 VALUES LESS THAN (1996), PARTITION p2 VALUES LESS THAN (2001), PARTITION p3 VALUES LESS THAN MAXVALUE ); List 分区:按照 List 中的值分区,主要用于枚举类型,与 Range 分区的区别在于 Range 分区的区间范围值是连续的。 Hash 分区:Hash 分区需要指定分区键和分区个数。通过 Hash 的分区表达式计算得到一个 INT 类型的结果,这个结果再跟分区个数取模得到具体这行数据属于那个分区。通常用于给定分区键的点查询,Hash 分区主要用来分散热点读,确保数据在预先确定个数的分区中尽可能平均分布。 Key 分区:类似 Hash 分区,Hash 分区允许使用用户自定义的表达式,但 Key 分区不允许使用用户自定义的表达式。Hash 仅支持整数分区,而 Key 分区支持除了 Blob 和 Text 的其他类型的列作为分区键。 TiDB Table Partition 的实现 本文接下来按照 TiDB 源码的 release-2.1 分支讲解,部分讲解会在 source-code 分支代码,目前只支持 Range 分区所以这里只介绍 Range 类型分区 Table Partition 的源码实现,包括 create table、select 、add partition、insert 、drop partition 这五种语句。create table create table 会重点讲构建 Partition 的这部分,更详细的可以看 TiDB 源码阅读系列文章(十七)DDL 源码解析,当用户执行创建分区表的SQL语句,语法解析(Parser)阶段会把 SQL 语句中 Partition 相关信息转换成 ast.PartitionOptions,下文会介绍。接下来会做一系列 Check,分区名在当前的分区表中是否唯一、是否分区 Range 的值保持递增、如果分区键构成为表达式检查表达式里面是否是允许的函数、检查分区键必须是 INT 类型,或者通过表达式返回 INT 类型、检查分区键是否符合一些约束。解释下分区键,在分区表中用于计算这一行数据属于哪一个分区的列的集合叫做分区键。分区键构成可能是一个字段或多个字段也可以是表达式。// PartitionOptions specifies the partition options. type PartitionOptions struct { Tp model.PartitionType Expr ExprNode ColumnNames []*ColumnName Definitions []*PartitionDefinition } ​ // PartitionDefinition defines a single partition. type PartitionDefinition struct { Name model.CIStr LessThan []ExprNode MaxValue bool Comment string } PartitionOptions 结构中 Tp 字段表示分区类型,Expr 字段表示分区键,ColumnNames 字段表示 Columns 分区,这种类型分区又分为 Range columns 分区和 List columns 分区,这种分区目前先不展开介绍。PartitionDefinition 其中 Name 字段表示分区名,LessThan 表示分区 Range 值,MaxValue 字段表示 Range 值是否为最大值,Comment 字段表示分区的描述。CreateTable Partition 部分主要流程如下: 把上文提到语法解析阶段会把 SQL语句中 Partition 相关信息转换成 ast.PartitionOptions , 然后 buildTablePartitionInfo 负责把 PartitionOptions 结构转换 PartitionInfo, 即 Partition 的元信息。 checkPartitionNameUnique 检查分区名是否重复,分表名是不区分大小写的。 对于每一分区 Range 值进行 Check,checkAddPartitionValue 就是检查新增的 Partition 的 Range 需要比之前所有 Partition 的 Range 都更大。 TiDB 单表最多只能有 1024 个分区 ,超过最大分区的限制不会创建成功。 如果分区键构成是一个包含函数的表达式需要检查表达式里面是否是允许的函数 checkPartitionFuncValid。 检查分区键必须是 INT 类型,或者通过表达式返回 INT 类型,同时检查分区键中的字段在表中是否存在 checkPartitionFuncType。 如果分区字段中有主键或者唯一索引的列,那么多有主键列和唯一索引列都必须包含进来。即:分区字段要么不包含主键或者索引列,要么包含全部主键和索引列 checkRangePartitioningKeysConstraints。 通过以上对 PartitionInfo 的一系列 check 主要流程就讲完了,需要注意的是我们没有对 PartitionInfo 的元数据持久化单独存储而是附加在 TableInfo Partition 中。 add partition add partition 首先需要从 SQL 中解析出来 Partition 的元信息,然后对当前添加的分区会有一些 Check 和限制,主要检查是否是分区表、分区名是已存在、最大分区数限制、是否 Range 值保持递增,最后把 Partition 的元信息 PartitionInfo 追加到 Table 的元信息 TableInfo中,具体如下: 检查是否是分区表,若不是分区表则报错提示。 用户的 SQL 语句被解析成将 ast.PartitionDefinition 然后 buildPartitionInfo 做的事就是保存表原来已存在的分区信息例如分区类型,分区键,分区具体信息,每个新分区分配一个独立的 PartitionID。 TiDB 默认一个表最多只能有 1024 个分区,超过最大分区的限制会报错。 对于每新增一个分区需要检查 Range 值进行 Check,checkAddPartitionValue 简单说就是检查新增的 Partition 的 Range 需要比之前所有 Partition 的 Range 都更大。 checkPartitionNameUnique 检查分区名是否重复,分表名是不区分大小写的。 最后把 Partition 的元信息 PartitionInfo 追加到 Table 的元信息 TableInfo.Partition 中,具体实现在这里 updatePartitionInfo。 drop partition drop partition 和 drop table 类似,只不过需要先找到对应的 Partition ID,然后删除对应的数据,以及修改对应 Table 的 Partition 元信息,两者区别是如果是 drop table 则删除整个表数据和表的 TableInfo 元信息,如果是 drop partition 则需删除对应分区数据和 TableInfo 中的 Partition 元信息,删除分区之前会有一些 Check 具体如下: 只能对分区表做 drop partition 操作,若不是分区表则报错提示。 checkDropTablePartition 检查删除的分区是否存在,TiDB 默认是不能删除所有分区,如果想删除最后一个分区,要用 drop table 代替。 removePartitionInfo 会把要删除的分区从 Partition 元信息删除掉,删除前会做checkDropTablePartition 的检查。 对分区表数据则需要拿到 PartitionID 根据插入数据时候的编码规则构造出 StartKey 和 EndKey 便能包含对应分区 Range 内所有的数据,然后把这个范围内的数据删除,具体代码实现在这里。 编码规则:Key: tablePrefix_rowPrefix_partitionID_rowIDstartKey: tablePrefix_rowPrefix_partitionIDendKey: tablePrefix_rowPrefix_partitionID + 1 删除了分区,同时也将删除该分区中的所有数据。如果删除了分区导致分区不能覆盖所有值,那么插入数据的时候会报错。 Select 语句 Select 语句重点讲 Select Partition 如何查询的和分区裁剪(Partition Pruning),更详细的可以看 TiDB 源码阅读系列文章(六)Select 语句概览 。一条 SQL 语句的处理流程,从 Client 接收数据,MySQL 协议解析和转换,SQL 语法解析,逻辑查询计划和物理查询计划执行,到最后返回结果。那么对于分区表是如何查询表里的数据的,其实最主要的修改是 逻辑查询计划 阶段,举个例子:如果用上文中 employees 表作查询, 在 SQL 语句的处理流程前几个阶段没什么不同,但是在逻辑查询计划阶段,rewriteDataSource 将 DataSource 重写了变成 Union All 。每个 Partition id 对应一个 Table Reader。select * from employees 等价于:select * from (union all select * from p0 where id < 1991 select * from p1 where id < 1996 select * from p2 where id < 2001 select * from p3 where id < MAXVALUE) 通过观察 EXPLAIN 的结果可以证实上面的例子,如图 1,最终物理执行计划中有四个 Table Reader 因为 employees 表中有四个分区,Table Reader 表示在 TiDB 端从 TiKV 端读取,cop task 是指被下推到 TiKV 端分布式执行的计算任务。图 1:EXPLAIN 输出用户在使用分区表时,往往只需要访问其中部分的分区, 就像程序局部性原理一样,优化器分析 FROM 和 WHERE 子句来消除不必要的分区,具体还要优化器根据实际的 SQL 语句中所带的条件,避免访问无关分区的优化过程我们称之为分区裁剪(Partition Pruning),具体实现在 这里,分区裁剪是分区表提供的重要优化手段,通过分区的裁剪,避免访问无关数据,可以加速查询速度。当然用户可以刻意利用分区裁剪的特性在 SQL 加入定位分区的条件,优化查询性能。Insert 语句 Insert 语句 是怎么样写入 Table Partition ?其实解释这些问题就可以了: 普通表和分区表怎么区分? 插入数据应该插入哪个 Partition? 每个 Partition 的 RowKey 怎么编码的和普通表的区别是什么? 怎么将数据插入到相应的 Partition 里面? 普通 Table 和 Table Partition 也是实现了 Table 的接口,load schema 在初始化 Table 数据结构的时候,如果发现 tableInfo 里面没有 Partition 信息,则生成一个普通的 tables.Table,普通的 Table 跟以前处理逻辑保持不变,如果 tableInfo 里面有 Partition 信息,则会生成一个 tables.PartitionedTable,它们的区别是 RowKey 的编码方式: 每个分区有一个独立的 Partition ID,Partition ID 和 Table ID 地位平等,每个 Partition 的 Row 和 index 在编码的时候都使用这个 Partition 的 ID。 下面是 PartitionRecordKey 和普通表 RecordKey 区别。 分区表按照规则编码成 Key-Value pair: Key: tablePrefix_rowPrefix_partitionID_rowIDValue: [col1, col2, col3, col4] 普通表按照规则编码成 Key-Value pair: Key: tablePrefix_rowPrefix_tableID_rowIDValue: [col1, col2, col3, col4] 通过 locatePartition 操作查询到应该插入哪个 Partition,目前支持 RANGE 分区插入到那个分区主要是通过范围来判断,例如在 employees 表中插入下面的 sql,通过计算范围该条记录会插入到 p3 分区中,接着调用对应 Partition 上面的 AddRecord 方法,将数据插入到相应的 Partition 里面。 INSERT INTO employees VALUES (1, 'PingCAP TiDB', '2003-10-15'), 插入数据时,如果某行数据不属于任何 Partition,则该事务失败,所有操作回滚。如果 Partition 的 Key 算出来是一个 NULL,对于不同的 Partition 类型有不同的处理方式: 对于 Range Partition:该行数据被插入到最小的那个 Partition 对于 List partition:如果某个 Partition 的 Value List 中有 NULL,该行数据被插入那个 Partition,否则插入失败 对于 Hash 和 Key Partition:NULL 值视为 0,计算 Partition ID 将数据插入到对应的 Partition 在 TiDB 分区表中分区字段插入的值不能大于表中 Range 值最大的上界,否则会报错 End TiDB 目前支持 Range 分区类型,具体以及更细节的可以看 这里。剩余其它类型的分区类型正在开发中,后面陆续会和大家见面,敬请期待。它们的源码实现读者届时可以自行阅读,流程和文中上述描述类似。"}, {"url": "https://pingcap.com/meetup/meetup-20181023-no76/", "title": "【Infra Meetup No.76】列式存储如何进行在线更新", "content": " 视频 | Infra Meetup No.76 - 韦万 - 列式存储如何进行在线更新 PPT 下载链接 时隔一月,我们又与广州的社区小伙伴们相聚啦~这次是由我司数据库核心研发工程师韦万老师带来的《列式存储如何进行在线更新》主题分享。他首先介绍了 OLAP 场景与 OLTP 的区别,以及为何列式数据库特别适合 OLAP 场景,并介绍了主流的对 OLAP 进行优化的技术。然后进入主题,韦万老师分别列举了目前流行的几种列式数据库的更新方案,包括 SQL Server, Vertica, Kudu 以及 VectorWise, 并分析了它们的优缺点。最后介绍了同学们比较关注的部分,即 TiDB 作为一款 HTAP(Hybrid Transactional/Analytical Processing)数据库,当前的架构以及最新进展(视频中剧透了“神秘武器”——TheFlash)。 PingCAP Infra Meetup作为一个基础架构领域的前沿技术公司,PingCAP 希望能为国内真正关注技术本身的 Hackers 打造一个自由分享的平台。自 2016 年 3 月 5 日开始,我们定期在周末举办 Infra Meetup,与大家深度探讨基础架构领域的前瞻性技术思考与经验,目前已落地北京、上海、广州、成都、杭州。在这里,我们希望提供一个高水准的前沿技术讨论空间,让大家真正感受到自由的开源精神魅力。 "}, {"url": "https://pingcap.com/meetup/meetup-20181023-no77/", "title": "【Infra Meetup No.77】我司成都分舵第一次 Meetup", "content": "此次成都 Infra Meetup,恰逢我司成都 Office 正式成立,驻成都的所有 PingCAPer 及 Contributor,与到场小伙伴一起让这首场成都 Infra Meetup 充满了庆祝的热烈气氛:一场成都 TiDB 社区小伙伴的线下见面会开始了。崔秋,我司联合创始人在我司联合创始人崔秋做了感谢社区的开场白后,我司技术副总裁申砾老师带来《Deep Dive Into TiDB SQL Layer》的分享,他首先为大家介绍了 TiDB 的整体架构,重点分享了 SQL 层的架构和核心组件,包括 Query Optimizer 和 Execution Engine,并举例说明了其中的实现细节。最后申老师简要介绍了 TiDB 的 Roadmap,鼓励大家通过各种方式参与 TiDB 开源社区里来。(欢迎捞 issue 提 PR 成为 TiDB Contributor,我们会有神秘小礼物相送哦~) 视频 | 申砾-Deep Dive Into TiDB SQL Layer PPT 下载链接 申砾,我司技术副总裁茶歇时间,大家三三两两聚在一起讨论,现场 PingCAPer 很耐心的一一回答大家关于 TiDB 技术细节的问题,现场讨论氛围非常热烈。茶歇过后,马上消费金融 NewSQL 负责人李银龙老师为大家分享了 TiDB 实践经验。 视频 | Infra Meetup No.77 - 李银龙 - 马上消费金融 TiDB 实践分享 李银龙,马上消费金融 NewSQL 负责人李老师首先介绍了马上消费金融上一代数据库解决方案的核心痛点,然后介绍了对 NewSQL 产品的需求要点,以及一些 NewSQL 产品的对比选型,并深入的分享了 TiDB 解决方案体系的细节和最佳实践经验。最后,李老师表达了对 TiDB 云化方案和类 Redis 分布式方案的期待。 PingCAP Infra Meetup作为一个基础架构领域的前沿技术公司,PingCAP 希望能为国内真正关注技术本身的 Hackers 打造一个自由分享的平台。自 2016 年 3 月 5 日开始,我们定期在周末举办 Infra Meetup,与大家深度探讨基础架构领域的前瞻性技术思考与经验,目前已落地北京、上海、广州、成都、杭州。在这里,我们希望提供一个高水准的前沿技术讨论空间,让大家真正感受到自由的开源精神魅力。 "}, {"url": "https://pingcap.com/weekly/2018-10-22-tidb-weekly/", "title": "Weekly update (October 15 ~ October 21, 2018)", "content": " Weekly update in TiDB Last week, we landed 60 PRs in the TiDB repository.Added Add the slow log for the Commit statement Support cross-domain requests in the HTTP API Add the PreAlloc4Row and Insert functions for Chunk and List Implement Operand and Pattern of the cascades planner Add the TiDB version to DDL metrics Add a session variable to make Insert compatible with MySQL Add the json_keys built-in function Add an EXPLAIN test for partition pruning Improved Improve the MySQL compatibility by adding the USAGE privilege for the showGrants statement Log more information when OtherError occurs in coprocessor Update the Delta information for the partitioned table in statistics Limit the length of sample values in statistics Refine ColumnPrune for LogicalUnionAll Eliminate if null on the non-null column when building Projection Support Group and GroupExpr for the cascades planner Eliminate projection after aggregation pruning Handle the DDL event for the partitioned table in statistics Refine Explain Analyze Remove the kv.BypassLatch option and enable the latch scheduler by default Refine the error log when the DDL job is canceled Improve the MySQL compatibility for the current_user() built-in function Propagate constants over outer join Support changing null to not null in the alter table statement Fixed Fix an invalid DDL job which makes TiDB panic Fix a panic in limit N when N is too large and overflows an integer Fix a bug in point get Fix date time parsing for the YYYY-MM-DD HH format Maintain DeferredExpr in aggressive constant folding Fix a panic caused by the empty histogram in statistics Fix a panic caused by the empty schema of LogicalTableDual Fix data race when initializing the systemTZ variable Fix the admin check table bug of byte comparing Add the check in DDL when creating a table with a foreign key Fix the histogram boundaries overflow error in statistics Convert DataSource to TableDual only when the empty range is not derived from parameterized constants Weekly update in TiSpark Last week, we landed 2 PRs in the TiSpark repository.Fixed Fix a bug in pyspark in Spark 2.3 that does not initialize a session correctly Weekly update in TiKV and PD Last week, we landed 16 PRs in the TiKV and PD repositories.Added Support more functions in Coprocessor: Exp Radians Add the version information for tikv-ctl Add tikv raftstore event duration to metrics Fixed Fix the cluster test of PD Fix the building failure on Mac OS X Fix WaitGroup data race Improved Remove the PD source code and build binary from the docker image Update pd-ctl commands health and topsize Release TiKV v2.0.8 Use the implicit project layout Export ThreadCollector to use it later Introduce eval_func and eval_func_with helper Extract panic_hook Use go mod to manage dependency New contributor (Thanks!) tidb: tianjiqx"}, {"url": "https://pingcap.com/success-stories/tidb-in-iqiyi/", "title": "Always Fun, Always On: How TiDB Helps iQiyi Deliver Streaming Videos to Its 421 Million Monthly Users", "content": " Industry: Media and EntertainmentAuthor: Boshuai Zhu (Senior Infrastructure Engineer at iQiyi)iQiyi, formerly Qiyi, is the Netflix of China: the country’s largest online video-on-demand platform. With “Always Fun, Always Fine” as our brand’s motto, we are committed to providing users with high-resolution, authentic media content including movies, TV dramas, variety shows, documentaries, animations and travel programs. By the end of 2017, our monthly active users on mobile devices reached 421 million and daily active users hit 126 million; at the end of June 2018, the number of our subscribers jumped to 66 million. On March 29, 2018, our company IPO’ed on the NASDAQ and raised $2.25 billion.Since our business has grown rapidly, our data size has also soared. This has placed enormous pressure on our backend system, especially the MySQL cluster. We experienced the suffocating pain of tackling immense data until we found TiDB, a MySQL-compatible NewSQL hybrid transactional and analytical processing (HTAP) database, built and supported by PingCAP. Finally, we can properly manage our data.Currently, the TiDB cluster is deployed in the internal system of our database cloud team. With the April 2018 release of its 2.0 version, TiDB has proven to be much more mature, with increased system stability and query efficiency. In this post, we will share why we chose TiDB, how we are using it, and the lessons we learned working closely with the PingCAP team.Why We Chose TiDB Before TiDB, MySQL was our main database solution for the production environment. The business developed so quickly that our data size rocketed and many bottlenecks occurred in the MySQL cluster. For example: A standalone MySQL instance only supported a limited data volume. Consequently, we had to delete obsolete data to keep the database running. The number of rows within a table increased continuously, which led to reduced query performance. To support our fast-growing business, we were in urgent need of a database which would be: Horizontally scalable Highly available Compatible with MySQL TiDB checked all of those boxes, and in fact, its performance has exceeded our expectations.What Is TiDB? TiDB is an open source, NewSQL, scalable hybrid transactional and analytical processing (HTAP) database built by the PingCAP team and the open source community. It aims to break down the traditional separation between an OLTP database and an OLAP database, and offer a one-stop solution that enables real-time business analysis on live transactional data. Figure 1: TiDB Platform Architecture Inside the TiDB Platform, there are several components: TiDB cluster consists of stateless TiDB instances and serves as a stateless SQL layer that processes users’ SQL queries, accesses data in the storage layer, and returns corresponding results. It’s MySQL compatible and sits on top of TiKV. TiKV cluster, composed of TiKV instances, is the distributed transactional Key-Value storage layer where the data resides. Regardless of where the data comes from, it is stored in TiKV eventually. It uses the Raft consensus protocol for replication to ensure data consistency and disaster recovery. TiSpark cluster also sits on top of TiKV. It is an Apache Spark plugin that works with the TiDB platform to support complex OLAP queries for BI analysts and data scientists. The TiDB ecosystem also has a wealth of other enterprise-level tools, such as Ansible scripts for quick deployment, Syncer for seamless migration from MySQL, Wormhole for migrating heterogeneous data, and TiDB-Binlog, which is a tool to collect binlog files.How Are We Using TiDB? Scenario 1: TiDB in Risk Monitoring Center The Risk Monitoring Center stores machine security statistics, including the traffic information from different dimensions such as per DC (data center), per IP address, per port, etc. To gain timely insights into the system status, some complex queries are performed by the application from time to time.During the database evaluation process, we compared Apache Druid with TiDB and found: Druid provides SQL support via Apache Calcite adapter; TiDB supports SQL natively. Druid does not support ACID transactions; TiDB guarantees ACID compliance, so the data is accurate and reliable anytime, anywhere. Druid is actually a computing engine that depends on an additional storage engine; data cannot be updated in real time. TiDB as a whole project uses TiKV as its storage engine and provides real-time updating of data. Druid is not flexible in aggregate queries, which matters a great deal for data analysis of iQiyi services; TiDB performs well in aggregate queries and thus offers us a reliable foundation for analyzing data. TiDB is highly compatible with the MySQL protocol. Users can access TiDB via the existing MySQL connection pool component. This translates to low cost for service migration and high efficiency for development. Therefore, we decided to deploy TiDB in our Risk Monitoring Center.Deployment Process The Risk Monitoring Center was the first iQiyi project to use TiDB online in the production environment, so we came up with the following plan: To ensure the absolute data safety, we designed a plan B for the TiDB cluster: We replaced the InnoDB in MySQL with TokuDB for its write capability. Then we deployed MySQL with TokuDB as the slave for the TiDB cluster and synchronize the data in the TiDB cluster with TiDB-Binlog. Although this was not optimal because the MySQL with TokuDB solution cannot handle the data growth in the peak time, we designed this to be the disaster recovery plan regardless of the delay. Deployed an internally developed load balancer on the front end to make full use of the computing capability of multiple TiDB nodes and guarantee the high availability of the TiDB nodes. Deployed Prometheus and Grafana to monitor the TiDB cluster status. Connected Grafana to our internal alert platform to instantly inform the operations team of the alert information via short messages and emails. Issues and Solutions The following issues occurred during our adoption of TiDB, but were quickly resolved.Issue One: Connection timeout.Cause: This issue arose because of the failure to select the optimal query plan due to obsolete statistical information. This is a common problem for relational databases. Two common workarounds are available: to collect statistical information manually or to use hint for plan execution. Both are extra workloads for the application developers.Solution: This issue is fixed in the latest version of TiDB with improved statistics-collecting strategy and auto-analyze.Issue Two: Adding an index in the table took a long time.Causes: The DDL execution information was not updated in time. As a result, we got the obsolete information when checking the DDL operation progress. In some cases, large Regions also took extra time to add indexes. Solution: After we reported the issue to the PingCAP development team, they responded actively and quickly. This issue has been fixed in the latest version of TiDB with the addition of the Batch Split feature for large Regions.TiDB in production After we migrated to TiDB for the Risk Monitoring Center, we successfully upgraded the TiDB cluster and modified the parameters of TiKV nodes. Generally, these operations did not affect the online services.During the upgrade of TiKV nodes, some errors occurred such as “Region is unavailable [try again later]” and “TiKV server timeout.” This was due to the lag of cache information, which is unavoidable in a distributed system. But it does not affect the services as long as the application has a retry mechanism. We are amazed by the fact that no matter how much the data increases (as shown in Figure 2), the response time remains stable, thanks to the automatic Region splitting strategy of TiKV (as shown in Figure 3), the storage layer of TiDB. Tables in TiDB are split automatically to several parts of equal size (96 MB by default but …"}, {"url": "https://pingcap.com/blog-cn/linearizability-and-raft/", "title": "线性一致性和 Raft", "content": " 在讨论分布式系统时,共识算法(Consensus algorithm)和一致性(Consistency)通常是讨论热点,两者的联系很微妙,很容易搞混。一些常见的误解:使用了 Raft [0] 或者 paxos 的系统都是线性一致的(Linearizability [1],即强一致),其实不然,共识算法只能提供基础,要实现线性一致还需要在算法之上做出更多的努力。以 TiKV 为例,它的共识算法是 Raft,在 Raft 的保证下,TiKV 提供了满足线性一致性的服务。本篇文章会讨论一下线性一致性和 Raft,以及 TiKV 针对前者的一些优化。线性一致性 什么是一致性,简单的来说就是评判一个并发系统正确与否的标准。线性一致性是其中一种,CAP [2] 中的 C 一般就指它。什么是线性一致性,或者说怎样才能达到线性一致?在回答这个问题之前先了解一些背景知识。背景知识 为了回答上面的问题,我们需要一种表示方法描述分布式系统的行为。分布式系统可以抽象成几个部分: Client Server Events Invocation Response Operations Read Write 一个分布式系统通常有两种角色,Client 和 Server。Client 通过发起请求来获取 Server 的服务。一次完整请求由两个事件组成,Invocation(以下简称 Inv)和 Response(以下简称 Resp)。一个请求中包含一个 Operation,有两种类型 Read 和 Write,最终会在 Server 上执行。说了一堆不明所以的概念,现在来看如何用这些表示分布式系统的行为。上图展示了 Client A 的一个请求从发起到结束的过程。变量 x 的初始值是 1,“x R() A” 是一个事件 Inv 意思是 A 发起了读请求,相应的 “x OK(1) A” 就是事件 Resp,意思是 A 读到了 x 且值为 1,Server 执行读操作(Operation)。如何达到线性一致 背景知识介绍完了,怎样才能达到线性一致?这就要求 Server 在执行 Operations 时需要满足以下三点: 瞬间完成(或者原子性) 发生在 Inv 和 Resp 两个事件之间 反映出“最新”的值 下面我举一个例子,用以解释上面三点。例:先下结论,上图表示的行为满足线性一致。对于同一个对象 x,其初始值为 1,客户端 ABCD 并发地进行了请求,按照真实时间(real-time)顺序,各个事件的发生顺序如上图所示。对于任意一次请求都需要一段时间才能完成,例如 A,“x R() A” 到 “x Ok(1) A” 之间的那条线段就代表那次请求花费的时间,而请求中的读操作在 Server 上的执行时间是很短的,相对于整个请求可以认为瞬间,读操作表示为点,并且在该线段上。线性一致性中没有规定读操作发生的时刻,也就说该点可以在线段上的任意位置,可以在中点,也可以在最后,当然在最开始也无妨。第一点和第二点解释的差不多了,下面说第三点。反映出“最新”的值?我觉得三点中最难理解就是它了。先不急于对“最新”下定义,来看看上图中 x 所有可能的值,显然只有 1 和 2。四个次请求中只有 B 进行了写请求,改变了 x 的值,我们从 B 着手分析,明确 x 在各个时刻的值。由于不能确定 B 的 W(写操作)在哪个时刻发生,能确定的只有一个区间,因此可以引入上下限的概念。对于 x=1,它的上下限为开始到事件“x W(2) B”,在这个范围内所有的读操作必定读到 1。对于 x=2,它的上下限为 事件“x Ok() B” 到结束,在这个范围内所有的读操作必定读到 2。那么“x W(2) B”到“x Ok() B”这段范围,x 的值是什么?1 或者 2。由此可以将 x 分为三个阶段,各阶段”最新”的值如下图所示:清楚了 x 的变化后理解例子中 A C D 的读到结果就很容易了。最后返回的 D 读到了 1,看起来是 “stale read”,其实并不是,它仍满足线性一致性。D 请求横跨了三个阶段,而读可能发生在任意时刻,所以 1 或 2 都行。同理,A 读到的值也可以是 2。C 就不太一样了,C 只有读到了 2 才能满足线性一致。因为 “x R() C” 发生在 “x Ok() B” 之后(happen before [3]),可以推出 R 发生在 W 之后,那么 R 一定得读到 W 完成之后的结果:2。一句话概括:在分布式系统上实现寄存器语义。实现线性一致 如开头所说,一个分布式系统正确实现了共识算法并不意味着能线性一致。共识算法只能保证多个节点对某个对象的状态是一致的,以 Raft 为例,它只能保证不同节点对 Raft Log(以下简称 Log)能达成一致。那么 Log 后面的状态机(state machine)的一致性呢?并没有做详细规定,用户可以自由实现。Raft Raft 是一个强 Leader 的共识算法,只有 Leader 能处理客户端的请求,集群的数据(Log)的流向是从 Leader 流向 Follower。其他的细节在这就不赘述了,网上有很多资料 [4]。In Practice 以 TiKV 为例,TiKV 内部可分成多个模块,Raft 模块,RocksDB 模块,两者通过 Log 进行交互,整体架构如下图所示,consensus 就是 Raft 模块,state machine 就是 RocksDB 模块。Client 将请求发送到 Leader 后,Leader 将请求作为一个 Proposal 通过 Raft 复制到自身以及 Follower 的 Log 中,然后将其 commit。TiKV 将 commit 的 Log 应用到 RocksDB 上,由于 Input(即 Log)都一样,可推出各个 TiKV 的状态机(即 RocksDB)的状态能达成一致。但实际多个 TiKV 不能保证同时将某一个 Log 应用到 RocksDB 上,也就是说各个节点不能实时一致,加之 Leader 会在不同节点之间切换,所以 Leader 的状态机也不总有最新的状态。Leader 处理请求时稍有不慎,没有在最新的状态上进行,这会导致整个系统违反线性一致性。好在有一个很简单的解决方法:依次应用 Log,将应用后的结果返回给 Client。这方法不仅简单还通用,读写请求都可以这样实现。这个方法依据 commit index 对所有请求都做了排序,使得每个请求都能反映出状态机在执行完前一请求后的状态,可以认为 commit 决定了 R/W 事件发生的顺序。Log 是严格全序的(total order),那么自然所有 R/W 也是全序的,将这些 R/W 操作一个一个应用到状态机,所得的结果必定符合线性一致性。这个方法的缺点很明显,性能差,因为所有请求在 Log 那边就被序列化了,无法并发的操作状态机。这样的读简称 LogRead。由于读请求不改变状态机,这个实现就显得有些“重“,不仅有 RPC 开销,还有写 Log 开销。优化的方法大致有两种: ReadIndex LeaseRead ReadIndex 相比于 LogRead,ReadIndex 跳过了 Log,节省了磁盘开销,它能大幅提升读的吞吐,减小延时(但不显著)。Leader 执行 ReadIndex 大致的流程如下: 记录当前的 commit index,称为 ReadIndex 向 Follower 发起一次心跳,如果大多数节点回复了,那就能确定现在仍然是 Leader 等待状态机至少应用到 ReadIndex 记录的 Log 执行读请求,将结果返回给 Client 第 3 点中的“至少”是关键要求,它表明状态机应用到 ReadIndex 之后的状态都能使这个请求满足线性一致,不管过了多久,也不管 Leader 有没有飘走。为什么在 ReadIndex 只有就满足了线性一致性呢?之前 LogRead 的读发生点是 commit index,这个点能使 LogRead 满足线性一致,那显然发生这个点之后的 ReadIndex 也能满足。LeaseRead LeaseRead 与 ReadIndex 类似,但更进一步,不仅省去了 Log,还省去了网络交互。它可以大幅提升读的吞吐也能显著降低延时。基本的思路是 Leader 取一个比 Election Timeout 小的租期,在租期不会发生选举,确保 Leader 不会变,所以可以跳过 ReadIndex 的第二步,也就降低了延时。 LeaseRead 的正确性和时间挂钩,因此时间的实现至关重要,如果漂移严重,这套机制就会有问题。Wait Free 到此为止 Lease 省去了 ReadIndex 的第二步,实际能再进一步,省去第 3 步。这样的 LeaseRead 在收到请求后会立刻进行读请求,不取 commit index 也不等状态机。由于 Raft 的强 Leader 特性,在租期内的 Client 收到的 Resp 由 Leader 的状态机产生,所以只要状态机满足线性一致,那么在 Lease 内,不管何时发生读都能满足线性一致性。有一点需要注意,只有在 Leader 的状态机应用了当前 term 的第一个 Log 后才能进行 LeaseRead。因为新选举产生的 Leader,它虽然有全部 committed Log,但它的状态机可能落后于之前的 Leader,状态机应用到当前 term 的 Log 就保证了新 Leader 的状态机一定新于旧 Leader,之后肯定不会出现 stale read。写在最后 本文粗略地聊了聊线性一致性,以及 TiKV 内部的一些优化。最后留四个问题以便更好地理解本文: 对于线性一致中的例子,如果 A 读到了 2,那么 x 的各个阶段是怎样的呢? 对于下图,它符合线性一致吗?(温馨提示:请使用游标卡尺。;-P) Leader 的状态机在什么时候没有最新状态?要线性一致性,Raft 该如何解决这问题? FollowerRead 可以由 ReadIndex 实现,那么能由 LeaseRead 实现吗? 如有疑问或想交流,欢迎联系我:shentaining@pingcap.com[0].Ongaro, Diego. Consensus: Bridging theory and practice. Diss. Stanford University, 2014.[1].Herlihy, Maurice P., and Jeannette M. Wing. “Linearizability: A correctness condition for concurrent objects.” ACM Transactions on Programming Languages and Systems (TOPLAS) 12.3 (1990): 463-492.[2].Gilbert, Seth, and Nancy Lynch. “Brewer’s conjecture and the feasibility of consistent, available, partition-tolerant web services.” Acm Sigact News 33.2 (2002): 51-59.[3].Lamport, Leslie. “Time, clocks, and the ordering of events in a distributed system.” Communications of the ACM 21.7 (1978): 558-565.[4].https://raft.github.io/"}, {"url": "https://pingcap.com/blog/tidb-academy-announce/", "title": "Launching TiDB Academy, First Course-“Distributed Database with TiDB for MySQL DBAs”", "content": "Author: Morgan Tocker, Senior Product and Community ManagerTiDB AcademyToday, we are excited to launch TiDB Academy, a series of technical training courses and certifications on TiDB and distributed databases in general, taught by our senior technical team. At PingCAP, we firmly believe it’s our responsibility to deliver transparency and share knowledge to our customers and community, not just handing you a mysterious “black box” to use. As the world of database technology moves toward a cloud-native, NewSQL direction, learning how to properly use distributed databases like TiDB will become increasingly important and valuable for IT professionals; that’s why we built TiDB Academy.These courses are designed to help practitioners and professionals – DBAs, DevOps, System Architects – understand the architecture, design choices, strengths, and trade-offs of TiDB, from the team who built it. I’m the instructor for the first course, called “Distributed Database with TiDB for MySQL DBAs”. We chose this topic first because, as a MySQL-compatible NewSQL database, TiDB’s most common use case is enhancing the productivity and complementing the capabilities of MySQL DBAs. Thus, during this course you will find me often explaining TiDB concepts by using a direct comparison to MySQL, leveraging my own 15-plus years of MySQL product experience and the expertise of other PingCAP engineers, many of whom were former MySQL DBAs themselves.This self-paced course is full of hands-on exercises and labs, so you can get your fingers dirty and your mind working, as you explore the inner workings of TiDB. Taking the course is free, and there’s a certification exam you can take for a small fee to validate your newly acquired skill as a TiDB and distributed database expert! This course is available now to enroll (https://pingcap.com/tidb-academy/), and the first certification exam will be on December 1, 2018.As a teaser, you will learn (among many other topics): Architectural Design: how TiDB’s different components support hybrid transactional and analytical processing (HTAP) workloads; Horizontal Scaling: how TiDB can elastically scale while using its transactional model to keep data strongly consistent and highly available; Online DDL: how TiDB’s DDL algorithm and implementation makes online schema change a breeze. If you have any questions about this first course, or the TiDB Academy in general, you can reach our teaching staff anytime: academy@pingcap.com. Happy learning!"}, {"url": "https://pingcap.com/weekly/2018-10-15-tidb-weekly/", "title": "Weekly update (September 24 ~ October 14, 2018)", "content": " Weekly update in TiDB Last three weeks, we landed 74 PRs in the TiDB repository.Added Add a session variable tidb_enable_cascades_planner Make explain support explain analyze Calculate radix bit number before building a hash table Add a benchmark test case of a complex query for the parser Support autoAnalyze for partitioned tables Add a force-priority option to the configuration file Add metrics for slow query logs Add a built-in function json_length Redesign the latch scheduler Add the admin show slow command Improved Support IndexJoin over UnionScan Improve the precision for the Avg aggregation function Refine chunk.SwapColumn to rebuild the column reference Build the anti semi join plan for NOT EXISTS Refine chunk.SwapColumn to rebuild the column reference Make the sysdate built-in function unfoldable Improve the INFORMATION_SCHEMA.ENGINES table compatibility Improve the warning and error information for the group_concat() built-in function Change the default value of the performance_schema session variable to OFF Support show create table with the Compression option Optimize regionErr, notLeader, and staleEpoch error handling Speed up the recovery when the PD leader is down Support building TiDB on Windows operation system Allow alter table to append values to an enum typed column Return a table dual logical plan when the filter is false or null Refine the handle check to use the point get plan for a prepared statement Change FLUSH TABLES WITH READ LOCK to produce an error Remove some useless code and avoid some redundancy check Use the chunk grow for a simple executor Fixed Fix a parser bug that an empty string in the ESCAPED BY subclause of FIELDS causes a panic Fix the statistics updating bug when there is no stats worker Fix the memory leak issue in statistics Check the privilege for show processlist Fix the log format for gc worker Fix a panic by avoiding the Send operation on the closed slow query channel Fix the results of the Command and Time fields in show processlist Fix the issue that the float type does not take effect in AddDate and SubDate built-in functions Exclude IsNull from the constant propagation Fix a bug in admin check table Return an error when the argument of the VALUES() function is not a column Fix the combined index low-bound check in statistics Fix a panic in the substring_index built-in function Fix the show create table result when the table has a Compression option Fix an issue of casting an unsigned integer to a decimal Fix a panic when the values for the PointGet operator are all null Fix the compatibility issue that updating the subquery table should be forbidden Fix some corner cases when parsing a string to a datetime Fix alter table add index on a virtual column bug Weekly update in TiSpark Last three weeks, we landed 4 PRs in the TiSpark repository.Added Update Spark support to Spark 2.3 Fixed Fix the date timezone in tests Fix an issue that Explain statements do not work in Spark 2.3 Weekly update in TiKV and PD Last three weeks, we landed 42 PRs in the TiKV and PD repositories.Added Support more functions in Coprocessor: InetAton InetNtoa Concat Right Sha2 TruncateDecimal TruncateReal Year RouldReal RoundDec RoundWithFracDec RoundWithFracInt RoundWithFracReal TruncateInt Fuzz codec::number Add RegionChangeObserver Get Regions with the top size Fixed Fix the hanging problem when etcd fails to start Fix an issue of parsing a datetime from a string Improved Improve the performance of Coprocessors md5 and sha1 Unify the PD logger Check the level 0 files before ingesting Integrate the error code with pkg/errors to provide error tracing Upgrade Golang gRPC to 1.12.2 Upgrade Rust gRPC to 0.4.0 New contributors (Thanks!) tikv: Kingwl colinback docs-cn: mccxj sweetIan "}, {"url": "https://pingcap.com/blog-cn/how-tikv-store-get-data/", "title": "TiKV 是如何存取数据的", "content": " 本文会详细的介绍 TiKV 是如何处理读写请求的,通过该文档,同学们会知道 TiKV 是如何将一个写请求包含的数据更改存储到系统,并且能读出对应的数据的。基础知识 在开始之前,我们需要介绍一些基础知识,便于大家去理解后面的流程。Raft TiKV 使用 Raft 一致性算法来保证数据的安全,默认提供的是三个副本支持,这三个副本形成了一个 Raft Group。当 Client 需要写入某个数据的时候,Client 会将操作发送给 Raft Leader,这个在 TiKV 里面我们叫做 Propose,Leader 会将操作编码成一个 entry,写入到自己的 Raft Log 里面,这个我们叫做 Append。Leader 也会通过 Raft 算法将 entry 复制到其他的 Follower 上面,这个我们叫做 Replicate。Follower 收到这个 entry 之后也会同样进行 Append 操作,顺带告诉 Leader Append 成功。当 Leader 发现这个 entry 已经被大多数节点 Append,就认为这个 entry 已经是 Committed 的了,然后就可以将 entry 里面的操作解码出来,执行并且应用到状态机里面,这个我们叫做 Apply。在 TiKV 里面,我们提供了 Lease Read,对于 Read 请求,会直接发给 Leader,如果 Leader 确定自己的 lease 没有过期,那么就会直接提供 Read 服务,这样就不用走一次 Raft 了。如果 Leader 发现 lease 过期了,就会强制走一次 Raft 进行续租,然后在提供 Read 服务。Multi Raft 因为一个 Raft Group 处理的数据量有限,所以我们会将数据切分成多个 Raft Group,我们叫做 Region。切分的方式是按照 range 进行切分,也就是我们会将数据的 key 按照字节序进行排序,也就是一个无限的 sorted map,然后将其切分成一段一段(连续)的 key range,每个 key range 当成一个 Region。两个相邻的 Region 之间不允许出现空洞,也就是前面一个 Region 的 end key 就是后一个 Region 的 start key。Region 的 range 使用的是前闭后开的模式 [start, end),对于 key start 来说,它就属于这个 Region,但对于 end 来说,它其实属于下一个 Region。TiKV 的 Region 会有最大 size 的限制,当超过这个阈值之后,就会分裂成两个 Region,譬如 [a, b) -> [a, ab) + [ab, b),当然,如果 Region 里面没有数据,或者只有很少的数据,也会跟相邻的 Region 进行合并,变成一个更大的 Region,譬如 [a, ab) + [ab, b) -> [a, b)Percolator 对于同一个 Region 来说,通过 Raft 一致性协议,我们能保证里面的 key 操作的一致性,但如果我们要同时操作多个数据,而这些数据落在不同的 Region 上面,为了保证操作的一致性,我们就需要分布式事务。譬如我们需要同时将 a = 1,b = 2 修改成功,而 a 和 b 属于不同的 Region,那么当操作结束之后,一定只能出现 a 和 b 要么都修改成功,要么都没有修改成功,不能出现 a 修改了,但 b 没有修改,或者 b 修改了,a 没有修改这样的情况。最通常的分布式事务的做法就是使用 two-phase commit,也就是俗称的 2PC,但传统的 2PC 需要有一个协调者,而我们也需要有机制来保证协调者的高可用。这里,TiKV 参考了 Google 的 Percolator,对 2PC 进行了优化,来提供分布式事务支持。Percolator 的原理是比较复杂的,需要关注几点:首先,Percolator 需要一个服务 timestamp oracle (TSO) 来分配全局的 timestamp,这个 timestamp 是按照时间单调递增的,而且全局唯一。任何事务在开始的时候会先拿一个 start timestamp (startTS),然后在事务提交的时候会拿一个 commit timestamp (commitTS)。Percolator 提供三个 column family (CF),Lock,Data 和 Write,当写入一个 key-value 的时候,会将这个 key 的 lock 放到 Lock CF 里面,会将实际的 value 放到 Data CF 里面,如果这次写入 commit 成功,则会将对应的 commit 信息放到入 Write CF 里面。Key 在 Data CF 和 Write CF 里面存放的时候,会把对应的时间戳给加到 Key 的后面。在 Data CF 里面,添加的是 startTS,而在 Write CF 里面,则是 commitCF。假设我们需要写入 a = 1,首先从 TSO 上面拿到一个 startTS,譬如 10,然后我们进入 Percolator 的 PreWrite 阶段,在 Lock 和 Data CF 上面写入数据,如下:Lock CF: W a = lock Data CF: W a_10 = value 后面我们会用 W 表示 Write,R 表示 Read, D 表示 Delete,S 表示 Seek。当 PreWrite 成功之后,就会进入 Commit 阶段,会从 TSO 拿一个 commitTS,譬如 11,然后写入:Lock CF: D a Write CF: W a_11 = 10 当 Commit 成功之后,对于一个 key-value 来说,它就会在 Data CF 和 Write CF 里面都有记录,在 Data CF 里面会记录实际的数据, Write CF 里面则会记录对应的 startTS。当我们要读取数据的时候,也会先从 TSO 拿到一个 startTS,譬如 12,然后进行读:Lock CF: R a Write CF: S a_12 -> a_11 = 10 Data CF: R a_10 在 Read 流程里面,首先我们看 Lock CF 里面是否有 lock,如果有,那么读取就失败了。如果没有,我们就会在 Write CF 里面 seek 最新的一个提交版本,这里我们会找到 11,然后拿到对应的 startTS,这里就是 10,然后将 key 和 startTS 组合在 Data CF 里面读取对应的数据。上面只是简单的介绍了下 Percolator 的读写流程,实际会比这个复杂的多。RocksDB TiKV 会将数据存储到 RocksDB,RocksDB 是一个 key-value 存储系统,所以对于 TiKV 来说,任何的数据都最终会转换成一个或者多个 key-value 存放到 RocksDB 里面。每个 TiKV 包含两个 RocksDB 实例,一个用于存储 Raft Log,我们后面称为 Raft RocksDB,而另一个则是存放用户实际的数据,我们称为 KV RocksDB。一个 TiKV 会有多个 Regions,我们在 Raft RocksDB 里面会使用 Region 的 ID 作为 key 的前缀,然后再带上 Raft Log ID 来唯一标识一条 Raft Log。譬如,假设现在有两个 Region,ID 分别为 1,2,那么 Raft Log 在 RocksDB 里面类似如下存放:1_1 -> Log {a = 1} 1_2 -> Log {a = 2} … 1_N -> Log {a = N} 2_1 -> Log {b = 2} 2_2 -> Log {b = 3} … 2_N -> Log {b = N} 因为我们是按照 range 对 key 进行的切分,那么在 KV RocksDB 里面,我们直接使用 key 来进行保存,类似如下:a -> N b -> N 里面存放了两个 key,a 和 b,但并没有使用任何前缀进行区分。RocksDB 支持 Column Family,所以能直接跟 Percolator 里面的 CF 对应,在 TiKV 里面,我们在 RocksDB 使用 Default CF 直接对应 Percolator 的 Data CF,另外使用了相同名字的 Lock 和 Write。PD TiKV 会将自己所有的 Region 信息汇报给 PD,这样 PD 就有了整个集群的 Region 信息,当然就有了一张 Region 的路由表,如下:当 Client 需要操作某一个 key 的数据的时候,它首先会向 PD 问一下这个 key 属于哪一个 Region,譬如对于 key a 来说,PD 知道它属于 Region 1,就会给 Client 返回 Region 1 的相关信息,包括有多少个副本,现在 Leader 是哪一个副本,这个 Leader 副本在哪一个 TiKV 上面。Client 会将相关的 Region 信息缓存到本地,加速后续的操作,但有可能 Region 的 Raft Leader 变更,或者 Region 出现了分裂,合并,Client 会知道缓存失效,然后重新去 PD 获取最新的信息。PD 同时也提供全局的授时服务,在 Percolator 事务模型里面,我们知道事务开始以及提交都需要有一个时间戳,这个就是 PD 统一分配的。RawKV 前面介绍了一些基础知识,下面将开始详细的介绍 TiKV 的读写流程。TiKV 提供两套 API,一套叫做 RawKV,另一套叫做 TxnKV。TxnKV 对应的就是上面提到的 Percolator,而 RawKV 则不会对事务做任何保证,而且比 TxnKV 简单很多,这里我们先讨论 RawKV。Write 当进行写入,譬如 Write a = 1,会进行如下步骤: Client 找 PD 问 a 所在的 Region PD 告诉 Region 相关信息,主要是 Leader 所在的 TiKV Client 将命令发送给 Leader 所在的 TiKV Leader 接受请求之后执行 Raft 流程 Leader 将 a = 1 Apply 到 KV RocksDB 然后给 Client 返回写入成功 Read 对于 Read 来说,也是一样的操作,唯一不同在于 Leader 可以直接提供 Read,不需要走 Raft。TxnKV Write 对于 TxnKV 来说,情况就要复杂的多,不过大部分流程已经在 Percolator 章节进行说明了。这里需要注意的是,因为我们要快速的 seek 到最新的 commit,所以在 RocksDB 里面,我们会先将 TS 使用 bigendian 生成 8 字节的 bytes,然后将这个 bytes 逐位取反,在跟原始的 key 组合存储到 RocksDB 里面,这样就能保证最新的提交存放到前面,seek 的时候就能直接定位了,当然 seek 的时候,也同样会将对应的 TS 按照相同的方式编码处理。譬如,假设一个 key 现在有两次提交,commitTS 分别为 10 和 12,startTS 则是 9 和 11,那么在 RocksDB 里面,key 的存放顺序则是:Write CF: a_12 -> 11 a_10 -> 9 Data CF: a_11 -> data_11 a_9 -> data_9 另外,还需要注意的是,对于 value 比较小的情况,TiKV 会直接将 value 存放到 Write CF 里面,这样 Read 的时候只要走 Write CF 就行了。在写入的时候,流程如下:PreWrite: Lock CF: W a -> Lock + Data Commit: Lock CF: R a -> Lock + 10 + Data Lock CF: D a Write CF: W a_11 -> 10 + Data 对于 TiKV 来说,在 Commit 阶段无论怎样都会读取 Lock 来判断事务冲突,所以我们可以从 Lock 拿到数据,然后再写入到 Write CF 里面。Read Read 的流程之前的 Percolator 已经有说明了,这里就不详细解释了。SQL Key Mapping 我们在 TiKV 上面构建了一个分布式数据库 TiDB,它是一个关系型数据库,所以大家需要关注的是一个关系型的 table 是如何映射到 key-value 上面的。假设我们有如下的表结构:CREATE TABLE t1 { id BIGINT PRIMARY KEY, name VARCHAR(1024), age BIGINT, content BLOB, UNIQUE(name), INDEX(age), } 上面我们创建了一张表 t1,里面有四个字段,id 是主键,name 是唯一索引,age 是一个索引。那么这个表里面的数据是如何对应到 TiKV 的呢?在 TiDB 里面,任何一张表都有一个唯一的 ID,譬如这里是 11,任何的索引也有唯一的 ID,上面 name 就是 12,age 就是 13。我们使用前缀 t 和 i 来区分表里面的 data 和 index。对于上面表 t1 来说,假设现在它有两行数据,分别是 (1, “a”, 10, “hello”) 和 (2, “b”, 12, “world”),在 TiKV 里面,每一行数据会有不同的 key-value 对应。如下:PK t_11_1 -> (1, “a”, 10, “hello”) t_11_2 -> (2, “b”, 12, “world”) Unique Name i_12_a -> 1 i_12_b -> 2 Index Age i_13_10_1 -> nil i_13_12_2 -> nil 因为 PK 具有唯一性,所以我们可以用 t + Table ID + PK 来唯一表示一行数据,value 就是这行数据。对于 Unique 来说,也是具有唯一性的,所以我们用 i + Index ID + name 来表示,而 value 则是对应的 PK。如果两个 name 相同,就会破坏唯一性约束。当我们使用 Unique 来查询的时候,会先找到对应的 PK,然后再通过 PK 找到对应的数据。对于普通的 Index 来说,不需要唯一性约束,所以我们使用 i + Index ID + age + PK,而 value 为空。因为 PK 一定是唯一的,所以两行数据即使 age 一样,也不会冲突。当我们使用 Index 来查询的时候,会先 seek 到第一个大于等于 i + Index ID + age 这个 key 的数据,然后看前缀是否匹配,如果匹配,则解码出对应的 PK,再从 PK 拿到实际的数据。TiDB 在操作 TiKV 的时候需要保证操作 keys 的一致性,所以需要使用 TxnKV 模式。结语 上面简单的介绍了下 TiKV 读写数据的流程,还有很多东西并没有覆盖到,譬如错误处理,Percolator 的性能优化这些,如果你对这些感兴趣,可以参与到 TiKV 的开发,欢迎联系我 tl@pingcap.com。"}, {"url": "https://pingcap.com/blog-cn/tidb-source-code-reading-19/", "title": "TiDB 源码阅读系列文章(十九)tikv-client(下)", "content": " 上篇文章 中,我们介绍了数据读写过程中 tikv-client 需要解决的几个具体问题,本文将继续介绍 tikv-client 里的两个主要的模块——负责处理分布式计算的 copIterator 和执行二阶段提交的 twoPhaseCommitter。copIterator copIterator 是什么 在介绍 copIterator 的概念之前,我们需要简单回顾一下前面 TiDB 源码阅读系列文章(六)中讲过的 distsql 和 coprocessor 的概念以及它们和 SQL 语句的关系。tikv-server 通过 coprocessor 接口,支持部分 SQL 层的计算能力,大部分只涉及单表数据的常用的算子都可以下推到 tikv-server 上计算,计算下推以后,从存储引擎读取的数据虽然是一样的多,但是通过网络返回的数据会少很多,可以大幅节省序列化和网络传输的开销。distsql 是位于 SQL 层和 coprocessor 之间的一层抽象,它把下层的 coprocessor 请求封装起来对上层提供一个简单的 Select 方法。执行一个单表的计算任务。最上层的 SQL 语句可能会包含 JOIN,SUBQUERY 等复杂算子,涉及很多的表,而 distsql 只涉及到单个表的数据。一个 distsql 请求会涉及到多个 region,我们要对涉及到的每一个 region 执行一次 coprocessor 请求。所以它们的关系是这样的,一个 SQL 语句包含多个 distsql 请求,一个 distsql 请求包含多个 coprocessor 请求。copIterator 的任务就是实现 distsql 请求,执行所有涉及到的 coprocessor 请求,并依次返回结果。构造 coprocessor task 一个 distsql 请求需要处理的数据是一个单表上的 index scan 或 table scan,在 Request 包含了转换好的 KeyRange list。接下来,通过 region cache 提供的 LocateKey 方法,我们可以找到有哪些 region 包含了一个 key range 范围内的数据。找到所有 KeyRange 包含的所有的 region 以后,我们需要按照 region 的 range 把 key range list 进行切分,让每个 coprocessor task 里的 key range list 不会超过 region 的范围。构造出了所有 coprocessor task 之后,下一步就是执行这些 task 了。copIterator 的执行模式 为了更容易理解 copIterator 的执行模式,我们先从最简单的实现方式开始, 逐步推导到现在的设计。copIterator 是 kv.Response 接口的实现,需要实现对应 Next 方法,在上层调用 Next 的时候,返回一个 coprocessor response,上层通过多次调用 Next 方法,获取多个 coprocessor response,直到所有结果获取完。最简单的实现方式,是在 Next 方法里,执行一个 coprocessor task,返回这个 task 的执行结果。这个执行方式的一个很大的问题,大量时间耗费在等待 coprocessor 请求返回结果,我们需要改进一下。coprocessor 请求如果是由 Next 触发的,每次调用 Next 就必须等待一个 RPC round trip 的延迟。我们可以改造成请求在 Next 被调用之前触发,这样就能在 Next 被调用的时候,更早拿到结果返回,省掉了阻塞等待的过程。在 copIterator 创建的时候,我们启动一个后台 worker goroutine 来依次执行所有的 coprocessor task,并把执行结果发送到一个 response channel,这样前台 Next 方法只需要从这个 channel 里 receive 一个 coprocessor response 就可以了。如果这个 task 已经执行完成,Next 方法可以直接获取到结果,立即返回。当所有 coprocessor task 被 worker 执行完成的时候,worker 把这个 response channel 关闭,Next 方法在 receive channel 的时候发现 channel 已经关闭,就可以返回 nil response,表示所有结果都处理完成了。以上的执行方案还是存在一个问题,就是 coprocessor task 只有一个 worker 在执行,没有并行,性能还是不理想。为了增大并行度,我们可以构造多个 worker 来执行 task,把所有的 task 发送到一个 task channel,多个 worker 从这一个 channel 读取 task,执行完成后,把结果发到 response channel,通过设置 worker 的数量控制并发度。这样改造以后,就可以充分的并行执行了,但是这样带来一个新的问题,task 是有序的,但是由于多个 worker 并行执行,返回的 response 顺序是乱序的。对于不要求结果有序的 distsql 请求,这个执行模式是可行的,我们使用这个模式来执行。对于要求结果有序的 distsql 请求,就不能满足要求了,我们需要另一种执行模式。当 worker 执行完一个 task 之后,当前的做法是把 response 发送到一个全局的 channel 里,如果我们给每一个 task 创建一个 channel,把 response 发送到这个 task 自己的 response channel 里,Next 的时候,就可以按照 task 的顺序获取 response,保证结果的有序。以上就是 copIterator 最终的执行模式。copIterator 实现细节 理解执行模式之后,我们从源码的角度,分析一遍完整的执行流程。前台执行流程 前台的执行的第一步是 CopClient 的 Send 方法。先根据 distsql 请求里的 KeyRanges 构造 coprocessor task,用构造好的 task 创建 copIterator,然后调用 copIterator 的 open 方法,启动多个后台 worker goroutine,然后启动一个 sender 用来把 task 丢进 task channel,最后 copIterator 做为 kv.Reponse 返回。前台执行的第二步是多次调用 kv.Response 的 Next 方法,直到获取所有的 response。copIterator 在 Next 里会根据结果是否有序,选择相应的执行模式,无序的请求会从 全局 channel 里获取结果,有序的请求会在每一个 task 的 response channel 里获取结果。后台执行流程 从 task channel 获取到一个 task 之后,worker 会执行 handleTask 来发送 RPC 请求,并处理请求的异常,当 region 分裂的时候,我们需要重新构造 新的 task,并重新发送。对于有序的 distsql 请求,分裂后的多个 task 的执行结果需要发送到旧的 task 的 response channel 里,所以一个 task 的 response channel 可能会返回多个 response,发送完成后需要 关闭 task 的 response channel。twoPhaseCommitter 2PC 简介 2PC 是实现分布式事务的一种方式,保证跨越多个网络节点的事务的原子性,不会出现事务只提交一半的问题。在 TiDB,使用的 2PC 模型是 Google percolator 模型,简单的理解,percolator 模型和传统的 2PC 的区别主要在于消除了事务管理器的单点,把事务状态信息保存在每个 key 上,大幅提高了分布式事务的线性 scale 能力,虽然仍然存在一个 timestamp oracle 的单点,但是因为逻辑非常简单,而且可以 batch 执行,所以并不会成为系统的瓶颈。关于 percolator 模型的细节,可以参考这篇文章的介绍 https://pingcap.com/blog-cn/percolator-and-txn/构造 twoPhaseCommitter 当一个事务准备提交的时候,会创建一个 twoPhaseCommiter,用来执行分布式的事务。构造的时候,需要做以下几件事情 从 memBuffer 和 lockedKeys 里收集所有的 key 和 mutationmemBuffer 里的 key 是有序排列的,我们从头遍历 memBuffer 可以顺序的收集到事务里需要修改的 key,value 长度为 0 的 entry 表示 DELETE 操作,value 长度大于 0 表示 PUT 操作,memBuffer 里的第一个 key 做为事务的 primary key。lockKeys 里保存的是不需要修改,但需要加读锁的 key,也会做为 mutation 的 LOCK 操作,写到 TiKV 上。 计算事务的大小是否超过限制在收集 mutation 的时候,会统计整个事务的大小,如果超过了最大事务限制,会返回报错。太大的事务可能会让 TiKV 集群压力过大,执行失败并导致集群不可用,所以要对事务的大小做出硬性的限制。 计算事务的 TTL 时间如果一个事务的 key 通过 prewrite 加锁后,事务没有执行完,tidb-server 就挂掉了,这时候集群内其他 tidb-server 是无法读取这个 key 的,如果没有 TTL,就会死锁。设置了 TTL 之后,读请求就可以在 TTL 超时之后执行清锁,然后读取到数据。我们计算一个事务的超时时间需要考虑正常执行一个事务需要花费的时间,如果太短会出现大的事务无法正常执行完的问题,如果太长,会有异常退出导致某个 key 长时间无法访问的问题。所以使用了这样一个算法,TTL 和事务的大小的平方根成正比,并控制在一个最小值和一个最大值之间。 execute 在 twoPhaseCommiter 创建好以后,下一步就是执行 execute 函数。在 execute 函数里,需要在 defer 函数里执行 cleanupKeys,在事务没有成功执行的时候,清理掉多余的锁,如果不做这一步操作,残留的锁会让读请求阻塞,直到 TTL 过期才会被清理。第一步会执行 prewriteKeys,如果成功,会从 PD 获取一个 commitTS 用来执行 commit 操作。取到了 commitTS 之后,还需要做以下验证: commitTS 比 startTS 大 schema 没有过期 事务的执行时间没有过长 如果没有通过检查,事务会失败报错。 通过检查之后,执行最后一步 commitKeys,如果没有错误,事务就提交完成了。当 commitKeys 请求遇到了网络超时,那么这个事务是否已经提交是不确定的,这时候不能执行 cleanupKeys 操作,否则就破坏了事务的一致性。我们对这种情况返回一个特殊的 undetermined error,让上层来处理。上层会在遇到这种 error 的时候,把连接断开,而不是返回给用户一个执行失败的错误。prewriteKeys, commitKeys 和 cleanupKeys 有很多相同的逻辑,需要把 keys 根据 region 分成 batch,然后对每个 batch 执行一次 RPC。当 RPC 返回 region 过期的错误时,我们需要把这个 region 上的 keys 重新分成 batch,发送 RPC 请求。这部分逻辑我们把它抽出来,放在 doActionOnKeys 和 doActionOnBatches 里,并实现 prewriteSinlgeBatch,commitSingleBatch,cleanupSingleBatch 函数,用来执行单个 batch 的 RPC 请求。虽然大部分逻辑是相同的,但是不同的请求在执行顺序上有一些不同,在 doActionOnKeys 里需要特殊的判断和处理。 prewrite 分成的多个 batch 需要同步并行的执行。 commit 分成的多个 batch 需要先执行第一个 batch,成功后再异步并行执行其他的 batch。 cleanup 分成的多个 batch 需要异步并行执行。 doActionOnBatches 会开启多个 goroutines 并行的执行多个 batch,如果遇到了 error,会把其他正在执行的 context cancel 掉,然后返回第一个遇到的 error。执行 prewriteSingleBatch 的时候,有可能会遇到 region 分裂错误,这时候 batch 里的 key 就不再是一个 region 上的 key 了,我们会在这里递归的调用 prewriteKeys,重新走一遍拆分 batch 然后执行 doActionOnBatch 和 prewriteSingleBatch 的流程。这部分逻辑在 commitSingleBatch 和 cleanupSingleBatch 里也都有。twoPhaseCommitter 包含的逻辑只是事务模型的一小部分,主要的逻辑在 tikv-server 端,超出了这篇文章的范围,就不在这里详细讨论了。"}, {"url": "https://pingcap.com/weekly/2018-09-25-tidb-weekly/", "title": "Weekly update (September 17 ~ September 23, 2018)", "content": " Weekly update in TiDB Last week, we landed 29 PRs in the TiDB repository.Added Support dumping statistics for partitioned tables Add a variable to control the statement priority of a TiDB server Add a WithRecovery() function in the util package Improved Remove the DDL version in metrics Set TiDBMemQuotaQuery to the value in the configuration file Prune columns for LogicalTableDual Optimize the IsPoint() function for performance Support limit/group-by/order-by clauses in Point_Get Reuse chunks to reduce memory usage in UnionScan Add correctness check for some system variables Optimize constant fold for null parameter expressions to simplify the outer join Enhance predicate pushdown over join Support the init_vector argument for the built-in function AES_ENCRYPT/AES_DECRYPT Fixed Fix a bug in the Format() function for some expressions Fix the session time in show processlist Fix INFORMATION_SCHEMA.SCHEMATA to show correct charset and collation Fix incorrect unquoted functions for JSON escape sequences Consider the timezone when adding an index in the timestamp column Fix predicate pushdown for UnionScan Fix mistaken conversion from the outer join to the inner join Fix a bug caused by the schema of union Weekly update in TiKV and PD Last week, we landed 14 PRs in the TiKV and PD repositories.Added Add the sha1 built-in function Add unpushed built-in UDFs Log1Arg and Log2Args Improved Refactor Month by using new handle_invalid_time_error Make Runable::run a default method Move Coprocessor to the read pool Adjust the PD project layout Make some parameters configurable in the simulator Fixed Fix the from_hex bug Fix micro_secs of Duration Fix the panic of adjacent-region-scheduler after PD transfers the leader Fix the DisableNamespaceRelocation option clone behavior New contributors (Thanks!) TiDB: FateTHarlaown Kingwl chenyanzhe TiKV: haoxiang47 koushiro sch00lb0y docs-cn: oasangqi "}, {"url": "https://pingcap.com/blog-cn/tikv-cluster-migration/", "title": "TiKV 集群版本的安全迁移", "content": " 问题描述 在 TiDB 的产品迭代中,不免会碰到一些兼容性问题出现。通常协议上的兼容性 protobuf 已经能帮我们处理的很好,在进行功能开发,性能优化时,通常会保证版本是向后兼容的,但并不保证向前兼容性,因此,当集群中同时有新旧版本节点存在时,旧版本不能兼容新版本的特性,就有可能造成该节点崩溃,影响集群可用性,甚至丢失数据。目前在有不兼容的版本升级时,会要求进行离线升级,但这会影响到服务,我们需要一个适合的机制来进行不停服务的升级。因此我们需要在进行滚动升级时,让这些不能保证整个集群的向后兼容性的功能不被启用。只有在保证集群中所有节点都已经升级完成后,我们才安全的启用这些功能。常见的当我们对引入新的 RaftCommand 的时候,旧版本的 TiKV 并不能识别新的添加的 RaftCommand,对于不能认知的 RaftCommand TiKV 有不同的处理,可能会报错退出或忽略。比如为了支持 Raft Learner, 在 raftpb 里对添加新的 ConfChange 类型。 当 PD 在进行 Region 调度时,会先发送 AddLearner 到 TiKV 上,接受到这个命令的肯定是这个 Region 的 Leader,在进行一系列检查后,会将该命令 Proposal, 而 Follwer 如果是旧版本的话,在 Apply 这条 Command 就会出错。而在滚动升级时,很有可能存在 Leader 是新版本,Follwer 是老版本的情况。引入版本检查机制 TiDB 的版本定义是遵循 Semver 的版本规则的。版本格式一般由主版本号(Major),次版本号(Minor),修订号(Patch),版本号递增规则如下: 主版本号:当进行了不兼容的 API 修改。 次版本号:当做了向下兼容的功能性新增。 修订号:当做了向下兼容的问题修正。 先行版本号(PreRelase)及版本编译信息可以加到“主版本号.次版本号.修订号”的后面,作为延伸。比如 TiDB 目前的版本是 2.1.0-beta,先行版号为 beta 版。在此之前,集群并没有版本的概念,虽然每个组件都有各自的版本信息,但各个节点的各自组件的版本都可以任意的。没有一个管理机制可以管理或查看所有组件的版本信息。为了解决滚动升级过程中存在多个版本的兼容性问题,这里引入集群版本的概念,并由 TiDB 集群的中心节点 PD 来进行管理和检查。具体实现 1.升级集群 在 PD 中,会设置一个 cluster_version 的键值对,对应当前运行集群中 TiKV 节点中最旧的版本。也就是必须要兼容这个版本, 因此不能打开集群中其他新版本的节点的一些不兼容的特性。在集群启动的时候,每个 TiKV 都需要向 PD 注册,注册时会带上版本信息。当当前 TiKV 的版本低于集群版本的时候,该 TiKV 会注册失败。因为此时集群的版本已经是更高的版本了,而加入旧版本的节点需要对旧版本进行兼容,为了防止已有的特性降级,直接拒绝不兼容的版本加入,目前默认主版本号和此版本号一样则为兼容的版本。如果 TiKV 的版本高于或等于当前的 cluster_version 时, TiKV 能够注册成功并成功启动。每次注册都会触发 PD 的一次检查,会检测当前集群中正常运行的 TiKV 的最低版本,并与当前的 cluster_version 进行比对,如果最低版本比 cluster_version 更加新,则将 cluster_version 更新。因此每次滚动升级的时候,能够自动更新集群的版本。2. 版本特性的开启 TiKV 很多功能是需要 PD 的参与,目前这些新功能的开启也是通过 PD 进行控制的。在 PD 中,会将每个版本新特性记录下来,在 TiKV 2.0 中,对应有 Raft Leaner, Region Merge。 TiKV 2.1 中有 Batch Split,Joint Consensus 等。这些特性都需要 PD 的参与与控制。比如说 Add Leaner,Region Merge,Joint Consensus 需要 PD 下发调度给 TiKV,Batch Split 则是 TiKV 主动发起并请求 PD 分配新的 Region ID。因此这些功能都是能通过 PD 进行控制的。PD 会通过比对当前的集群版本,选择开启当前集群版本所支持的新特性。从而保证版本的兼容性。3. 集群回滚 当升级完成后,如果遇到问题需要进行集群进行回滚时, 需要手动修改集群版本后。PD 提供了 pdctl 可以通过命令手动修改集群的 cluster_version,这时旧版本的 TiKV 就能注册并启动,从而进行回滚。PD 对 cluster_version 是通过 etcd 进行了持久化,在每次 PD 启动的时候,leader 都会从 etcd kv 中加载出 clustrer_version,然后提供服务。从而保证在 PD leader 切换后 cluster_version 的一致性。另外 PD 本身的版本可能会小于当前 cluster_version。因此在滚动升级的时候,需要先升级 PD,如果只升级了 TiKV,虽然 cluster_version 已经更新到新的版本的,但 PD 并不能开启新的功能,因为对它来说是不支持的。如果出现这种情况,PD 的日志中会有报警。在升级的时候,最好按 PD,TiKV,TiDB 的顺序逐一对各个组件。后续计划 上面提到的新功能特性一般都是需要 PD 参与的。而有些特性不需要PD的参与,因此需要保证这种特性在 TiKV 之间是可以兼容的,实现的时候可以采用类是 http2 <-> http 的方式,对请求进行降级装发,保留两套接口等。另为 TiDB 目前是自身保证可以无缝兼容,但与 TiKV 可能存在兼容性问题,往后同样考虑让TiDB 也在 PD上进行注册。"}, {"url": "https://pingcap.com/meetup/meetup-20180919-no74/", "title": "【Infra Meetup No.74】TitanDB 首次公开分享", "content": "上周六在广州举办的 Infra Meetup No.74 上,我司 TiKV 核心开发工程师黄华超老师为大家介绍了我们自研的 TitanDB——TitanDB 是基于 RocksDB 做的 key-value 分离的实现,主要解决大 value 写放大严重的问题。这次 Meetup 是 TitanDB 第一次公开分享。现场的小伙伴从 TiDB 的架构开始,由浅入深,最后对 TiKV、TitanDB 的架构都有了深入的了解,分享结束后的自由讨论依然非常热烈~ 以下是视频 & 文字回顾,enjoy~ 视频 | Infra Meetup No.74 - 黄华超 - TitanDB PPT 下载链接 华超老师先给大家讲解了 TiDB 和 TiKV 各自的架构,以及 TiDB 和 TiKV 的读写交互流程,并且解答了大家的一些问题。然后集中介绍了 TiKV 存储相关内容,包括 TiKV 是如何使用 RocksDB 的,使用过程中遇到的一些问题以及写放大的计算和如何在读写之间做权衡。最后介绍了 KV 分离的概念以及 Badger 和 TitanDB 的实现和优化。TitanDB 是基于 RocksDB 做的 key-value 分离的实现,主要解决大 value 写放大严重的问题。TitanDB 通过把大的 value 从 LSM-Tree 中分离出来,减少 LSM-Tree 的写放大,但是会对读的性能造成一些影响,实际使用中需要根据业务情况选择把多大的 value 分离出来。TitanDB 可以说是给读写放大以及空间放大之间的权衡提供另外一种选择。 PingCAP Infra Meetup作为一个基础架构领域的前沿技术公司,PingCAP 希望能为国内真正关注技术本身的 Hackers 打造一个自由分享的平台。自 2016 年 3 月 5 日开始,我们定期在周末举办 Infra Meetup,邀请业内大牛与大家深度探讨基础架构领域的前瞻性技术思考与经验。在这里,我们希望提供一个高水准的前沿技术讨论空间,让大家真正感受到自由的开源精神魅力。 "}, {"url": "https://pingcap.com/weekly/2018-09-17-tidb-weekly/", "title": "Weekly update (September 10 ~ September 16, 2018)", "content": " Weekly update in TiDB Last week, we landed 35 PRs in the TiDB repository.Added Add a design document for TiDB cluster’s system timezone Support resigning the DDL owner and use the ddl/owner/resign HTTP method Write system timezone into the MYSQL.TIDB table in the bootstrap stage Add two built-in functions decode and encode Add a proposal document for a Volcano/Cascades model based SQL planner Improved Make the decimal default precision visible in SHOW CREATE TABLE Use the pumps client to write binlog files Improve the error message of GC life time Fill the data length fields for INFORMATION_SCHEMA.TABLES Support more built-in JSON functions Refactor the INFORMATION_SCHEMA.CHARSETS and INFORMATION_SCHEMA.COLLATIONS tables Register the metrics when TiDB starts up Store topN slow queries in the domain package Split property related code into a single package Reduce the interval for checking create table/schema Merge multiple EQ or In expressions if possible when calculating the range Use UnsafeDestroyRange instead of DeleteRange in GC Make updateRecord easier to understand Update the way of using the index feedback Move the error library from juju/errors to pkg/errors Fixed Fix a bug in INSERT ... ON DUPLICATE KEY UPDATE Consider the timezone when calculating the default value for datetime Fix parsing datetime from string Use the inferred type as the column type in the schema Fix the default NUMBER_SCALE value of the float type in INFORMATION_SCHEMA.COLUMNS Weekly update in TiSpark Last week, we landed 1 PR in the TiSpark repository.Fixed Resolve the conflicting jackson version introduced by typesafe.play Weekly update in TiKV and PD Last week, we landed 28 PRs in the TiKV and PD repositories.Added Add new built-in functions builtin-log2 and builtin-log10 Scale a TiKV cluster Implement DestroyRange Add a thread pool scheduler Fixed Fix the panic issue about the hot store command Suppress the growth of EntryCache when a TiKV peer is down Update the follower size and keys after a commit is merged Broadcast the commit for urgent requests Flush logs before exiting Remove ReadDelegate lazily when a peer is destroyed asynchronously Fix a check about messages from the merged Region Improved Make the TSO time decoding in pd-ctl more accurate Reduce the scheduler messages Use asynchronous snapshots in scheduler Split the txn process module Remove Generic from DAGContext Introduce Deadline and a new ReqContext New contributors (Thanks!) tidb: kuafou tikv: sllt docs-cn: ethercflow "}, {"url": "https://pingcap.com/blog/series-c-announcement/", "title": "PingCAP Raises $50 Million in Series C Round, Sets Eyes on Global Expansion, Cross-Cloud Offering, and More Core Technology Investment", "content": "Read the coverage on TechCrunch, Business Insider, SiliconANGLEPingCAP Raises $50 Million in Series C RoundSAN MATEO, CA., September 11, 2018 – PingCAP, a leading distributed database company that created the popular cloud-native NewSQL database TiDB, announces a $50 million Series C funding round led by FOSUN and Morningside Venture Capital. All previous investors—China Growth Capital, Yunqi Partners, Matrix Partners China, and others—have also participated in this round. PingCAP plans to use this new capital to expand the TiDB ecosystem globally, build cross-cloud product offering, and invest in innovation of its core technology.“Since day 1, we have made it our mission to build a database of the future–one that helps enterprises unleash the power of their data creatively, anywhere in the world,” says co-founder and CEO Max Liu. “With this new funding round, we will be one step closer to fulfilling that mission.”PingCAP’s flagship product, TiDB, is a hybrid transactional and analytical processing (HTAP) database that powers both distributed transactions and real-time analytics. It features horizontal scalability, strong consistency, and high availability with MySQL compatibility, serving as a one-stop database solution for both OLTP (Online Transactional Processing) and OLAP (Online Analytical Processing) workloads.“A new breed of database vendors, sometimes referred to as NewSQL databases, are coming on the scene with offerings blending operational and analytical processes, which has emerged as an appealing use case for many enterprises,” says James Curtis, Senior Analyst, Data Platforms and Analytics at 451 Research. “PingCAP is among these NewSQL database vendors and is noted for its open source, modular-based database that enables hybrid operational and analytic processing to occur in a singular system.”As one of the leading open source HTAP databases in the industry, TiDB has been adopted by more than 300 companies, from banking and e-commerce, to fintech, gaming, and travel. Its distributed transactional key-value storage component, TiKV, was recently accepted as a Cloud Native Computing Foundation project.“After three years of hard work, rapid product development, and cutting-edge engineering, PingCAP and its open source community have made the promise of an HTAP database a reality. We are excited to support the future growth of this amazing team,” says Yonggang Cong, Vice President and Managing Director of FOSUN.“The database industry has always been a competitive arena, and PingCAP has secured a prominent spot in this crowded field by becoming the go-to solution for many large-scale Internet companies and financial services enterprises in China,” says Richard Liu, Managing Director of Morningside Venture Capital. “Thus, we are glad to grow with PingCAP and continue building the TiDB ecosystem together.”About PingCAPPingCAP was founded in April 2015, and provides enterprise-level and cloud-based services and technology for TiDB, a cloud-native NewSQL database which the company began building since its inception. Its mission is to build a hybrid transactional and analytical processing database with global scalability, so companies can count on TiDB as its single unifying database solution, spend less time managing multiple databases, and more time delivering business value for their customers and users. PingCAP has a global customer base that includes Mobike, Bank of Beijing, Hulu, Lenovo, and Ele.me. For more information, visit: www.pingcap.com."}, {"url": "https://pingcap.com/weekly/2018-09-10-tidb-weekly/", "title": "Weekly update (September 03 ~ September 09, 2018)", "content": " Weekly update in TiDB Last week, we landed 39 PRs in the TiDB repository.Added Add different labels for restricted SQL and general SQL metrics Add the USR1 signal handler to dump goroutine Use the point get plan for the UPDATE statement Support load data with IgnoreLines Support the json_contains builtin function Improved Make Analyze Buckets number configurable Set HIGH_PRIORITY for the bootstrap SQL statements Only check the range typed partition when creating a partitioned table Make a tiny refactor in the reorganization stage of adding indices Relax the tso backoff limit Reduce chunk’s iterator function call Improve compatibility for the MariaDB client Do AutoAnalyze on a certain period of a day Change the logic of converting the logical join to the index join Read the inner table and build hash table parallel in hash join Add batch copy to the inner join and the left and right outer join Add a ctxPool field to the worker struct to make executing the SQL statement in the DDL package possible Fixed Fix some datetime related cases which are inconsistent with MySQL Fix a compatibility problem of analyzing period variables Fix an error in the parser when parsing a single line comment ended with a newline character Fix an issue that the gc_delete_range table is queried with a wrong form of timestamp Fix an issue that the bit type can use null as its default value Return the correct column name and column label name Fix a panic when logging detailed statistics Fix a wrong count output of explain for the TableScan plan Fix the update join result when the join table order is changed Fix the issue that creating a partitioned table with bigint columns fails Weekly update in TiSpark Last week, we released a new version 1.1 and landed 10 PRs in the TiSpark repository.Fixed Remove the experimental split function and related parameters Fix the SharedState behavior in ThriftServer Fix the issue that start-tithriftserver.sh loses extra options Weekly update in TiKV and PD Last week, we landed 50 PRs in the TiKV and PD repositories.Added Add new built-in functions: builtin-Greatest*/Least* builtin-BitCount builtin-LTrim/RTrim builtin-math.Sin builtin-Rand/RandWithSeed builtin-Reverse/ReverseBinary) builtin-CharLength builtin-HexIntArg/HexStrArg builtin-Asin/Acos) builtin-Inet6Ntoa builtin-MD5 builtin-Cot/Degrees builtin-Elt builtin-LastDay builtin-Month Fixed Always update read delegate’s Regions to avoid stale Region information in LocalReader Remove read delegate on conf change RemoveNode Do not drop MsgRequestPreVote messages from newly split Regions Improved Reduce key clone in GC Limit the garbage cleanup speed to avoid blocking snapshot application Remove extra Region clone when handling Region heartbeats Clean up residual Region clone Start schedulers based on the proportion of Regions New contributors (Thanks!) TiKV: WPH95 chux0519 intellild liufuyang malc0lm mtunique TiDB: llvim xiangyuf "}, {"url": "https://pingcap.com/blog-cn/use-tikv-to-build-distributed-redis-service/", "title": "使用 TiKV 构建分布式类 Redis 服务", "content": " 什么是 Redis Redis 是一个开源的,高性能的,支持多种数据结构的内存数据库,已经被广泛用于数据库,缓存,消息队列等领域。它有着丰富的数据结构支持,譬如 String,Hash,Set 和 Sorted Set,用户通过它们能构建自己的高性能应用。Redis 非常快,没准是世界上最快的数据库了,它虽然使用内存,但也提供了一些持久化机制以及异步复制机制来保证数据的安全。Redis 的不足 Redis 非常酷,但它也有一些问题: 内存很贵,而且并不是无限容量的,所以我们不可能将大量的数据存放到一台机器。 异步复制并不能保证 Redis 的数据安全。 Redis 提供了 transaction mode,但其实并不满足 ACID 特性。 Redis 提供了集群支持,但也不能支持跨多个节点的分布式事务。 所以有时候,我们需要一个更强大的数据库,虽然在延迟上面可能赶不上 Redis,但也有足够多的特性,譬如: 丰富的数据结构 高吞吐,能接受的延迟 强数据一致 水平扩展 分布式事务 为什么选择 TiKV 大约 4 年前,我开始解决上面提到的 Redis 遇到的一些问题。为了让数据持久化,最直观的做法就是将数据保存到硬盘上面,而不是在内存里面。所以我开发了 LedisDB,一个使用 Redis 协议,提供丰富数据结构,但将数据放在 RocksDB 的数据库。LedisDB 并不是完全兼容 Redis,所以后来,我和其他同事继续创建了 RebornDB,一个完全兼容 Redis 的数据库。 无论是 LedisDB 还是 RebornDB,因为他们都是将数据放在硬盘,所以能存储更大量的数据。但它们仍然不能提供 ACID 的支持,另外,虽然我们可以通过 codis 去提供集群的支持,我们也不能很好的支持全局的分布式事务。所以我们需要另一种方式,幸运的是,我们有 TiKV。TiKV 是一个高性能,支持分布式事务的 key-value 数据库。虽然它仅仅提供了简单的 key-value API,但基于 key-value,我们可以构造自己的逻辑去创建更强大的应用。譬如,我们就构建了 TiDB ,一个基于 TiKV 的,兼容 MySQL 的分布式关系型数据库。TiDB 通过将 database 的 schema 映射到 key-value 来支持了相关 SQL 特性。所以对于 Redis,我们也可以采用同样的办法 - 构建一个支持 Redis 协议的服务,将 Redis 的数据结构映射到 key-value 上面。如何开始 整个架构非常简单,我们仅仅需要做的就是构建一个 Redis 的 Proxy,这个 Proxy 会解析 Redis 协议,然后将 Redis 的数据结构映射到 key-value 上面。Redis Protocol Redis 协议被叫做 RESP(Redis Serialization Protocol),它是文本类型的,可读性比较好,并且易于解析。它使用 “rn” 作为每行的分隔符并且用不同的前缀来代表不同的类型。例如,对于简单的 String,第一个字节是 “+”,所以一个 “OK” 行就是 “+OKrn”。 大多数时候,客户端会使用最通用的 Request-Response 模型用于跟 Redis 进行交互。客户端会首先发送一个请求,然后等待 Redis返回结果。请求是一个 Array,Array 里面元素都是 bulk strings,而返回值则可能是任意的 RESP 类型。Redis 同样支持其他通讯方式:Pipeline - 这种模式下面客户端会持续的给 Redis 发送多个请求,然后等待 Redis 返回一个结果。 Push - 客户端会在 Redis 上面订阅一个 channel,然后客户端就会从这个 channel 上面持续受到 Redis push 的数据。下面是一个简单的客户端发送 LLEN mylist 命令到 Redis 的例子:C: *2rn C: $4rn C: LLENrn C: $6rn C: mylistrn S: :48293rn 客户端会发送一个带有两个 bulk string 的 array,第一个 bulk string 的长度是 4,而第二个则是 6。Redis 会返回一个 48293 整数。正如你所见,RESP 非常简单,自然而然的,写一个 RESP 的解析器也是非常容易的。作者创建了一个 Go 的库 goredis,基于这个库,我们能非常容易的从连接上面解析出 RESP,一个简单的例子:// Create a buffer IO from the connection. br := bufio.NewReaderSize(conn, 4096) // Create a RESP reader. r := goredis.NewRespReader(br) // Parse the Request req := r.ParseRequest() 函数 ParseRequest 返回一个解析好的 request,它是一个 [][]byte 类型,第一个字段是函数名字,譬如 “LLEN”,然后后面的字段则是这个命令的参数。TiKV 事务 API 在我们开始之前,作者将会给一个简单实用 TiKV 事务 API 的例子,我们调用 Begin 开始一个事务:txn, err := db.Begin() 函数 Begin 创建一个事务,如果出错了,我们需要判断 err,不过后面作者都会忽略 err 的处理。当我们开始了一个事务之后,我们就可以干很多操作了:value, err := txn.Get([]byte(“key”)) // Do something with value and then update the newValue to the key. txn.Put([]byte(“key”), newValue) 上面我们得到了一个 key 的值,并且将其更新为新的值。TiKV 使用乐观事务模型,它会将所有的改动都先缓存到本地,然后在一起提交给 Server。// Commit the transaction txn.Commit(context.TODO()) 跟其他事务处理一样,我们也可以回滚这个事务:txn.Rollback() 如果两个事务操作了相同的 key,它们就会冲突。一个事务会提交成功,而另一个事务会出错并且回滚。映射 Data structure 到 TiKV 现在我们知道了如何解析 Redis 协议,如何在一个事务里面做操作,下一步就是支持 Redis 的数据结构了。Redis 主要有 4 中数据结构:String,Hash,Set 和 Sorted Set,但是对于 TiKV 来说,它只支持 key-value,所以我们需要将这些数据结构映射到 key-value。首先,我们需要区分不同的数据结构,一个非常容易的方式就是在 key 的后面加上 Type flag。例如,我们可以将 ’s’ 添加到 String,所以一个 String key “abc” 在 TiKV 里面其实就是 “abcs”。对于其他类型,我们可能需要考虑更多,譬如对于 Hash 类型,我们需要支持如下操作:HSET key field1 value1 HSET key field2 value2 HLEN key 一个 Hash 会有很多 fields,我有时候想知道整个 Hash 的个数,所以对于 TiKV,我们不光需要将 Hash 的 key 和 field 合在一起变成 TiKV 的一个 key,也同时需要用另一个 key 来保存整个 Hash 的长度,所以整个 Hash 的布局类似:key + ‘h’ -> length key + ‘f’ + field1 -> value key + ‘f’ + field2 -> value 如果我们不保存 length,那么如果我们想知道 Hash 的 length,每次都需要去扫整个 Hash 得到所有的 fields,这个其实并不高效。但如果我们用另一个 key 来保存 length,任何时候,当我们加入一个新的 field,我们都需要去更新这个 length 的值,这也是一个开销。对于我来说,我倾向于使用另一个 key 来保存 length,因为 HLEN 是一个高频的操作。例子 作者构建了一个非常简单的例子 example ,里面只支持 String 和 Hash 的一些操作,我们可以 clone 下来并编译:git clone https://github.com/siddontang/redis-tikv-example.git $GOPATH/src/github.com/siddontang/redis-tikv-example cd $GOPATH/src/github.com/siddontang/redis-tikv-example go build 在运行之前,我们需要启动 TiKV,可以参考 instruction,然后执行:./redis-tikv-example 这个例子会监听端口 6380,然后我们可以用任意的 Redis 客户端,譬如 redis-cli 去连接:redis-cli -p 6380 127.0.0.1:6380> set k1 a OK 127.0.0.1:6380> get k1 "a" 127.0.0.1:6380> hset k2 f1 a (integer) 1 127.0.0.1:6380> hget k2 f1 "a" 尾声 现在已经有一些公司基于 TiKV 来构建了他们自己的 Redis Server,并且也有一个开源的项目 tidis 做了相同的事情。tidis 已经比较完善,如果你想替换自己的 Redis,可以尝试一下。 正如同你所见,TiKV 其实算是一个基础的组件,我们可以在它的上面构建很多其他的应用。如果你对我们现在做的事情感兴趣,欢迎联系我:tl@pingcap.com。"}, {"url": "https://pingcap.com/blog-cn/tidb-source-code-reading-18/", "title": "TiDB 源码阅读系列文章(十八)tikv-client(上)", "content": " 在整个 SQL 执行过程中,需要经过 Parser,Optimizer,Executor,DistSQL 这几个主要的步骤,最终数据的读写是通过 tikv-client 与 TiKV 集群通讯来完成的。为了完成数据读写的任务,tikv-client 需要解决以下几个具体问题: 如何定位到某一个 key 或 key range 所在的 TiKV 地址? 如何建立和维护和 tikv-server 之间的连接? 如何发送 RPC 请求? 如何处理各种错误? 如何实现分布式读取多个 TiKV 节点的数据? 如何实现 2PC 事务? 我们接下来就对以上几个问题逐一解答,其中 5、6 会在下篇中介绍。如何定位 key 所在的 tikv-server 我们需要回顾一下之前 《三篇文章了解 TiDB 技术内幕——说存储》 这篇文章中介绍过的一个重要的概念:Region。TiDB 的数据分布是以 Region 为单位的,一个 Region 包含了一个范围内的数据,通常是 96MB 的大小,Region 的 meta 信息包含了 StartKey 和 EndKey 这两个属性。当某个 key >= StartKey && key < EndKey 的时候,我们就知道了这个 key 所在的 Region,然后我们就可以通过查找该 Region 所在的 TiKV 地址,去这个地址读取这个 key 的数据。获取 key 所在的 Region, 是通过向 PD 发送请求完成的。PD client 实现了这样一个接口:GetRegion(ctx context.Context, key []byte) (*metapb.Region, *metapb.Peer, error)通过调用这个接口,我们就可以定位这个 key 所在的 Region 了。如果需要获取一个范围内的多个 Region,我们会从这个范围的 StartKey 开始,多次调用 GetRegion 这个接口,每次返回的 Region 的 EndKey 做为下次请求的 StartKey,直到返回的 Region 的 EndKey 大于请求范围的 EndKey。以上执行过程有一个很明显的问题,就是我们每次读取数据的时候,都需要先去访问 PD,这样会给 PD 带来巨大压力,同时影响请求的性能。为了解决这个问题,tikv-client 实现了一个 RegionCache 的组件,缓存 Region 信息, 当需要定位 key 所在的 Region 的时候,如果 RegionCache 命中,就不需要访问 PD 了。RegionCache 的内部,有两种数据结构保存 Region 信息,一个是 map,另一个是 b-tree,用 map 可以快速根据 region ID 查找到 Region,用 b-tree 可以根据一个 key 找到包含该 key 的 Region。严格来说,PD 上保存的 Region 信息,也是一层 cache,真正最新的 Region 信息是存储在 tikv-server 上的,每个 tikv-server 会自己决定什么时候进行 Region 分裂,在 Region 变化的时候,把信息上报给 PD,PD 用上报上来的 Region 信息,满足 tidb-server 的查询需求。当我们从 cache 获取了 Region 信息,并发送请求以后, tikv-server 会对 Region 信息进行校验,确保请求的 Region 信息是正确的。如果因为 Region 分裂,Region 迁移导致了 Region 信息变化,请求的 Region 信息就会过期,这时 tikv-server 就会返回 Region 错误。遇到了 Region 错误,我们就需要清理 RegionCache,重新获取最新的 Region 信息,并重新发送请求。如何建立和维护和 tikv-server 之间的连接 当 TiDB 定位到 key 所在的 tikv-server 以后,就需要建立和 TiKV 之间的连接,我们都知道, TCP 连接的建立和关闭有不小的开销,同时会增大延迟,使用连接池可以节省这部分开销,TiDB 和 tikv-server 之间也维护了一个连接池 connArray。TiDB 和 TiKV 之间通过 gRPC 通信,而 gPRC 支持在单 TCP 连接上多路复用,所以多个并发的请求可以在单个连接上执行而不会相互阻塞。理论上一个 tidb-server 和一个 tikv-server 之间只需要维护一个连接,但是在性能测试的时候发现,单个连接在并发-高的时候,会成为性能瓶颈,所以实际实现的时候,tidb-server 对每一个 tikv-server 地址维护了多个连接,并以 round-robin 算法选择连接发送请求。连接的个数可以在 config 文件里配置,默认是 16。如何发送 RPC 请求 tikv-client 通过 tikvStore 这个类型,实现 kv.Storage 这个接口,我们可以把 tikvStore 理解成 tikv-client 的一个包装。外部调用 kv.Storage 的接口,并不需要关心 RPC 的细节,RPC 请求都是 tikvStore 为了实现 kv.Storage 接口而发起的。实现不同的 kv.Storage 接口需要发送不同的 RPC 请求。比如实现 Snapshot.BatchGet 需要tikvpb.TikvClient.KvBatchGet 方法;实现 Transaction.Commit,需要 tikvpb.TikvClient.KvPrewrite, tikvpb.TikvClient.KvCommit 等多个方法。在 tikvStore 的实现里,并没有直接调用 RPC 方法,而是通过一个 Client 接口调用,做这一层的抽象的主要目的是为了让下层可以有不同的实现。比如用来测试的 mocktikv 就自己实现了 Client 接口,通过本地调用实现,并不需要调用真正的 RPC。rpcClient 是真正实现 RPC 请求的 Client 实现,通过调用 tikvrpc.CallRPC,发送 RPC 请求。tikvrpc.CallRPC 再往下层走,就是调用具体每个 RPC 生成的代码了,到了生成的代码这一层,就已经是 gRPC 框架这一层的内容了,我们就不继续深入解析了,感兴趣的同学可以研究一下 gRPC 的实现。如何处理各种错误 我们前面提到 RPC 请求都是通过 Client 接口发送的,但实际上这个接口并没有直接被各个 tikvStore 的各个方法调用,而是通过一个 RegionRequestSender 的对象调用的。RegionRequestSender 主要的工作除了发送 RPC 请求,还要负责处理各种可以重试的错误,比如网络错误和部分 Region 错误。RPC 请求遇到的错误主要分为两大类:Region 错误和网络错误。Region 错误 是由 tikv-server 收到请求后,在 response 里返回的,常见的有以下几种: NotLeader这种错误的原因通常是 Region 的调度,PD 为了负载均衡,可能会把一个热点 Region 的 leader 调度到空闲的 tikv-server 上,而请求只能由 leader 来处理。遇到这种错误就需要 tikv-client 重试,把请求发给新的 leader。 StaleEpoch这种错误主要是因为 Region 的分裂,当 Region 内的数据量增多以后,会分裂成多个新的 Region。新的 Region 包含的 range 是不同的,如果直接执行,返回的结果有可能是错误的,所以 TiKV 就会拒绝这个请求。tikv-client 需要从 PD 获取最新的 Region 信息并重试。 ServerIsBusy这个错误通常是因为 tikv-server 积压了过多的请求处理不完,tikv-server 如果不拒绝这个请求,队列会越来越长,可能等到客户端超时了,请求还没有来的及处理。所以做为一种保护机制,tikv-server 提前返回错误,让客户端等待一段时间后再重试。 另一类错误是网络错误,错误是由 SendRequest 的返回值 返回的 error 的,遇到这种错误通常意味着这个 tikv-server 没有正常返回请求,可能是网络隔离或 tikv-server down 了。tikv-client 遇到这种错误,会调用 OnSendFail 方法,处理这个错误,会在 RegionCache 里把这个请求失败的 tikv-server 上的所有 region 都 drop 掉,避免其他请求遇到同样的错误。当遇到可以重试的错误的时候,我们需要等待一段时间后重试,我们需要保证每次重试等待时间不能太短也不能太长,太短会造成多次无谓的请求,增加系统压力和开销,太长会增加请求的延迟。我们用指数退避的算法来计算每一次重试前的等待时间,这部分的逻辑是在 Backoffer 里实现的。在上层执行一个 SQL 语句的时候,在 tikv-client 这一层会触发多个顺序的或并发的请求,发向多个 tikv-server,为了保证上层 SQL 语句的超时时间,我们需要考虑的不仅仅是单个 RPC 请求,还需要考虑一个 query 整体的超时时间。为了解决这个问题,Backoffer 实现了 fork 功能, 在发送每一个子请求的时候,需要 fork 出一个 child Backoffer,child Backoffer 负责单个 RPC 请求的重试,它记录了 parent Backoffer 已经等待的时间,保证总的等待时间,不会超过 query 超时时间。对于不同错误,需要等待的时间是不一样的,每个 Backoffer 在创建时,会根据不同类型,创建不同的 backoff 函数。以上就是 tikv-client 上篇的内容,我们在下篇会详细介绍实现分布式计算相关的 copIterator 和实现分布式事务的 twoPCCommiter。"}, {"url": "https://pingcap.com/meetup/meetup-20180905-no73/", "title": "【Infra Meetup No.73】TiKV 原理剖析", "content": "在上周六举办的 Infra Meetup No.73 上,我司 TiKV 核心开发工程师张金鹏老师分享了 TiKV 的原理与正在开发的新功能,整整讲满了 100 分钟~这可能是近期关于 TiKV 最深入的一次分享交流了吧~haha),结束后现场的小伙伴三五成群,意犹未尽地聚在一起讨论交流,钻研精神可嘉!以下是现场视频&文字回顾,enjoy~ 视频 | Infra Meetup No.74 - 张金鹏 - TiKV 原理剖析 PPT 下载链接 金鹏老师首先介绍了 TiKV 中的几个概念,包括 Region、Peer 和 ts,其中 Region 代表一段连续的数据,Peer 是 Region 的一个副本,ts 表示时间戳。然后从宏观的角度分析了数据在 TiKV 之间是如何分布的,以及如何进行 balance,并介绍了 TiKV 的分层结构,分析了读和写请求在 TiKV 内部的各个层之间是怎样流转的。接着,他重点介绍了 TiKV 的几个核心组件,包括 Multi-raft、RocksDB、分布式事务、Coprocessor、GC 和调度。其中 Multi-raft 涉及到 region 的 split 和 merge,以及 leader lease、pre-vote、learner 等概念;RocksDB 相关的内容包括 column family、delete files in range、ingest sst files、多线程 compaction、sub-compaction 等。(课代表温馨提示:金鹏老师对这些概念的讲解非常细致深入,也耐心解答了现场小伙伴的提问, 对这些名词不太熟悉的朋友赶紧点开视频跳到相关章节观看吧!)随后,他举例讲解了 TiDB 的表数据是如何映射成 KV 数据,并详细介绍了 TiKV 中的 MVCC 机制,以及是如何支持分布式事务的。GC 模块主要负载清理掉过期的数据,同时 TiKV 针对 drop/truncate table/index 进行了优化,使用 RocksDB 的 delete files in range 删除过期的数据,达到快速回收空间的效果。PD 通过 TiKV 上报的读写流量,进行动态调度,使集群中各个 TiKV 节点的负载达到均衡,充分利用集群的资源。最后金鹏老师透露,TiKV 还在不断地完善中,多个新功能正在开发中,包括消除系统瓶颈的多线程 raftstore 多线程 apply 功能,通过分离 value 来减少写放大的 TitanDB engine,加速垃圾数据回收的分布式 GC 系统,以及正在实现 raft 的 Joint Consensus 功能。欢迎大家到 TiKV Repo 逛一逛,捞一捞有趣的 issues,或者参考 这篇文章 练练手,为 TiKV 添加 built-in 函数。P.S. TiKV 在 8 月 28 日正式成为 CNCF 托管项目,源码地址变更为:github.com/tikv/tikv/。 PingCAP Infra Meetup作为一个基础架构领域的前沿技术公司,PingCAP 希望能为国内真正关注技术本身的 Hackers 打造一个自由分享的平台。自 2016 年 3 月 5 日开始,我们定期在周末举办 Infra Meetup,邀请业内大牛与大家深度探讨基础架构领域的前瞻性技术思考与经验。在这里,我们希望提供一个高水准的前沿技术讨论空间,让大家真正感受到自由的开源精神魅力。 "}, {"url": "https://pingcap.com/weekly/2018-09-03-tidb-weekly/", "title": "Weekly update (August 27 ~ September 02, 2018)", "content": " Weekly update in TiDB Last week, we landed 45 PRs in the TiDB repository.Added Enable the Mutex profiling in the TiDB server Let Analyze use the RC level and the low priority Support Grow of the chunk capacity Add job action and schema version information to metrics Forbid users to drop an important system table Support rollback when adding an index in a partitioned table Add a KeyOnly option for the Seek operation Maintain HistColl in StatsInfo of DataSource Add a TiDB tracing prototype Improved Remove goroutine_pool Remove the test coverage task from travis Rebase the auto increment ID when needed Fix the lint tool Make the duplicate error output in the Update statement more clearly Bump Go version to 1.11 Make TestTableSplit stable in the ddl package Improve compatibility for converting a string to an integer Use the shallow copy for Join Improve the propagate constant and propagate more filters Fixed Fix the Hash Join executor and break the innerTable fetcher if an error happens during fetching the outer table Fix the AutoAnalyze trigger condition Fix data race in ddl.TestStat() Add an unsigned flag to the Year type Fix the last_insert_id in INSERT... ON DUPLICATE KEY UPDATE Fix the update error of zero column size in the statistics package Fix the issue that the Year type string format has too many leading zeros in the Prepare and Execute statements Fix the insert zero timestamp bug in the Prepare statement Fix the out of range error for intdiv Fix ComStmtSendLongData when the data length is 0 Fix the INSERT... ON DUPLICATE KEY UPDATE plan Fix a bug for bit default value Fix the admin check table error when a column of the index is virtually generated Weekly update in TiSpark Last week, we landed 2 PRs in the TiSpark repository.Fixed Fix the issue that table not exists might occur when loading the table Improved Add details in the explain result Weekly update in TiKV and PD Last week, we landed 30 PRs in the TiKV and PD repositories.Added Add new built-in functions: builtin-is_ipv6 builtin-sign builtin-atan_1_arg and builtin-atan_2_args Add new documents: overview, op-guide, and client TiKV Control User Guide RocksDB Option Configuration TiKV Coprocessor Configuration Reference to CNCF Add a method to get approximate_split_keys() Add keepalive configurations Add statistics for the PD simulator Add the GetAllStores function to the PD Client interface Fixed Fix the false stale peer alert Improved Use the approximate way to split large Regions Reduce clone in the transaction process Print the help message when starting tikv-ctl without arguments Remove some unnecessary conversions in PD New contributors (Thanks!) tidb-operator: fengzixu tidb: shafreeck tikv: Observer42 caniszczyk "}, {"url": "https://pingcap.com/blog/tidb-community-200-contributors/", "title": "TiDB Reaches the 200 Contributors Milestone", "content": "Dear TiDB Contributors:As you might’ve noticed, TiDB recently added its 200th contributor. As CEO and co-founder of PingCAP who began building TiDB three years ago, I would like to thank the entire TiDB community for helping us reach this important milestone!TiDB development started in 2015. In August 2018, we welcomed our 200th contributor!Here are a few of my favorite contributions to highlight: @dbjoa (from Samsung Electronics) contributed plan cache for prepared statements, resulting in a performance gain of 27%! @spongedu (from Tencent, and previously Alibaba) has contributed over 80 (!) pull requests to TiDB and TiKV. Seeing new contributors progress from fixing a small bug to developing new features. @bb7133 first improved an error message in May 2018, and by August added propagate more filters in PropagateConstant. He is interested in the SQL optimizer and will contribute more in this area. While this achievement is worth celebrating, we know there are still lots of work ahead. Pull requests can be reviewed quicker, issues resolved faster, and documentation written clearer to make using and contributing to TiDB easier and more productive. We appreciate your patience, as we continue to improve the way we manage and grow the TiDB community.Your contributions–beyond just code, comments, and bug reports–tell an important story of how to prioritize the needs of a fast-growing open-source community and usebase, while managing the development of a system as complex as a distributed database. They inspire us to get up every morning with energy, passion, and focus on always doing what’s best for the community.So thank you again on behalf of everyone at PingCAP. You have helped make TiDB what it is today, and will continue to shape what TiDB will be tomorrow.With gratitude,Max"}, {"url": "https://pingcap.com/blog-cn/tidb-source-code-reading-17/", "title": "TiDB 源码阅读系列文章(十七)DDL 源码解析", "content": " DDL 是数据库非常核心的组件,其正确性和稳定性是整个 SQL 引擎的基石,在分布式数据库中,如何在保证数据一致性的前提下实现无锁的 DDL 操作是一件有挑战的事情。本文首先会介绍 TiDB DDL 组件的总体设计,介绍如何在分布式场景下支持无锁 schema 变更,描述这套算法的大致流程,然后详细介绍一些常见的 DDL 语句的源码实现,包括 create table、add index、drop column、drop table 这四种。DDL in TiDB TiDB 的 DDL 通过实现 Google F1 的在线异步 schema 变更算法,来完成在分布式场景下的无锁,在线 schema 变更。为了简化设计,TiDB 在同一时刻,只允许一个节点执行 DDL 操作。用户可以把多个 DDL 请求发给任何 TiDB 节点,但是所有的 DDL 请求在 TiDB 内部是由 owner 节点的 worker 串行执行的。 worker:每个节点都有一个 worker 用来处理 DDL 操作。 owner:整个集群中只有一个节点能当选 owner,每个节点都可能当选这个角色。当选 owner 后的节点 worker 才有处理 DDL 操作的权利。owner 节点的产生是用 Etcd 的选举功能从多个 TiDB 节点选举出 owner 节点。owner 是有任期的,owner 会主动维护自己的任期,即续约。当 owner 节点宕机后,其他节点可以通过 Etcd 感知到并且选举出新的 owner。 这里只是简单概述了 TiDB 的 DDL 设计,下两篇文章详细介绍了 TiDB DDL 的设计实现以及优化,推荐阅读: TiDB 的异步 schema 变更实现 TiDB 的异步 schema 变更优化 下图描述了一个 DDL 请求在 TiDB 中的简单处理流程:图 1:TiDB 中 DDL SQL 的处理流程TiDB 的 DDL 组件相关代码存放在源码目录的 ddl 目录下。 File Introduction ddl.go 包含 DDL 接口定义和其实现。 ddl_api.go 提供 create , drop , alter , truncate , rename 等操作的 API,供 Executor 调用。主要功能是封装 DDL 操作的 job 然后存入 DDL job queue,等待 job 执行完成后返回。 ddl_worker.go DDL worker 的实现。owner 节点的 worker 从 job queue 中取 job,然后执行,执行完成后将 job 存入 job history queue 中。 syncer.go 负责同步 ddl worker 的 owner 和 follower 间的 schema version。 每次 DDL 状态变更后 schema version ID 都会加 1。 ddl owner 相关的代码单独放在 owner 目录下,实现了 owner 选举等功能。另外,ddl job queue 和 history ddl job queue 这两个队列都是持久化到 TiKV 中的。structure 目录下有 list,hash 等数据结构在 TiKV 上的实现。本文接下来按照 TiDB 源码的 origin/source-code 分支讲解,最新的 master 分支和 source-code 分支代码会稍有一些差异。Create table create table 需要把 table 的元信息(TableInfo)从 SQL 中解析出来,做一些检查,然后把 table 的元信息持久化保存到 TiKV 中。具体流程如下: 语法解析:ParseSQL 解析成抽象语法树 CreateTableStmt。 编译生成 Plan:Compile 生成 DDL plan , 并 check 权限等。 生成执行器:buildExecutor 生成 DDLExec 执行器。TiDB 的执行器是火山模型。 执行器调用 e.Next 开始执行,即 DDLExec.Next 方法,判断 DDL 类型后执行 executeCreateTable , 其实质是调用 ddl_api.go 的 CreateTable 函数。 CreateTable 方法是主要流程如下: 会先 check 一些限制,比如 table name 是否已经存在,table 名是否太长,是否有重复定义的列等等限制。 buildTableInfo 获取 global table ID,生成 tableInfo , 即 table 的元信息,然后封装成一个 DDL job,这个 job 包含了 table ID 和 tableInfo,并将这个 job 的 type 标记为 ActionCreateTable。 d.doDDLJob(ctx, job) 函数中的 d.addDDLJob(ctx, job) 会先给 job 获取一个 global job ID 然后放到 job queue 中去。 DDL 组件启动后,在 start 函数中会启动一个 ddl_worker 协程运行 onDDLWorker 函数(最新 Master 分支函数名已重命名为 start),每隔一段时间调用 handleDDLJobQueue 函数去尝试处理 DDL job 队列里的 job,ddl_worker 会先 check 自己是不是 owner,如果不是 owner,就什么也不做,然后返回;如果是 owner,就调用 getFirstDDLJob 函数获取 DDL 队列中的第一个 job,然后调 runDDLJob 函数执行 job。 runDDLJob 函数里面会根据 job 的类型,然后调用对应的执行函数,对于 create table 类型的 job,会调用 onCreateTable 函数,然后做一些 check 后,会调用 t.CreateTable 函数,将 db_ID 和 table_ID 映射为 key,tableInfo 作为 value 存到 TiKV 里面去,并更新 job 的状态。 finishDDLJob 函数将 job 从 DDL job 队列中移除,然后加入 history ddl job 队列中去。 doDDLJob 函数中检测到 history DDL job 队列中有对应的 job 后,返回。 Add index add index 主要做 2 件事: 修改 table 的元信息,把 indexInfo 加入到 table 的元信息中去。 把 table 中已有了的数据行,把 index columns 的值全部回填到 index record 中去。 具体执行流程的前部分的 SQL 解析、Compile 等流程,和 create table 一样,可以直接从 DDLExec.Next 开始看,然后调用 alter 语句的 e.executeAlterTable(x) 函数,其实质调 ddl 的 AlterTable 函数,然后调用 CreateIndex 函数,开始执行 add index 的主要工作,具体流程如下: Check 一些限制,比如 table 是否存在,索引是否已经存在,索引名是否太长等。 封装成一个 job,包含了索引名,索引列等,并将 job 的 type 标记为 ActionAddIndex。 给 job 获取一个 global job ID 然后放到 DDL job 队列中去。 owner ddl worker 从 DDL job 队列中取出 job,根据 job 的类型调用 onCreateIndex 函数。 buildIndexInfo 生成 indexInfo,然后更新 tableInfo 中的 Indices,持久化到 TiKV 中去。 这里引入了 online schema change 的几个步骤,需要留意 indexInfo 的状态变化:none -> delete only -> write only -> reorganization -> public。在 reorganization -> public 时,首先调用 getReorgInfo 获取 reorgInfo,主要包含需要 reorganization 的 range,即从表的第一行一直到最后一行数据都需要回填到 index record 中。然后调用 runReorgJob , addTableIndex 函数开始填充数据到 index record中去。runReorgJob 函数会定期保存回填数据的进度到 TiKV。addTableIndex 的流程如下: 启动多个 worker 用于并发回填数据到 index record。 把 reorgInfo 中需要 reorganization 分裂成多个 range。扫描的默认范围是 [startHandle , endHandle],然后默认以 128 为间隔分裂成多个 range,之后并行扫描对应数据行。在 master 分支中,range 范围信息是从 PD 中获取。 把 range 包装成多个 task,发给 worker 并行回填 index record。 等待所有 worker 完成后,更新 reorg 进度,然后持续第 3 步直到所有的 task 都做完。 后续执行 finishDDLJob,检测 history ddl job 流程和 create table 类似。 Drop Column drop Column 只要修改 table 的元信息,把 table 元信息中对应的要删除的 column 删除。drop Column 不会删除原有 table 数据行中的对应的 Column 数据,在 decode 一行数据时,会根据 table 的元信息来 decode。具体执行流程的前部分都类似,直接跳到 DropColumn 函数开始,具体执行流程如下: Check table 是否存在,要 drop 的 column 是否存在等。 封装成一个 job, 将 job 类型标记为 ActionDropColumn,然后放到 DDL job 队列中去 owner ddl worker 从 DDL job 队列中取出 job,根据 job 的类型调用 onDropColumn 函数: 这里 column info 的状态变化和 add index 时的变化几乎相反:public -> write only -> delete only -> reorganization -> absent。 updateVersionAndTableInfo 更新 table 元信息中的 Columns。 后续执行 finishDDLJob,检测 history ddl job 流程和 create table 类似。 Drop table drop table 需要删除 table 的元信息和 table 中的数据。具体执行流程的前部分都类似,owner ddl worker 从 DDL job 队列中取出 job 后执行 onDropTable 函数: tableInfo 的状态变化是:public -> write only -> delete only -> none。 tableInfo 的状态变为 none 之后,会调用 DropTable 将 table 的元信息从 TiKV 上删除。 至于删除 table 中的数据,后面在调用 finishDDLJob 函数将 job 从 job queue 中移除,加入 history ddl job queue 前,会调用 delRangeManager.addDelRangeJob(job),将要删除的 table 数据范围插入到表 gc_delete_range 中,然后由 GC worker 根据 gc_delete_range 中的信息在 GC 过程中做真正的删除数据操作。New Parallel DDL 目前 TiDB 最新的 Master 分支的 DDL 引入了并行 DDL,用来加速多个 DDL 语句的执行速度。因为串行执行 DDL 时,add index 操作需要把 table 中已有的数据回填到 index record 中,如果 table 中的数据较多,回填数据的耗时较长,就会阻塞后面 DDL 的操作。目前并行 DDL 的设计是将 add index job 放到新增的 add index job queue 中去,其它类型的 DDL job 还是放在原来的 job queue。相应的,也增加一个 add index worker 来处理 add index job queue 中的 job。图 2:并行 DDL 处理流程并行 DDL 同时也引入了 job 依赖的问题。job 依赖是指同一 table 的 DDL job,job ID 小的需要先执行。因为对于同一个 table 的 DDL 操作必须是顺序执行的。比如说,add column a,然后 add index on column a, 如果 add index 先执行,而 add column 的 DDL 假设还在排队未执行,这时 add index on column a 就会报错说找不到 column a。所以当 add index job queue 中的 job2 执行前,需要检测 job queue 是否有同一 table 的 job1 还未执行,通过对比 job 的 job ID 大小来判断。执行 job queue 中的 job 时也需要检查 add index job queue 中是否有依赖的 job 还未执行。End TiDB 目前一共支持 十多种 DDL,具体以及和 MySQL 兼容性对比可以看 这里。剩余其它类型的 DDL 源码实现读者可以自行阅读,流程和上述几种 DDL 类似。"}, {"url": "https://pingcap.com/weekly/2018-08-27-tidb-weekly/", "title": "Weekly update (August 20 ~ August 26, 2018)", "content": " Weekly update in TiDB Last week, we landed 34 PRs in the TiDB repository.Added Make the query feedback work for the partitioned table Support a new aggregate framework for HashAggExec Fixed Fix a bug when using a correlated column as the index Fix the prepare result for zero timestamp/time/datetime Fix the Enum type flag bug Make partition by range value accept the constant expression Fix concat in the GROUP statement Fix selecting null value for table partition Use the unified infoschema in select ... information_schema.tables Fix the Format function for the Mod opcode Improved Split ranges if the slice is too big Execute the admin command with Super_priv Weekly update in TiSpark Last week, we landed 3 PRs in the TiSpark repository.Added Decode JSON to string Weekly update in TiKV and PD Last week, we landed 27 PRs in the TiKV and PD repositories.Added Add new built-in functions: builtin-cos builtin-date builtin-inet6_aton Support producing multiple split keys in split-checker Fixed Update approximate_size and approximate_keys after the Region is merged Improved Make a more efficient workflow for Raft LocalReader Remove the IsolationLevel and ScanMode options from MvccTxn Handle the API error properly instead of turning them into gRPC errors Add new forward/backward Scanners to improve the scan performance Try ask_split when ask_batch_split is incompatible Associate a buffer to AggFuncExpr to reduce memory allocation New contributors (Thanks!) TiKV: hawkingrei niedhui vkorenev TiSpark: alex-lx "}, {"url": "https://pingcap.com/blog-cn/tidb-operator-introduction/", "title": "TiDB Operator,让 TiDB 成为真正的 Cloud-Native 数据库", "content": " TiDB Operator 是 TiDB 在 Kubernetes 平台上的自动化部署运维工具。目前,TiDB Operator 已正式开源(pingcap/tidb-operator)。借助 TiDB Operator,TiDB 可以无缝运行在公有云厂商提供的 Kubernetes 平台上,让 TiDB 成为真正的 Cloud-Native 数据库。要了解 TiDB Operator,首先需要对 TiDB 和 Kubernetes 有一定了解,相信长期以来一直关注 TiDB 的同学可能对 TiDB 已经比较熟悉了。本文将首先简单介绍一下 TiDB 和 Kubernetes,聊一聊为什么我们要做 TiDB Operator,然后讲讲如何快速体验 TiDB Operator,以及如何参与到 TiDB Operator 项目中来成为 Contributor。TiDB 和 Kubernetes 简介 TiDB 作为一个开源的分布式数据库产品,具有多副本强一致性的同时能够根据业务需求非常方便的进行弹性伸缩,并且扩缩容期间对上层业务无感知。TiDB 包括三大核心组件:TiDB/TiKV/PD。  TiDB Server:主要负责 SQL 的解析器和优化器,它相当于计算执行层,同时也负责客户端接入和交互。 TiKV Server:是一套分布式的 Key-Value 存储引擎,它承担整个数据库的存储层,数据的水平扩展和多副本高可用特性都是在这一层实现。 PD Server:相当于分布式数据库的大脑,一方面负责收集和维护数据在各个 TiKV 节点的分布情况,另一方面 PD 承担调度器的角色,根据数据分布状况以及各个存储节点的负载来采取合适的调度策略,维持整个系统的平衡与稳定。 上面的这三个组件,每个角色都是一个多节点组成的集群,所以最终 TiDB 的架构看起来是这样的。Kubernetes 最早是作为一个纯粹的容器编排系统而诞生的,用户部署好 Kubernetes 集群之后,直接使用其内置的各种功能部署应用服务。 由于这个 PaaS 平台使用起来非常便利,吸引了很多用户,不同用户也提出了各种不同的需求。有些特性需求 Kubernetes 直接在其核心代码里面实现了,但是有些特性并不适合合并到主干分支。为满足这类需求,Kubernetes 开放出一些 API 供用户自己扩展,实现自己的需求。当前 Kubernetes 内部的 API 变得越来越开放,使其更像是一个跑在云上的操作系统。用户可以把它当作一套云的 SDK 或 Framework 来使用,而且可以很方便地开发组件来扩展满足自己的业务需求。对有状态服务的支持就是一个很有代表性的例子。为什么我们要做 TiDB Operator 第一,使用传统的自动化工具带来了很高的部署和运维成本。TiDB 的分层架构对于分布式系统是比较常见的,各个组件都可以根据业务需求独立水平伸缩,并且 TiKV 和 TiDB 都可以独立使用。比如,在 TiKV 之上可以构建兼容 Redis 协议的 KV 数据库,而 TiDB 也可以对接 LevelDB 这样的 KV 存储引擎。但是,这种多组件的分布式系统增加了手工部署和运维的成本。一些传统的自动化部署和运维工具如 Puppet/Chef/SaltStack/Ansible,由于缺乏全局状态管理,不能及时对各种异常情况做自动故障转移,并且很难发挥分布式系统的弹性伸缩能力。其中有些还需要写大量的 DSL 甚至与 Shell 脚本一起混合使用,可移植性较差,维护成本比较高。第二,在云时代,容器成为应用分发部署的基本单位,而谷歌基于内部使用数十年的容器编排系统 Borg 经验推出的开源容器编排系统 Kubernetes 成为当前容器编排技术事实上的标准。如今各大云厂商都开始提供托管的 Kubernetes 集群,部署在 Kubernetes 平台的应用可以不用绑定在特定云平台,轻松实现在各种云平台之间的迁移,其容器化打包和发布方式也解决了对操作系统环境的依赖。Kubernetes 项目最早期只支持无状态服务(Stateless Service)的管理。无状态服务通过 ReplicationController 定义多个副本,由 Kubernetes 调度器来决定在不同节点上启动多个 Pod,实现负载均衡和故障转移。对于无状态服务,多个副本对应的 Pod 是等价的,所以在节点出现故障时,在新节点上启动一个 Pod 与失效的 Pod 是等价的,不会涉及状态迁移问题,因而管理非常简单。 但是对于有状态服务(Stateful Service),由于需要将数据持久化到磁盘,使得不同 Pod 之间不能再认为成等价,也就不能再像无状态服务那样随意进行调度迁移。Kubernetes v1.3 版本提出 PetSet 的概念,用来管理有状态服务并于 v1.5 将其更名为 StatefulSet。StatefulSet 明确定义一组 Pod 中每个的身份,启动和升级都按特定顺序来操作。另外使用持久化卷存储(PersistentVolume)来作为存储数据的载体,当节点失效 Pod 需要迁移时,对应的 PV 也会重新挂载,而 PV 的底层依托于分布式文件系统,所以 Pod 仍然能访问到之前的数据。同时 Pod 在发生迁移时,其网络身份例如 IP 地址是会发生变化的,很多分布式系统不能接受这种情况。所以 StatefulSet 在迁移 Pod 时可以通过绑定域名的方式来保证 Pod 在集群中网络身份不发生变化。但是由于有状态服务的特殊性,当节点出现异常时,出于数据安全性考虑,Kubernetes 并不会像无状态服务那样自动做故障转移。尽管网络存储能挂载到不同的节点上供其上的 Pod 使用,但是如果出现节点故障时,简单粗暴地将网络 PV 挂载到其它节点上是比较危险的。Kubernetes 判断节点故障是基于部署在每个节点上的 Kubelet 服务是否能正常上报节点状态,Kubelet 能否正常工作与用户应用并没有必然联系,在一些特殊情况下,Kubelet 服务进程可能无法正常启动,但是节点上的业务容器还在运行,将 PV 再挂载到其它节点可能会出现双写问题。为了在 Kubernetes 上部署和管理 TiDB 这种有状态的服务,我们需要扩展 StatefulSet 的功能。TiDB Operator 正是基于 Kubernetes 内置的 StatefulSet 开发的 TiDB 集群管理和运维工具。Kubernetes 直到 v1.7 才试验性引入本地 PV,在这之前只有网络 PV,TiKV 自身在存储数据时就是多副本的,网络 PV 的多副本会增加数据冗余,降低 TiDB 的性能。在这之前我们基于 Kubernetes 内置的 hostPath volume 实现了本地 PV 满足 TiKV 对磁盘 IO 的要求。官方本地 PV 方案直到最近的 Kubernetes v1.10 才相对稳定地支持调度功能,满足用户对本地 PV 的需求。为了降低用户的使用和管理成本并且拥抱 Kubernetes 开源社区,我们又重新基于官方的本地 PV 方案实现了对数据的管理。TiDB Operator 原理解析 Operator 本质上是 Kubernetes 的控制器(Controller),其核心思想是用户给定一个 Spec 描述文件,Controller 根据 Spec 的变化,在 Kubernetes 集群中创建对应资源,并且不断调整资源使其状态满足用户预期的 Spec。上图是 TiDB Operator 工作流程原理图,其中 TidbCluster 是通过 CRD(Custom Resource Definition)扩展的内置资源类型: 用户通过 Helm 往 Kubernetes API Server 创建或更新 TidbCluster 对象。 TiDB Operator 通过 watch API Server 中的 TidbCluster 对象创建更新或删除,维护 PD/TiKV/TiDB StatefulSet, Service 和 Deployment 对象更新。 Kubernetes 根据 StatefulSet, Service 和 Deployment 对象创建更新或删除对应的容器和服务。 在第 2 步中,TiDB Operator 在更新 StatefulSet 等对象时会参考 PD API 给出的集群状态来做出 TiDB 集群的运维处理。通过 TiDB Operator 和 Kubernetes 的动态调度处理,创建出符合用户预期的 TiDB 集群。快速体验 TiDB Operator TiDB Operator 需要运行在 Kubernetes v1.10 及以上版本。TiDB Operator 和 TiDB 集群的部署和管理是通过 Kubernetes 平台上的包管理工具 Helm 实现的。运行 TiDB Operator 前请确保 Helm 已经正确安装在 Kubernetes 集群里。 如果没有 Kubernetes 集群,可以通过 TiDB Operator 提供的脚本快速在本地启动一个多节点的 Kubernetes 集群:git clone https://github.com/pingcap/tidb-operator cd tidb-operator NUM_NODES=3 # the default node number is 2 KUBE_REPO_PREFIX=uhub.ucloud.cn/pingcap manifests/local-dind/dind-cluster-v1.10.sh up 等 Kubernetes 集群准备好,就可以通过 Helm 和 Kubectl 安装部署 TiDB Operator 和 TiDB 集群了。 安装 TiDB Operatorkubectl apply -f manifests/crd.yaml helm install charts/tidb-operator --name=tidb-operator --namespace=tidb-admin 部署 TiDB 集群helm install charts/tidb-cluster --name=demo-tidb --namespace=tidb --set clusterName=demo 集群默认使用 local-storage 作为 PD 和 TiKV 的数据存储,如果想使用其它持久化存储,需要修改 charts/tidb-cluster/values.yaml 里面的 storageClassName。参与 TiDB Operator TiDB Operator 让 TiDB 成为真正意义上的 Cloud-Native 数据库,开源只是一个起点,需要 TiDB 社区和 Kubernetes 社区的共同参与。 大家在使用过程发现 bug 或缺失什么功能,都可以直接在 GitHub 上面提 issue 或 PR,一起参与讨论。要想成为 Contributor 具体可以参考 这个文档。"}, {"url": "https://pingcap.com/meetup/meetup-20180820-no72/", "title": "【Infra Meetup No.72】TiDB Operator,让 TiDB 成为真正的 Cloud-Native 数据库", "content": " TiDB Operator 是 TiDB 在 Kubernetes 平台上的自动化部署运维工具,目前已经开源。在上周六举办的 Infra Meetup 第 72 期上,我司邓栓老师为大家分享了 TiDB Operator 开源的细节,并演示了单机快速体验 TiDB Operator 的操作。 以下是邓栓老师撰写的技术详解文章和 Meetup 现场视频。希望大家通过文字和视频深入了解 TiDB Operator 之后,可以速来贡献代码、成为 Contributor !( ´▽`)  TiDB Operator 是 TiDB 在 Kubernetes 平台上的自动化部署运维工具。目前,TiDB Operator 已正式开源(pingcap/tidb-operator)。借助 TiDB Operator,TiDB 可以无缝运行在公有云厂商提供的 Kubernetes 平台上,让 TiDB 成为真正的 Cloud-Native 数据库。要了解 TiDB Operator,首先需要对 TiDB 和 Kubernetes 有一定了解,相信长期以来一直关注 TiDB 的同学可能对 TiDB 已经比较熟悉了。本文将首先简单介绍一下 TiDB 和 Kubernetes,聊一聊为什么我们要做 TiDB Operator,然后讲讲如何快速体验 TiDB Operator,以及如何参与到 TiDB Operator 项目中来成为 Contributor。TiDB 和 Kubernetes 简介 TiDB 作为一个开源的分布式数据库产品,具有多副本强一致性的同时能够根据业务需求非常方便的进行弹性伸缩,并且扩缩容期间对上层业务无感知。TiDB 包括三大核心组件:TiDB/TiKV/PD。  TiDB Server:主要负责 SQL 的解析器和优化器,它相当于计算执行层,同时也负责客户端接入和交互。 TiKV Server:是一套分布式的 Key-Value 存储引擎,它承担整个数据库的存储层,数据的水平扩展和多副本高可用特性都是在这一层实现。 PD Server:相当于分布式数据库的大脑,一方面负责收集和维护数据在各个 TiKV 节点的分布情况,另一方面 PD 承担调度器的角色,根据数据分布状况以及各个存储节点的负载来采取合适的调度策略,维持整个系统的平衡与稳定。 上面的这三个组件,每个角色都是一个多节点组成的集群,所以最终 TiDB 的架构看起来是这样的。Kubernetes 最早是作为一个纯粹的容器编排系统而诞生的,用户部署好 Kubernetes 集群之后,直接使用其内置的各种功能部署应用服务。 由于这个 PaaS 平台使用起来非常便利,吸引了很多用户,不同用户也提出了各种不同的需求。有些特性需求 Kubernetes 直接在其核心代码里面实现了,但是有些特性并不适合合并到主干分支。为满足这类需求,Kubernetes 开放出一些 API 供用户自己扩展,实现自己的需求。当前 Kubernetes 内部的 API 变得越来越开放,使其更像是一个跑在云上的操作系统。用户可以把它当作一套云的 SDK 或 Framework 来使用,而且可以很方便地开发组件来扩展满足自己的业务需求。对有状态服务的支持就是一个很有代表性的例子。为什么我们要做 TiDB Operator 第一,使用传统的自动化工具带来了很高的部署和运维成本。TiDB 的分层架构对于分布式系统是比较常见的,各个组件都可以根据业务需求独立水平伸缩,并且 TiKV 和 TiDB 都可以独立使用。比如,在 TiKV 之上可以构建兼容 Redis 协议的 KV 数据库,而 TiDB 也可以对接 LevelDB 这样的 KV 存储引擎。但是,这种多组件的分布式系统增加了手工部署和运维的成本。一些传统的自动化部署和运维工具如 Puppet/Chef/SaltStack/Ansible,由于缺乏全局状态管理,不能及时对各种异常情况做自动故障转移,并且很难发挥分布式系统的弹性伸缩能力。其中有些还需要写大量的 DSL 甚至与 Shell 脚本一起混合使用,可移植性较差,维护成本比较高。第二,在云时代,容器成为应用分发部署的基本单位,而谷歌基于内部使用数十年的容器编排系统 Borg 经验推出的开源容器编排系统 Kubernetes 成为当前容器编排技术事实上的标准。如今各大云厂商都开始提供托管的 Kubernetes 集群,部署在 Kubernetes 平台的应用可以不用绑定在特定云平台,轻松实现在各种云平台之间的迁移,其容器化打包和发布方式也解决了对操作系统环境的依赖。Kubernetes 项目最早期只支持无状态服务(Stateless Service)的管理。无状态服务通过 ReplicationController 定义多个副本,由 Kubernetes 调度器来决定在不同节点上启动多个 Pod,实现负载均衡和故障转移。对于无状态服务,多个副本对应的 Pod 是等价的,所以在节点出现故障时,在新节点上启动一个 Pod 与失效的 Pod 是等价的,不会涉及状态迁移问题,因而管理非常简单。 但是对于有状态服务(Stateful Service),由于需要将数据持久化到磁盘,使得不同 Pod 之间不能再认为成等价,也就不能再像无状态服务那样随意进行调度迁移。Kubernetes v1.3 版本提出 PetSet 的概念,用来管理有状态服务并于 v1.5 将其更名为 StatefulSet。StatefulSet 明确定义一组 Pod 中每个的身份,启动和升级都按特定顺序来操作。另外使用持久化卷存储(PersistentVolume)来作为存储数据的载体,当节点失效 Pod 需要迁移时,对应的 PV 也会重新挂载,而 PV 的底层依托于分布式文件系统,所以 Pod 仍然能访问到之前的数据。同时 Pod 在发生迁移时,其网络身份例如 IP 地址是会发生变化的,很多分布式系统不能接受这种情况。所以 StatefulSet 在迁移 Pod 时可以通过绑定域名的方式来保证 Pod 在集群中网络身份不发生变化。但是由于有状态服务的特殊性,当节点出现异常时,出于数据安全性考虑,Kubernetes 并不会像无状态服务那样自动做故障转移。尽管网络存储能挂载到不同的节点上供其上的 Pod 使用,但是如果出现节点故障时,简单粗暴地将网络 PV 挂载到其它节点上是比较危险的。Kubernetes 判断节点故障是基于部署在每个节点上的 Kubelet 服务是否能正常上报节点状态,Kubelet 能否正常工作与用户应用并没有必然联系,在一些特殊情况下,Kubelet 服务进程可能无法正常启动,但是节点上的业务容器还在运行,将 PV 再挂载到其它节点可能会出现双写问题。为了在 Kubernetes 上部署和管理 TiDB 这种有状态的服务,我们需要扩展 StatefulSet 的功能。TiDB Operator 正是基于 Kubernetes 内置的 StatefulSet 开发的 TiDB 集群管理和运维工具。Kubernetes 直到 v1.7 才试验性引入本地 PV,在这之前只有网络 PV,TiKV 自身在存储数据时就是多副本的,网络 PV 的多副本会增加数据冗余,降低 TiDB 的性能。在这之前我们基于 Kubernetes 内置的 hostPath volume 实现了本地 PV 满足 TiKV 对磁盘 IO 的要求。官方本地 PV 方案直到最近的 Kubernetes v1.10 才相对稳定地支持调度功能,满足用户对本地 PV 的需求。为了降低用户的使用和管理成本并且拥抱 Kubernetes 开源社区,我们又重新基于官方的本地 PV 方案实现了对数据的管理。TiDB Operator 原理解析 Operator 本质上是 Kubernetes 的控制器(Controller),其核心思想是用户给定一个 Spec 描述文件,Controller 根据 Spec 的变化,在 Kubernetes 集群中创建对应资源,并且不断调整资源使其状态满足用户预期的 Spec。上图是 TiDB Operator 工作流程原理图,其中 TidbCluster 是通过 CRD(Custom Resource Definition)扩展的内置资源类型: 用户通过 Helm 往 Kubernetes API Server 创建或更新 TidbCluster 对象。 TiDB Operator 通过 watch API Server 中的 TidbCluster 对象创建更新或删除,维护 PD/TiKV/TiDB StatefulSet, Service 和 Deployment 对象更新。 Kubernetes 根据 StatefulSet, Service 和 Deployment 对象创建更新或删除对应的容器和服务。 在第 2 步中,TiDB Operator 在更新 StatefulSet 等对象时会参考 PD API 给出的集群状态来做出 TiDB 集群的运维处理。通过 TiDB Operator 和 Kubernetes 的动态调度处理,创建出符合用户预期的 TiDB 集群。快速体验 TiDB Operator TiDB Operator 需要运行在 Kubernetes v1.10 及以上版本。TiDB Operator 和 TiDB 集群的部署和管理是通过 Kubernetes 平台上的包管理工具 Helm 实现的。运行 TiDB Operator 前请确保 Helm 已经正确安装在 Kubernetes 集群里。 如果没有 Kubernetes 集群,可以通过 TiDB Operator 提供的脚本快速在本地启动一个多节点的 Kubernetes 集群:git clone https://github.com/pingcap/tidb-operator cd tidb-operator NUM_NODES=3 # the default node number is 2 KUBE_REPO_PREFIX=uhub.ucloud.cn/pingcap manifests/local-dind/dind-cluster-v1.10.sh up 等 Kubernetes 集群准备好,就可以通过 Helm 和 Kubectl 安装部署 TiDB Operator 和 TiDB 集群了。 安装 TiDB Operatorkubectl apply -f manifests/crd.yaml helm install charts/tidb-operator --name=tidb-operator --namespace=tidb-admin 部署 TiDB 集群helm install charts/tidb-cluster --name=demo-tidb --namespace=tidb --set clusterName=demo 集群默认使用 local-storage 作为 PD 和 TiKV 的数据存储,如果想使用其它持久化存储,需要修改 charts/tidb-cluster/values.yaml 里面的 storageClassName。参与 TiDB Operator TiDB Operator 让 TiDB 成为真正意义上的 Cloud-Native 数据库,开源只是一个起点,需要 TiDB 社区和 Kubernetes 社区的共同参与。 大家在使用过程发现 bug 或缺失什么功能,都可以直接在 GitHub 上面提 issue 或 PR,一起参与讨论。要想成为 Contributor 具体可以参考 这个文档。Infra Meetup No.72 视频回顾 视频链接: Infra Meetup No.72 演示部分录像切换到“高清”信号更清晰 可下载 PPT 配合观看 PingCAP Infra Meetup作为一个基础架构领域的前沿技术公司,PingCAP 希望能为国内真正关注技术本身的 Hackers 打造一个自由分享的平台。自 2016 年 3 月 5 日开始,我们定期在周六的上午举办 Infra Meetup,邀请业内大牛与大家深度探讨基础架构领域的前瞻性技术思考与经验。在这里,我们希望提供一个高水准的前沿技术讨论空间,让大家真正感受到自由的开源精神魅力。 "}, {"url": "https://pingcap.com/weekly/2018-08-20-tidb-weekly/", "title": "Weekly update (August 13 ~ August 19, 2018)", "content": " Weekly update in TiDB Last week, we landed 46 PRs in the TiDB repository.Added Store the TiDB server information to PD and add the HTTP API handle Support dropping the index for the partitioned table Support the Replace operation for table partition Add BatchPut and BatchDelete for the Raw client Support CharsetOpt to load the data statement in Parser Fixed Fix group_concat when the chunk size is set to 1 Fix the admin check index panic when the index contains the pkIsHandle column Fix the fraction part handle of current_timestamp Fix the panic in checkRangePartitioningKeysConstraints when creating table partitions by range columns Set the proper customized timezone Set the types of index columns in CheckIndexRangeExec Fix the missing microsecond for the timestamp Fix duplicate row check when the chunk size is small Fix the return value of resultType/flag in the enum/set column information Improved Log detailed statistics for the query feedback Collect execution details and output them in the slow query log Notify the statistics worker when truncating tables Add a new interface MergePartialResult for the new aggregation framework Weekly update in TiSpark Last week, we landed 2 PRs in the TiSpark repository.Fixed Fix the Index Read error caused by splitting or moving Regions Refactor error handling Weekly update in TiKV and PD Last week, we landed 48 PRs in the TiKV and PD repositories.Added Support more functions in Coprocessor: Sqrt Pow UnHex is_ipv4 Tan ASCII Left LeftShift Add nodes dynamically in the PD simulator Add an option to disable the namespace checker Add Version and use conf to initialize nodes in the PD simulator Add EvalConfigBuilder Support batch_split Fixed Create a peer if needed when pre-vote is received Fix a bug in do_div_mod Improved Optimize MVCC scanners Refactor the PD Selector Optimize prefix_next Decode bytes in place Improve the performance of the Region tree New contributors (Thanks!) TiDB: mengnan TiKV: arosspope bombless opensourcegeek xiangyuf PD: lerencao docs: lerencao docs-cn: ahdong2007 lerencao "}, {"url": "https://pingcap.com/blog/9-whys-to-ask-when-evaluating-a-distributed-database/", "title": "9 Why's to Ask When Evaluating a Distributed Database", "content": " When I first started building TiDB with my co-founders, we encountered countless challenges, pitfalls, and critical design choices that could have made or broken the project. To build an enterprise-grade distributed database like TiDB from scratch, we have to constantly make difficult decisions that balance the speed of development with long-term considerations for our customers and our team.Three years and two big releases later, TiDB 2.0 is now deployed in-production in more than 200 companies. Along the way, our team answered many questions from our users as they evaluated TiDB and other distributed databases. Choosing what to use in your infrastructure stack is an important decision and not an easy one. So I’ve gathered our learning from over the years, and summarized them into the following “9 why’s” that every engineer should ask when looking at a distributed database. Hopefully, this list can make your decision-making a bit easier.1. Why Distributed Database is Not a Silver Bullet? There’s no single technology that can be the elixir to all your problems. The database realm is no different. If your data can fit on a single MySQL instance without too much pressure on your server, or if your performance requirement for complex queries isn’t high, then a distributed database may not be a good choice. Choosing to use a distributed database typically means additional maintenance cost, which may not be worthwhile for small workloads. If you need High Availability (HA) for small workloads, MySQL’s master-slave replication model plus its GTID solution might just be enough to get the job done. If not, you can extend it with Group Replication. With a community as active and large as MySQL’s, you can Google pretty much any issue and find the solution. In short, if a single instance database is enough, stick with MySQL. When we first began building TiDB to be MySQL compatible, our goal was never to replace MySQL, but to solve problems that single instance databases inherently cannot solve.So when is the right time to deploy a distributed system like TiDB? Like any answer to a hard question, it depends. I don’t want to give a one-size-fits-all answer, but there are signals to look for when deciding whether a distributed database is the right answer. For example, are you: Finding yourself thinking about how to replicate, migrate, or scale your database for extra capacity? Looking for ways to optimize your existing storage capacity? Getting concerned about slow query performance? Researching middleware scaling solutions or implementing manual sharding policy? If you find yourself asking these types of questions on a regular basis, it’s time to consider whether a solution like TiDB can help you.MySQL and TiDB are not mutually exclusive choices. In fact, we spent an enormous amount of work helping our users continue to use MySQL by building tools to make the migration from MySQL to TiDB seamless. This preserves the option of simultaneously using MySQL for single instance workloads where it shines. So if your data is still small and workloads light, keep on using MySQL—TiDB will be waiting for you in the future.2. Why Separate SQL from Storage? Easy Maintenance. We separated the TiDB platform’s SQL layer (stateless and also called TiDB) from its storage layer (persistent and called TiKV) in order to make deployment, operations, and maintenance more simple. It is one of the most important design choices we made. This may seem counter-intuitive (don’t more components make deployment more complex?). Well, being a DevOps isn’t just about conducting deployment, but also quickly isolating issues, system debugging, and overall maintenance–a modular design really shines in supporting these responsibilities. One example: if you found a bug in your SQL layer that needs an urgent update, a rolling update can be quite time-consuming, disruptive, even risky, if your entire system is fused together and not layered separately. However, if your SQL layer is stateless and separated, an update is easy and doesn’t disrupt other parts of your system.Better Resource Usage. A modular design is also better for resource allocation and usage. Storage and SQL processing rely on different kinds of computing resources. Storage is heavily dependent on input-output (I/O) and affected by the kind of hardware you use, e.g. PCIe/NVMe/Optane SSDs. SQL processing relies more on CPU power and RAM size. Thus, putting SQL and storage in separate layers help make the entire system more efficient in using the right kind of resources for the right kind of work.TiDB is designed to support an HTAP (hybrid transactional and analytical processing) architecture, where both OLTP and OLAP workloads can be handled with great performance together. Each type of workload is optimized differently and needs different kinds of physical resources to yield good performance. OLAP requests are typically long, complex queries that need a lot of RAM to run quickly. OLTP requests are short and fast, so must optimize for latency and throughput in terms of OPS (operations per second). Because TiDB’s SQL layer is stateless and separated from storage, it can intelligently determine which kind of workload should use which kind of physical resources by applying its SQL parser and Cost-Based Optimizer to analyze the query before execution.Development Flexibility and Efficiency. Using a separate key-value abstraction to build a low-level storage layer effectively increases the entire system’s flexibility. It can easily provide horizontal scalability–auto-sharding along the keys is more straightforward to implement than a table with complex schema and structure. A separate storage layer also opens up new possibilities to take advantage of different computing modes in a distributed system. TiSpark, our OLAP engine that leverages Spark, is one such example, where it takes advantage of our layers design and sits on top of TiKV to read data directly from it without any dependency or interference from TiDB. From a development angle, separation allows multiple programming languages to be used. We chose Go, a highly efficient language to build TiDB and boost our productivity, and Rust, a highly performant systems language to develop TiKV, where speed and performance is critical. If the entire system isn’t modularized, a multi-programming language approach would be impossible. Our layered architecture allows our SQL team to work in parallel with our storage team, and we use RPC (more specifically gRPC in TiDB) for communications between the components.3. Why Latency Isn’t the Only Measuring Stick? Many people have asked me: can TiDB replace Redis? Unfortunately no, because TiDB is simply not a caching service. TiDB is a distributed database solution that first and foremost supports distributed transactions with strong consistency, high availability, and horizontal scalability, where your data is persisted and replicated across multiple machines (or multiple data centers). Simply put, TiDB’s goal is to be every system’s “source of truth.” But to make all these features happen in a distributed system, some tradeoffs with latency is unavoidable (and any argument to the contrary is defying physics). Thus, if your production scenario requires very low latency, say less than 1ms, you should use a caching solution like Redis! In fact, many of our customers use Redis on top of TiDB, so they can have low latency with a reliable “source of truth.” That way, when the caching layer goes down, there’s a database that’s always on with your data–consistent, available, and with unlimited capacity.A more meaningful measuring stick of a distributed database is throughput, in the context of latency. If a system’s throughput increases linearly with the number of machines added to the system (more machines, more throughput), while latency is holding steady, that is the true sign of a robust distributed database. Some of our production …"}, {"url": "https://pingcap.com/blog-cn/tidb-source-code-reading-16/", "title": "TiDB 源码阅读系列文章(十六)INSERT 语句详解", "content": " 在之前的一篇文章 《TiDB 源码阅读系列文章(四)INSERT 语句概览》 中,我们已经介绍了 INSERT 语句的大体流程。为什么需要为 INSERT 单独再写一篇?因为在 TiDB 中,单纯插入一条数据是最简单的情况,也是最常用的情况;更为复杂的是在 INSERT 语句中设定各种行为,比如,对于 Unique Key 冲突的情况应如何处理:是报错?是忽略当前插入的数据?还是覆盖已有数据?所以,这篇会为大家继续深入介绍 INSERT 语句。本文将首先介绍在 TiDB 中的 INSERT 语句的分类,以及各语句的语法和语义,然后分别介绍五种 INSERT 语句的源码实现。INSERT 语句的种类 从广义上讲,TiDB 有以下六种 INSERT 语句: Basic INSERT INSERT IGNORE INSERT ON DUPLICATE KEY UPDATE INSERT IGNORE ON DUPLICATE KEY UPDATE REPLACE LOAD DATA 这六种语句理论上都属于 INSERT 语句。第一种,Basic INSERT,即是最普通的 INSERT 语句,语法 INSERT INTO VALUES (),语义为插入一条语句,若发生唯一约束冲突(主键冲突、唯一索引冲突),则返回执行失败。第二种,语法 INSERT IGNORE INTO VALUES (),是当 INSERT 的时候遇到唯一约束冲突后,忽略当前 INSERT 的行,并记一个 warning。当语句执行结束后,可以通过 SHOW WARNINGS 看到哪些行没有被插入。第三种,语法 INSERT INTO VALUES () ON DUPLICATE KEY UPDATE,是当冲突后,更新冲突行后插入数据。如果更新后的行跟表中另一行冲突,则返回错误。第四种,是在上一种情况,更新后的行又跟另一行冲突后,不插入该行并显示为一个 warning。第五种,语法 REPLACE INTO VALUES (),是当冲突后,删除表上的冲突行,并继续尝试插入数据,如再次冲突,则继续删除标上冲突数据,直到表上没有与改行冲突的数据后,插入数据。最后一种,语法 LOAD DATA INFILE INTO 的语义与 INSERT IGNORE 相同,都是冲突即忽略,不同的是 LOAD DATA 的作用是将数据文件导入到表中,也就是其数据来源于 csv 数据文件。由于 INSERT IGNORE ON DUPLICATE KEY UPDATE 是在 INSERT ON DUPLICATE KEY UPDATE 上做了些特殊处理,将不再单独详细介绍,而是放在同一小节中介绍;LOAD DATA 由于其自身的特殊性,将留到其他篇章介绍。Basic INSERT 语句 几种 INSERT 语句的最大不同在于执行层面,这里接着 《TiDB 源码阅读系列文章(四)INSERT 语句概览》 来讲语句执行过程。不记得前面内容的同学可以返回去看原文章。INSERT 的执行逻辑在 executor/insert.go 中。其实前面讲的前四种 INSERT 的执行逻辑都在这个文件里。这里先讲最普通的 Basic INSERT。InsertExec 是 INSERT 的执行器实现,其实现了 Executor 接口。最重要的是下面三个接口: Open:进行一些初始化 Next:执行写入操作 Close:做一些清理工作 其中最重要也是最复杂的是 Next 方法,根据是否通过一个 SELECT 语句来获取数据(INSERT SELECT FROM),将 Next 流程分为,insertRows 和 insertRowsFromSelect 两个流程。两个流程最终都会进入 exec 函数,执行 INSERT。exec 函数里处理了前四种 INSERT 语句,其中本节要讲的普通 INSERT 直接进入了 insertOneRow。在讲 insertOneRow 之前,我们先看一段 SQL。CREATE TABLE t (i INT UNIQUE); INSERT INTO t VALUES (1); BEGIN; INSERT INTO t VALUES (1); COMMIT; 把这段 SQL 分别一行行地粘在 MySQL 和 TiDB 中看下结果。MySQL:mysql> CREATE TABLE t (i INT UNIQUE); Query OK, 0 rows affected (0.15 sec) mysql> INSERT INTO t VALUES (1); Query OK, 1 row affected (0.01 sec) mysql> BEGIN; Query OK, 0 rows affected (0.00 sec) mysql> INSERT INTO t VALUES (1); ERROR 1062 (23000): Duplicate entry '1' for key 'i' mysql> COMMIT; Query OK, 0 rows affected (0.11 sec) TiDB:mysql> CREATE TABLE t (i INT UNIQUE); Query OK, 0 rows affected (1.04 sec) mysql> INSERT INTO t VALUES (1); Query OK, 1 row affected (0.12 sec) mysql> BEGIN; Query OK, 0 rows affected (0.01 sec) mysql> INSERT INTO t VALUES (1); Query OK, 1 row affected (0.00 sec) mysql> COMMIT; ERROR 1062 (23000): Duplicate entry '1' for key 'i' 可以看出来,对于 INSERT 语句 TiDB 是在事务提交的时候才做冲突检测而 MySQL 是在语句执行的时候做的检测。这样处理的原因是,TiDB 在设计上,与 TiKV 是分层的结构,为了保证高效率的执行,在事务内只有读操作是必须从存储引擎获取数据,而所有的写操作都事先放在单 TiDB 实例内事务自有的 memDbBuffer 中,在事务提交时才一次性将事务写入 TiKV。在实现中是在 insertOneRow 中设置了 PresumeKeyNotExists 选项,所有的 INSERT 操作如果在本地检测没发现冲突,就先假设插入不会发生冲突,不需要去 TiKV 中检查冲突数据是否存在,只将这些数据标记为待检测状态。最后到提交过程中,统一将整个事务里待检测数据使用 BatchGet 接口做一次批量检测。当所有的数据都通过 insertOneRow 执行完插入后,INSERT 语句基本结束,剩余的工作为设置一下 lastInsertID 等返回信息,并最终将其结果返回给客户端。INSERT IGNORE 语句 INSERT IGNORE 的语义在前面已经介绍了。之前介绍了普通 INSERT 在提交的时候才检查,那 INSERT IGNORE 是否可以呢?答案是不行的。因为: INSERT IGNORE 如果在提交时检测,那事务模块就需要知道哪些行需要忽略,哪些直接报错回滚,这无疑增加了模块间的耦合。 用户希望立刻获取 INSERT IGNORE 有哪些行没有写入进去。即,立刻通过 SHOW WARNINGS 看到哪些行实际没有写入。 这就需要在执行 INSERT IGNORE 的时候,及时检查数据的冲突情况。一个显而易见的做法是,把需要插入的数据试着读出来,当发现冲突后,记一个 warning,再继续下一行。但是对于一个语句插入多行的情况,就需要反复从 TiKV 读取数据来进行检测,显然,这样的效率并不高。于是,TiDB 实现了 batchChecker,代码在 executor/batch_checker.go。在 batchChecker 中,首先,拿待插入的数据,将其中可能冲突的唯一约束在 getKeysNeedCheck 中构造成 Key(TiDB 是通过构造唯一的 Key 来实现唯一约束的,详见 《三篇文章了解 TiDB 技术内幕——说计算》)。然后,将构造出来的 Key 通过 BatchGetValues 一次性读上来,得到一个 Key-Value map,能被读到的都是冲突的数据。最后,拿即将插入的数据的 Key 到 BatchGetValues 的结果中进行查询。如果查到了冲突的行,构造好 warning 信息,然后开始下一行,如果查不到冲突的行,就可以进行安全的 INSERT 了。这部分的实现在 batchCheckAndInsert 中。同样,在所有数据执行完插入后,设置返回信息,并将执行结果返回客户端。INSERT ON DUPLICATE KEY UPDATE 语句 INSERT ON DUPLICATE KEY UPDATE 是几种 INSERT 语句中最为复杂的。其语义的本质是包含了一个 INSERT 和 一个 UPDATE。较之与其他 INSERT 复杂的地方就在于,UPDATE 语义是可以将一行更新成任何合法的样子。在上一节中,介绍了 TiDB 中对于特殊的 INSERT 语句采用了 batch 的方式来实现其冲突检查。在处理 INSERT ON DUPLICATE KEY UPDATE 的时候我们采用了同样的方式,但由于语义的复杂性,实现步骤也复杂了不少。首先,与 INSERT IGNORE 相同,首先将待插入数据构造出来的 Key,通过 BatchGetValues 一次性地读出来,得到一个 Key-Value map。再把所有读出来的 Key 对应的表上的记录也通过一次 BatchGetValues 读出来,这部分数据是为了将来做 UPDATE 准备的,具体实现在 initDupOldRowValue。然后,在做冲突检查的时候,如果遇到冲突,则首先进行一次 UPDATE。我们在前面 Basic INSERT 小节中已经介绍了,TiDB 的 INSERT 是提交的时候才去 TiKV 真正执行。同样的,UPDATE 语句也是在事务提交的时候才真正去 TiKV 执行的。在这次 UPDATE 中,可能还是会遇到唯一约束冲突的问题,如果遇到了,此时即报错返回,如果该语句是 INSERT IGNORE ON DUPLICATE KEY UPDATE 则会忽略这个错误,继续下一行。在上一步的 UPDATE 中,还需要处理以下场景,如下面这个 SQL:CREATE TABLE t (i INT UNIQUE); INSERT INTO t VALUES (1), (1) ON DUPLICATE KEY UPDATE i = i; 可以看到,这个 SQL 中,表中原来并没有数据,第二句的 INSERT 也就不可能读到可能冲突的数据,但是,这句 INSERT 本身要插入的两行数据之间冲突了。这里的正确执行应该是,第一个 1 正常插入,第二个 1 插入的时候发现有冲突,更新第一个 1。此时,就需要做如下处理。将上一步被 UPDATE 的数据对应的 Key-Value 从第一步的 Key-Value map 中删掉,将 UPDATE 出来的数据再根据其表信息构造出唯一约束的 Key 和 Value,把这个 Key-Value 对放回第一步读出来 Key-Value map 中,用于后续数据进行冲突检查。这个细节的实现在 fillBackKeys。这种场景同样出现在,其他 INSERT 语句中,如 INSERT IGNORE、REPLACE、LOAD DATA。之所以在这里介绍是因为,INSERT ON DUPLICATE KEY UPDATE 是最能完整展现 batchChecker 的各方面的语句。最后,同样在所有数据执行完插入/更新后,设置返回信息,并将执行结果返回客户端。REPLACE 语句 REPLACE 语句虽然它看起来像是独立的一类 DML,实际上观察语法的话,它与 Basic INSERT 只是把 INSERT 换成了 REPLACE。与之前介绍的所有 INSERT 语句不同的是,REPLACE 语句是一个一对多的语句。简要说明一下就是,一般的 INSERT 语句如果需要 INSERT 某一行,那将会当遭遇了唯一约束冲突的时候,出现以下几种处理方式: 放弃插入,报错返回:Basic INSERT 放弃插入,不报错:INSERT IGNORE 放弃插入,改成更新冲突的行,如果更新的值再次冲突 报错:INSERT ON DUPLICATE KEY UPDATE 不报错:INSERT IGNORE ON DUPLICATE KEY UPDATE 他们都是处理一行数据跟表中的某一行冲突时的不同处理。但是 REPLACE 语句不同,它将会删除遇到的所有冲突行,直到没有冲突后再插入数据。如果表中有 5 个唯一索引,那有可能有 5 条与等待插入的行冲突的行。那么 REPLACE 语句将会一次性删除这 5 行,再将自己插入。看以下 SQL:CREATE TABLE t ( i int unique, j int unique, k int unique, l int unique, m int unique); INSERT INTO t VALUES (1, 1, 1, 1, 1), (2, 2, 2, 2, 2), (3, 3, 3, 3, 3), (4, 4, 4, 4, 4); REPLACE INTO t VALUES (1, 2, 3, 4, 5); SELECT * FROM t; i j k l m 1 2 3 4 5 在执行完之后,实际影响了 5 行数据。理解了 REPLACE 语句的特殊性以后,我们就可以更容易理解其具体实现。与 INSERT 语句类似,REPLACE 语句的主要执行部分也在其 Next 方法中,与 INSERT 不同的是,其中的 insertRowsFromSelect 和 insertRows 传递了 ReplaceExec 自己的 exec 方法。在 exec 中调用了 replaceRow,其中同样使用了 batchChecker 中的批量冲突检测,与 INSERT 有所不同的是,这里会删除一切检测出的冲突,最后将待插入行写入。写在最后 INSERT 语句是所有 DML 语句中最复杂,功能最强大多变的一个。其既有像 INSERT ON DUPLICATE UPDATE 这种能执行 INSERT 也能执行 UPDATE 的语句,也有像 REPLACE 这种一行数据能影响许多行数据的语句。INSERT 语句自身都可以连接一个 SELECT 语句作为待插入数据的输入,因此,其又受到了来自 planner 的影响(关于 planner 的部分详见相关的源码阅读文章: (七)基于规则的优化 和 (八)基于代价的优化)。熟悉 TiDB 的 INSERT 各个语句实现,可以帮助各位读者在将来使用这些语句时,更好地根据其特色使用最为合理、高效语句。另外,如果有兴趣向 TiDB 贡献代码的读者,也可以通过本文更快的理解这部分的实现。"}, {"url": "https://pingcap.com/weekly/2018-08-13-tidb-weekly/", "title": "Weekly update (August 06 ~ August 12, 2018)", "content": " Weekly update in TiDB Last week, we landed 46 PRs in the TiDB repositories.Added Support the Update operation for table partition Support the prefix index in admin check table Fixed Fix behaviors of builtin LTrim, RTrim and Trim Fix group_concat(a) when a is null Make USE INDEX(PRIMARY) work on the integer primary key Fix admin check table false alarm when the index contains the pkIsHandle column Fix inconsistent row count estimation Fix a bug when applying the RenameTable diff Improved Perform the batch check for the constrains when adding a unique index Remove Exists in plan and executor Disable the Read Committed isolation level Refactor joinResultGenerator to handle the unmatched outer records Adjust the way of checking all the schema versions Update the import path from coreos/gofail to etcd-io/gofail to fix CI Weekly update in TiKV and PD Last week, we landed 27 PRs in the TiKV and PD repositories.Added Support more functions in Coprocessor: upper/lower bin PI interval Support splitting Regions by the number of keys Make PD support allocating timestamp after recovering from incorrect system time Fixed Fix the TiKV panic when the decimal overflows Prevent dynamic-level-size from being turned on for existing TiKV clusters Improved Output unit B in tikv-ctl Improve TiKV Read flow statistics accuracy Improve the TiKV performance: PR1 PR2 PR3 Improve the PD performance Improve the TiKV log output Add a test for time fallback in PD Improve the PD error code New contributors (Thanks!) docs-cn: Lunatictwo TiKV: smallyard sweetIan "}, {"url": "https://pingcap.com/success-stories/tidb-in-zhuanzhuan/", "title": "Managing the Surging Data Volume of a Fast-Growing Marketplace with TiDB", "content": " Industry: E-commerceAuthors: Xuan Sun (Chief Architect at Zhuan Zhuan), Dong Chen (Senior Engineer at Zhuan Zhuan) and Haodong Ji (Senior Database Administrator at Zhuan Zhuan)The Letgo of China, Zhuan Zhuan is a mobile app that enables our 100 million users to engage in “recommerce,” the e-commerce of buying and selling of second-hand goods ranging from smartphones and clothes to furniture and baby gear. Co-invested by 58.com Inc., the leading online classifieds and listings website in China, and the internet services giant Tencent, our platform has experienced tremendous growth since its launch in 2015.While growth is always a good thing, we soon became concerned that the surging data volume would pose a serious challenge to our backend system and put the operations team under great pressure. Luckily, we found TiDB, a MySQL-compatible distributed hybrid transactional and analytical processing (HTAP) database built by PingCAP and its active open-source community. As a result, we no longer have to worry about scaling databases and can focus on building better applications for our users.Currently, we have deployed TiDB in multiple clusters for the messaging and risk management applications. These TiDB clusters hold several dozens of TBs of data with excellent and stable performance. In this post, we will elaborate on our pain points, why we chose TiDB, our practice in production, and our future plans with TiDB. TiDB Cluster Architecture at Zhuan Zhuan Our Pain Points Previously, our main solution for the backend system was MySQL, with MongoDB supporting a small number of applications. Although this solution could basically meet our demand, some problems arose as our business grew: Our data grew quickly, but it was difficult to rapidly scale the storage capacity horizontally in MySQL. With a massive data volume that keeps increasing, MySQL created a heavy workload for the operations team when performing Data Definition Language (DDL) operations. To handle the service access performance under large data volume, we had to use more MySQL shardings, which made the application logic much heavier and more complicated. Meanwhile, to meet the multi-dimensional query demand, we always needed to introduce extra storage or sacrifice some performance, thus blocking the rapid iteration of our product. Due to the regular MySQL Master-Slave (M-S) failover design, application access was often unavailable. If a node failed, it took a long time to recover because of the massive data volume. But the M-S architecture could only guarantee high availability using extra components and through Master-Slave switch, and during the switch process, as the system needed to ensure the state of the Master database, the election of the new Master, and the issue of the new routing, application access got interrupted. Why TiDB? To address our pain points, the Infrastructure and DBA teams decided to find a NewSQL database solution for our fast-growing business. We came across TiDB at the very beginning of the evaluation process, and we quickly realized that it would solve our main problems.We chose TiDB for the following reasons: Horizontal scalability: TiDB provides horizontal scalability simply by adding more nodes. We don’t need to worry about the storage capacity ever! Online DDL: With TiDB, we can add new columns or indices online, saving hours of work for the DBA team. MySQL compatibility: TiDB is compatible with MySQL, and the data in MySQL can be easily migrated to TiDB. We can use TiDB as if we were using MySQL, but without manual sharding. Automatic failover and high availability: With TiDB, there’s no M-S switch, so our data and applications can be always on and continuously available. Adoption Process Before using TiDB in the production environment, we carried out functional testing and stress testing. Through functional testing, we found that TiDB met our requirements. TiDB supports most MySQL syntax, which enables us to migrate our applications from MySQL to TiDB seamlessly.For the stress testing, we simulated various application scenarios using testing tools, evaluated the performance of TiDB, and compared the results. With that information, we were able to give the R&D staff suggestions about which application scenarios were most suited for using TiDB.In this stress testing, we used six physical servers in total, three of which were CPU-intensive for starting the TiDB server and the Placement Driver (PD). The others were IO/CPU-intensive PCIe servers for starting the TiKV server. The sysbench-1.0.11 was used to test the response time (95th percent) of a 200GB TiDB cluster in different scenarios: Response time under different scenarios This is what we found: Sequential scan is efficient. As consecutive lines are probably stored at adjacent locations in the same machine, each batch read or write is highly efficient. Controlling the number of concurrent threads can shorten the request response time and improve the processing performance of the database. Based on the testing results, we recommended these use-case scenarios: Online applications with mixed read and write. Sequential write scenarios such as data archiving, logging, and turnover amortizing. After the functional testing and stress testing, we felt confident that TiDB met our requirements, so we began pre-production adoption. We mounted TiDB on the online MySQL and used it as MySQL’s slave to synchronize online data. Then we migrated some online read traffic from MySQL to TiDB, to see whether the TiDB cluster met the needs of application access. It turned out that TiDB could handle that well.In-Production Practice For our first TiDB use case, we chose the messaging application, one of the most important services at Zhuan Zhuan. The messaging service plays a key role in ensuring effective buyer-seller communication and promoting deals, and it produces a massive amount of data.It’s also where we had experienced a number of pain points with the previous MySQL solution. With MySQL, we split the database vertically and the tables horizontally for all applications. There are dozens of TBs of data online, which record up to tens of billions of pieces of data. Though we had implemented MySQL sharding, there were still occasional performance issues, and when they occurred, we would have to immediately split the data a second time. The execution cost of that second split was relatively high.There are several key application tables in the messaging service, including the Contact List Table, the Messages Table, and the System Messages Table. As the hub of the entire messaging system, the Contact List Table has to withstand tremendous access pressure. Its application scenario is much more complicated than any other table. For those reasons, we decided to migrate it first.Migration Process Step 1: Test TiDB.First, we simulated the online data and requests, then executed a lot of feature and performance tests for the Contact List Table. We also migrated one copy of the data and traffic from the online production environment to the offline testing environment and tested TiDB on the real traffic. For the migration work, we used the self-developed message queue, in which the data is converted into access requests and sent to the TiDB testing cluster. By analyzing the logs of production and testing data access modules, we were able to make a preliminary judgment about whether TiDB can process application requests well. It turned out that TiDB completely met the needs of the messaging service—but that wasn’t the end of it.Our DBA staff also needed to verify that TiDB’s data was consistent with that of the online MySQL. This was done by sampling the table records of MySQL and the Checksum values recorded by TiDB. The results were successful.Step 2: Synchronize data.Our DBA staff deployed the TiDB cluster as the slave of MySQL’s instances and then synchronized the data of its Contact List Table to a large table of TiDB. A …"}, {"url": "https://pingcap.com/blog-cn/tidb-source-code-reading-15/", "title": "TiDB 源码阅读系列文章(十五)Sort Merge Join", "content": " 什么是 Sort Merge Join 在开始阅读源码之前, 我们来看看什么是 Sort Merge Join (SMJ),定义可以看 wikipedia。简单说来就是将 Join 的两个表,首先根据连接属性进行排序,然后进行一次扫描归并, 进而就可以得出最后的结果。这个算法最大的消耗在于对内外表数据进行排序,而当连接列为索引列时,我们可以利用索引的有序性避免排序带来的消耗, 所以通常在查询优化器中,连接列为索引列的情况下可以考虑选择使用 SMJ。TiDB Sort Merge Join 实现 执行过程 TiDB 的实现代码在 tidb/executor/merge_join.go 中 MergeJoinExec.NextChunk 是这个算子的入口。下面以 SELECT * FROM A JOIN B ON A.a = B.a 为例,对 SMJ 执行过程进行简述,假设此时外表为 A,内表为 B,join-keys 为 a,A,B 表的 a 列上都有索引: 顺序读取外表 A 直到 join-keys 中出现另外的值,把相同 keys 的行放入数组 a1,同样的规则读取内表 B,把相同 keys 的行放入数组 a2。如果外表数据或者内表数据读取结束,退出。 从 a1 中读取当前第一行数据,设为 v1。从 a2 中读取当前第一行数据,设为 v2。 根据 join-keys 比较 v1,v2,结果分为几种情况: cmpResult > 0, 表示 v1 大于 v2,把当前 a2 的数据丢弃,从内表读取下一批数据,读取方法同 1。重复 2。 cmpResult < 0, 表示 v1 小于 v2,说明外表的 v1 没有内表的值与之相同,把外表数据输出给 resultGenerator(不同的连接类型会有不同的结果输出,例如外连接会把不匹配的外表数据输出)。 cmpResult == 0, 表示 v1 等于 v2。那么遍历 a1 里面的数据,跟 a2 的数据,输出给 resultGenerator 作一次连接。 回到步骤 1。 下面的图展示了 SMJ 的过程:读取内表 / 外表数据 我们分别通过 fetchNextInnerRows 或者 fetchNextOuterRows 读取内表和外表的数据。这两个函数实现的功能类似,这里只详述函数 fetchNextInnerRows 的实现。MergeSortExec 算子读取数据,是通过迭代器 readerIterator 完成,readerIterator 可以顺序读取数据。MergeSortExec 算子维护两个 readerIterator:outerIter 和 innerIter,它们在 buildMergeJoin 函数中被构造。真正读取数据的操作是在 readerIterator.nextSelectedRow 中完成, 这里会通过 ri.reader.NextChunk 每次读取一个 Chunk 的数据,关于 Chunk 的相关内容,可以查看我们之前的文章 TiDB 源码阅读系列文章(十)Chunk 和执行框架简介 。这里值得注意的是,我们通过 expression.VectorizedFilter 对外表数据进行过滤,返回一个 curSelected 布尔数组,用于外表的每一行数据是否是满足 filter 过滤条件。以 select * from t1 left outer join t2 on t1.a=100; 为例, 这里的 filter 是 t1.a=100, 对于没有通过这个过滤条件的行,我们通过 ri.joinResultGenerator.emitToChunk 函数发送给 resultGenerator, 这个 resultGenerator 是一个 interface,具体是否输出这行数据,会由 join 的类型决定,比如外连接则会输出,内连接则会忽略。具体关于 resultGenerator, 可以参考之前的文章:TiDB 源码阅读系列文章(九)Hash JoinrowsWithSameKey 通过 nextSelectedRow 不断读取下一行数据,并通过对每行数据的 join-keys 进行判断是不是属于同一个 join-keys,如果是,会把相同 join-keys 的行分别放入到 innerChunkRows 和 outerIter4Row 数组中。然后对其分别建立迭代器 innerIter4Row 和 outerIter4Row。在 SMJ 中的执行过程中,会利用这两个迭代器来获取数据进行真正的比较得出 join result。Merge-Join 实现 Merge-Join 逻辑的代码在函数 MergeJoinExec.joinToChunk, 对内外表迭代器的当前数据根据各自的 join-keys 作对比,有如下几个结果: cmpResult > 0,代表外表当前数据大于内表数据,那么通过 fetchNextInnerRows 直接读取下一个内表数据,然后重新比较即可。 cmpResult < 0,代表外表当前数据小于内表数据,这个时候就分几种情况了,如果是外连接,那么需要输出外表数据 + NULL,如果是内连接,那么这个外表数据就被忽略,对于这个不同逻辑的处理,统一由 e.resultGenerator 来控制,我们只需要把外表数据通过 e.resultGenerator.emitToChunk 调用它即可。然后通过 fetchNextOuterRows 读取下一个外表数据,重新比较。 cmpResult == 0,代表外表当前数据等于内表当前数据,这个时候就把外表数据跟内表当前数据做一次连接,通过 e.resultGenerator.emitToChunk 生成结果。之后外表跟内表分别获取下一个数据,重新开始比较。 重复上面的过程,直到外表或者内表数据被遍历完,退出 Merge-Join 的过程。更多 我们上面的分析代码基于 Source-code 分支,可能大家已经发现了一些问题,比如我们会一次性读取内外表的 Join group(相同的 key)。这里如果相同的 key 比较多,是有内存 OOM 的风险的。针对这个问题,我们在最新的 master 分支做了几个事情来优化: 外表其实不需要把相同的 keys 一次性都读取上来, 它只需要按次迭代外表数据,再跟内表逐一对比作连接即可。这里至少可以减少外表发生 OOM 的问题,可以大大减少 OOM 的概率。 对于内表,我们对 OOM 也不是没有办法,我们用 memory.Tracker 这个内存追踪器来记录当前内表已经使用的中间结果的内存大小,如果它超过我们设置的阈值,我们会采取输出日志或者终止 SQL 继续运行的方法来规避 OOM 的发生。关于 memory.Tracker 我们不在此展开,可以留意我们后续的源码分析文章。 后续我们还会在 Merge-Join 方面做一些优化, 比如我们可以做多路归并,中间结果存外存等等,敬请期待。"}, {"url": "https://pingcap.com/weekly/2018-08-06-tidb-weekly/", "title": "Weekly update (July 30 ~ August 05, 2018)", "content": " Weekly update in TiDB Last week, we landed 68 PRs in the TiDB repositories.Added Support the Delete operation for table partition Support analyzing the partition table Fixed Fix the union result when mixing signed and unsigned columns Add BatchPut for RawKV Fix a bug about wrong copying in index join Fix a panic caused by the local feedback Fix a bug in decimal multiplication Sort user records in the privilege cache Fix TruncateTo Fix a bug of update with an outer join Fix admin cleanup index for non-unique handles in a unique index Fix a bug when eliminating a projection Skip inner rows when the join keys contain NULL Improved Support fast path point select Always choose the smaller child as the outer table for IndexJoin Remove FromID from expression.Column Add default value check of the primary key when creating a table Use the revive linter Weekly update in TiKV and PD Last week, we landed 30 PRs in the TiKV and PD repositories.Added Support specifying the time zone by name Add etcd Raft state metrics Add hierarchy in the error code Fixed Fix the issue that the operator kind is not set correctly Fix a bug in from_bytes Perform GC on stale peers which send pre-vote messages Improved Use RangeProperties instead of SizeProperties Optimize scan_lock Refactor Row in the executor Avoid reading etcd if possible Reduce Key related memcpy Export the seek_region interface New contributors (Thanks!) TiDB: hhxcc TiKV: TennyZhuang lerencao TiSpark: ariesdevil docs-cn: motian "}, {"url": "https://pingcap.com/blog/adding-built-in-functions-to-tikv/", "title": "Landing Your First Rust Pull Request in TiKV", "content": " This guide is intended to show how you can land your first Pull Request (PR) in Rust to contribute to TiKV in less than 30 minutes. But before we do that, here’s some helpful background.TiDB (“Ti” = Titanium) is an open-source distributed scalable Hybrid Transactional and Analytical Processing (HTAP) database, built by the company PingCAP (that’s us!) and its active open-source community (that’s you!). It’s designed to provide infinite horizontal scalability, strong consistency, and high availability with MySQL compatibility. It serves as a one-stop data warehouse for both OLTP (Online Transactional Processing) and OLAP (Online Analytical Processing) workloads.What powers this experience is TiKV, a distributed transactional key-value store (all built in Rust!), which is now deployed in more than 200 companies in production (see the constantly-updated list of adopters). One key reason why TiDB can process complex SQL queries so quickly is a Coprocessor API layer between TiDB and TiKV, which takes advantage of the distributed nature of a distributed database to “push down” partial queries in parallel, where partial results are generated and reassembled for the client. This is a key differentiator between TiDB and other distributed databases.So far, TiDB can only push down some simple expressions to TiKV to be processed, e.g. fetching the value in a column and doing comparison or arithmetic operations on simple data structures. To get more juice out of distributed computing resources, we need to include more expressions to push down. The first type is MySQL built-in functions. How do we accomplish that in short order? That’s where you–our intrepid systems hacker, Rust lover, and distributed system geek–come in!So follow along this guide to contribute a built-in MySQL function to TiKV in Rust in 30 minutes. And when you do, you will receive some special gifts from us reserved just for our beloved contributors, as a small token of our gratitude. Let’s get started!How the Coprocessor Works Before diving into our step-by-step guide on how to contribute, it’s worth understanding how TiDB’s Coprocessor works at a high-level. After TiDB receives a SQL statement, it parses the statement into an abstract syntax tree (AST), then generates an optimal execution plan using its Cost-Based Optimizer. (Learn more details on how TiDB generates a query plan HERE.) The execution plan is split into multiple subtasks and the Coprocessor API pushes down these subtasks to different TiKV nodes to be processed in parallel.Here’s an illustration on how a statement like select count(*) from t where a + b > 5 gets pushed down:After TiKV receives these subtask expressions, the following steps are performed in a loop: Obtain the complete data of the next row, parse and decode the data record based on the requested columns. Use the predicate specified in the where clause to filter data. If the data passes the filter predicate, the aggregation result will be computed. After different TiKV nodes compute and return results of their respective subtasks, they are returned to TiDB. TiDB then aggregates on all the results sent from TiKV and sends the final result to the client.How to add a MySQL built-in function to TiKV Now that you have an overview of how Coprocessor in TiDB/TiKV works, here’s how to contribute MySQL built-in functions to further strengthen TiKV’s coprocessing power!Step 1: Select a function for pushdown Go to the push down scalar functions issue page, choose a function you like from the unimplemented function signature list, then tell us so we can create an issue and assign it to you to prevent duplication of work.Step 2: Find the logic of corresponding implementation in TiDB Search the related builtinXXXSig (XXX is the function signature you want to implement) in the expression directory of TiDB.Take MultiplyIntUnsigned as an example, which we will use throughout this guide, you can find the corresponding function signature (builtinArithmeticMultiplyIntUnsignedSig) and its implementation.Step 3: Define the function The name of the file where the built-in function exists in TiKV should correspond to the same name in TiDB.For example, since all the pushdown files in the expression directory in TiDB are named builtin_XXX, in TiKV the corresponding file name should be builtin_XXX.rs. In this example, the current function is in the builtin_arithmetic.go file in TiDB, so the function should be placed in builtin_arithmetic.rs in TiKV.Note: If the corresponding file in TiKV does not exist, you need to create a new file in the corresponding directory with the same name as in TiDB. The function name should follow the Rust snake_case naming conventions.For this example, MultiplyIntUnsigned will be defined as multiply_int_unsigned. For the return value, you can refer to the Eval functions which are implemented in TiDB and their corresponding return value types, as shown in the following table: Eval Function in TiDB Return Value Type in TiKV evalInt Result<Option<i64>> evalReal Result<Option<i64>> evalString Result<Option<Cow<‘a, [u8]>>> evalDecimal Result<Option<Cow<‘a, Decimal>>> evalTime Result<Option<Cow<‘a, Time>>> evalDuration Result<Option<Cow<‘a, Duration>>> evalJSON Result<Option<Cow<‘a, Json>>> Thus, in TiDB’s builtinArithmeticMultiplyIntUnsignedSig, it implements the evalInt method, so the return value type of this function multiply_int_unsigned should be Result<Option<i64>>. All the arguments of the builtin-in function should be consistent with that of the eval function of the expression: The statement context is ctx:&StatementContext The value of each column in this row is row: &[Datum] Putting all this together, the definition of the pushdown function multiply_int_unsigned should look like this:pub fn multiply_int_unsigned( &self, ctx: &mut EvalContext, row: &[Datum], ) -> Result<Option<i64>> Step 4: Implement the function logic Implement the function logic based on the corresponding logic in TiDB.For this example, you can see that the implementation of builtinArithmeticMultiplyIntUnsignedSig of TiDB is:func (s *builtinArithmeticMultiplyIntUnsignedSig) evalInt(row types.Row) (val int64, isNull bool, err error) { a, isNull, err := s.args[0].EvalInt(s.ctx, row) if isNull || err != nil { return 0, isNull, errors.Trace(err) } unsignedA := uint64(a) b, isNull, err := s.args[1].EvalInt(s.ctx, row) if isNull || err != nil { return 0, isNull, errors.Trace(err) } unsignedB := uint64(b) result := unsignedA * unsignedB if unsignedA != 0 && result/unsignedA != unsignedB { return 0, true, types.ErrOverflow.GenByArgs("BIGINT UNSIGNED", fmt.Sprintf("(%s * %s)", s.args[0].String(), s.args[1].String())) } return int64(result), false, nil } To implement the same function in Rust for TiKV, it should be:pub fn multiply_int_unsigned( &self, ctx: &mut EvalContext, row: &[Datum], ) -> Result<Option<i64>> { let lhs = try_opt!(self.children[0].eval_int(ctx, row)); let rhs = try_opt!(self.children[1].eval_int(ctx, row)); let res = (lhs as u64).checked_mul(rhs as u64).map(|t| t as i64); // TODO: output expression in error when column's name pushed down. res.ok_or_else(|| Error::overflow("BIGINT UNSIGNED", &format!("({} * {})", lhs, rhs))) .map(Some) } Step 5: Add argument check When TiKV receives a pushdown request, it checks all the expressions first including the number of the expression arguments.In TiDB, there is a strict limit for the number of arguments in each built-in function. For the number of arguments, see builtin.go in TiDB.To add argument check: Go to scalar_function.rs in TiKV and find the check_args function of ScalarFunc. Add the check for the number …"}, {"url": "https://pingcap.com/blog-cn/30mins-become-contributor-of-tikv/", "title": "三十分钟成为 Contributor | 为 TiKV 添加 built-in 函数", "content": " 背景知识 SQL 语句发送到 TiDB 后经过 parser 生成 AST(抽象语法树),再经过 Query Optimizer 生成执行计划,执行计划切分成很多子任务,这些子任务以表达式的方式最后下推到底层的各个 TiKV 来执行。图 1如图 1,当 TiDB 收到来自客户端的查询请求select count(*) from t where a + b > 5时,执行顺序如下: TiDB 对 SQL 进行解析,组织成对应的表达式,下推给 TiKV TiKV 收到请求后,循环以下过程 获取下一行完整数据,并按列解析 使用参数中的 where 表达式对数据进行过滤 若上一条件符合,进行聚合计算 TiKV 向 TiDB 返回聚合计算结果 TiDB 对所有涉及的结果进行二次聚合,返回给客户端 这里的 where 条件便是以表达式树的形式下推给 TiKV。在此之前 TiDB 只会向 TiKV 下推一小部分简单的表达式,比如取出某一个列的某个数据类型的值,简单数据类型的比较操作,算术运算等。为了充分利用分布式集群的资源,进一步提升 SQL 在整个集群的执行速度,我们需要将更多种类的表达式下推到 TiKV 来运行,其中的一大类就是 MySQL built-in 函数。目前,由于 TiKV 的 built-in 函数尚未全部实现,对于无法下推的表达式,TiDB 只能自行解决。这无疑将成为提升 TiDB 速度的最大绊脚石。好消息是,TiKV 在实现 built-in 函数时,可以直接参考 TiDB 的对应函数逻辑(顺便可以帮 TiDB 找找 Bug),为我们减少了不少工作量。Built-in 函数无疑是 TiDB 和 TiKV 成长道路上不可替代的一步,如此艰巨又庞大的任务,我们需要广大社区朋友们的支持与鼓励。亲爱的朋友们,想玩 Rust 吗?想给 TiKV 提 PR 吗?想帮助 TiDB 跑得更快吗?动动您的小手指,拿 PR 来砸我们吧。您的 PR 一旦被采用,将会有小惊喜哦。手把手教你实现 built-in 函数 Step 1:准备下推函数 在 TiKV 的 https://github.com/pingcap/tikv/issues/3275 issue 中,找到未实现的函数签名列表,选一个您想要实现的函数。Step 2:获取 TiDB 中可参考的逻辑实现 在 TiDB 的 expression 目录下查找相关 builtinXXXSig 对象,这里 XXX 为您要实现的函数签名,本例中以 MultiplyIntUnsigned 为例,可以在 TiDB 中找到其对应的函数签名(builtinArithmeticMultiplyIntUnsignedSig)及 实现。Step 3:确定函数定义 built-in 函数所在的文件名要求与 TiDB 的名称对应,如 TiDB 中,expression 目录下的下推文件统一以 builtin_XXX 命名,对应到 TiKV 这边,就是 builtin_XXX.rs。若同名对应的文件不存在,则需要自行在同级目录下新建。对于本例,当前函数存放于 TiDB 的 builtin_arithmetic.go 文件里,对应到 TiKV 便是存放在 builtin_arithmetic.rs 中。 函数名称:函数签名转为 Rust 的函数名称规范,这里 MultiplyIntUnsigned 将会被定义为 multiply_int_unsigned。 函数返回值,可以参考 TiDB 中实现的 Eval 函数,对应关系如下: TiDB 对应实现的 Eval 函数 TiKV 对应函数的返回值类型 evalInt Result<Option<i64>> evalReal Result<Option<f64>> evalString Result<Option<Cow<'a, [u8]>>> evalDecimal Result<Option<Cow<'a, Decimal>>> evalTime Result<Option<Cow<'a, Time>>> evalDuration Result<Option<Cow<'a, Duration>>> evalJSON Result<Option<Cow<'a, Json>>> 可以看到 TiDB 的 builtinArithmeticMultiplyIntUnsignedSig 对象实现了 evalInt 方法,故当前函数(multiply_int_unsigned)的返回类型应该为 Result<Option<i64>>。 函数的参数, 所有 builtin-in 的参数都与 Expression 的 eval 函数一致,即: 环境配置量 (ctx:&StatementContext) 该行数据每列具体值 (row:&[Datum]) 综上,multiply_int_unsigned 的下推函数定义为:pub fn multiply_int_unsigned( &self, ctx: &mut EvalContext, row: &[Datum], ) -> Result<Option<i64>> Step 4:实现函数逻辑 这一块相对简单,直接对照 TiDB 的相关逻辑实现即可。这里,我们可以看到 TiDB 的 builtinArithmeticMultiplyIntUnsignedSig 的具体实现如下:func (s *builtinArithmeticMultiplyIntUnsignedSig) evalInt(row types.Row) (val int64, isNull bool, err error) { a, isNull, err := s.args[0].EvalInt(s.ctx, row) if isNull || err != nil { return 0, isNull, errors.Trace(err) } unsignedA := uint64(a) b, isNull, err := s.args[1].EvalInt(s.ctx, row) if isNull || err != nil { return 0, isNull, errors.Trace(err) } unsignedB := uint64(b) result := unsignedA * unsignedB if unsignedA != 0 && result/unsignedA != unsignedB { return 0, true, types.ErrOverflow.GenByArgs("BIGINT UNSIGNED", fmt.Sprintf("(%s * %s)", s.args[0].String(), s.args[1].String())) } return int64(result), false, nil } 参考以上代码,翻译到 TiKV 即可,如下:pub fn multiply_int_unsigned( &self, ctx: &mut EvalContext, row: &[Datum], ) -> Result<Option<i64>> { let lhs = try_opt!(self.children[0].eval_int(ctx, row)); let rhs = try_opt!(self.children[1].eval_int(ctx, row)); let res = (lhs as u64).checked_mul(rhs as u64).map(|t| t as i64); // TODO: output expression in error when column's name pushed down. res.ok_or_else(|| Error::overflow("BIGINT UNSIGNED", &format!("({} * {})", lhs, rhs))) .map(Some) } Step 5:添加参数检查 TiKV 在收到下推请求时,首先会对所有的表达式进行检查,表达式的参数个数检查就在这一步进行。TiDB 中对每个 built-in 函数的参数个数有严格的限制,这一部分检查可参考 TiDB 同目录下 builtin.go 相关代码。在 TiKV 同级目录的 scalar_function.rs 文件里,找到 ScalarFunc 的 check_args 函数,按照现有的模式,加入参数个数的检查即可。Step 6:添加下推支持 TiKV 在对一行数据执行具体的 expression 时,会调用 eval 函数,eval 函数又会根据具体的返回类型,执行具体的子函数。这一部分工作在 scalar_function.rs 中以宏(dispatch_call)的形式完成。对于 MultiplyIntUnsigned, 我们最终返回的数据类型为 Int,所以可以在 dispatch_call 中找到 INT_CALLS,然后照着加入 MultiplyIntUnsigned => multiply_int_unsigned , 表示当解析到函数签名 MultiplyIntUnsigned 时,调用上述已实现的函数 multiply_int_unsigned。至此 MultiplyIntUnsigned 下推逻辑已完全实现。Step 7:添加测试 在函数 multiply_int_unsigned 所在文件 builtin_arithmetic.rs 底部的 test 模块中加入对该函数签名的单元测试,要求覆盖到上述添加的所有代码,这一部分也可以参考 TiDB 中相关的测试代码。本例在 TiKV 中实现的测试代码如下:#[test] fn test_multiply_int_unsigned() { let cases = vec![ (Datum::I64(1), Datum::I64(2), Datum::U64(2)), ( Datum::I64(i64::MIN), Datum::I64(1), Datum::U64(i64::MIN as u64), ), ( Datum::I64(i64::MAX), Datum::I64(1), Datum::U64(i64::MAX as u64), ), (Datum::U64(u64::MAX), Datum::I64(1), Datum::U64(u64::MAX)), ]; let mut ctx = EvalContext::default(); for (left, right, exp) in cases { let lhs = datum_expr(left); let rhs = datum_expr(right); let mut op = Expression::build( &mut ctx, scalar_func_expr(ScalarFuncSig::MultiplyIntUnsigned, &[lhs, rhs]), ).unwrap(); op.mut_tp().set_flag(types::UNSIGNED_FLAG as u32); let got = op.eval(&mut ctx, &[]).unwrap(); assert_eq!(got, exp); } // test overflow let cases = vec![ (Datum::I64(-1), Datum::I64(2)), (Datum::I64(i64::MAX), Datum::I64(i64::MAX)), (Datum::I64(i64::MIN), Datum::I64(i64::MIN)), ]; for (left, right) in cases { let lhs = datum_expr(left); let rhs = datum_expr(right); let mut op = Expression::build( &mut ctx, scalar_func_expr(ScalarFuncSig::MultiplyIntUnsigned, &[lhs, rhs]), ).unwrap(); op.mut_tp().set_flag(types::UNSIGNED_FLAG as u32); let got = op.eval(&mut ctx, &[]).unwrap_err(); assert!(check_overflow(got).is_ok()); } } Step 8:运行测试 运行 make expression,确保所有的 test case 都能跑过。完成以上几个步骤之后,就可以给 TiKV 项目提 PR 啦。想要了解提 PR 的基础知识,尝试移步 此文,看看是否有帮助。"}, {"url": "https://pingcap.com/weekly/2018-07-30-tidb-weekly/", "title": "Weekly update (July 23 ~ July 29, 2018)", "content": " Weekly update in TiDB Last week, we landed 43 PRs in the TiDB repositories.Added Add the sum_decimal method for AggFunc Support truncating and dropping partitioned tables Implement the reorganization of table partition when adding the index Fixed Fix a bug that the bit and year column types are not supported when a partition table is created Fix a bug in the decimal modulo operation Refactor the code of building Insert Fix a panic caused by the outdated feedback Fix a panic that is upgraded from the old version TiDB Fix a bug that null values cannot be found using the unique index Improved Add the partition function check when creating a partition table Provide preliminary support for the parallel DDL operation Use feedback timely Optimize DecodeRowKey Remove the types.Row interface Pass row pointer rather than row to avoid convertT2I Weekly update in TiSpark Last week, we landed 6 PRs in the TiSpark repositories.Fixed Fix a decimal decoding bug Weekly update in TiKV and PD Last week, we landed 17 PRs in the TiKV and PD repositories.Added Support encoding and decoding a Chunk Introduce a version check mechanism Add thread I/O metrics Add a document about the PD API Fixed Fix a bug in AdjacentRegionScheduler Improved Keep the number of operators generated by HotRegionScheduler within the schedule limit Stop searching in get_txn_commit_info Check the legality of the label Escape key in Error Refine the task log in raftstore New contributor (Thanks!) tidb: laidahe "}, {"url": "https://pingcap.com/weekly/2018-07-23-tidb-weekly/", "title": "Weekly update (July 16 ~ July 22, 2018)", "content": " Weekly update in TiDB Last week, we landed 41 PRs in the TiDB repositories.Added Support group_concat in the new aggregation evaluation framework Support the remained types (String/Time/Duration/JSON) for Max/Min Support FIRST_ROW in the new aggregation evaluation framework Support the admin check table statement for table partition Add the proposal template Add the new storage row format proposal Add the design document about the new aggregate framework Set the PB field type and the ExtraHandle column type Fixed Fix the daylight saving time issue Fix the panic of creating partition tables Fix the bug in loading data Fix the OOM issue in the batch operations Add keepalive Truncate the prefix index from runes when the charset is UTF-8 Check b.err located after buildSort and buildLimit in builUnion Use reference count to keep only one domain instance Improved Speed up executing the replace into statement Handle the error of mismatch cluster id Refactor the index for table partition Check the partition count limit when creating and adding the partitioned table Make decoding much faster Weekly update in TiSpark Last week, we landed 2 PRs in the TiSpark repositories.Improved Improve the error log of the PD connection issue Re-throw the exception when PD initialization fails Weekly update in TiKV and PD Last week, we landed 23 PRs in the TiKV and PD repositories.Added Create MAINTAINERS.md Record the node version Support futures for the mpsc channel Support Region half-splitting without scan Add the bottommost level compaction Add the error code Support Region merging Support the Raft learner in the simulator Add the policy selection for splitting Regions Fixed Fix the template permissions Fix the bug in from_bytes Handle the non-integer input for bit related functions Fix hot Write and Read cases Improved Enable prevote by default Collapse continuous rollbacks Check sensitive environment variables Add a custom log formatter Refactor ClusterInfo Improve the taint cache behavior "}, {"url": "https://pingcap.com/blog-cn/tidb-source-code-reading-14/", "title": "TiDB 源码阅读系列文章(十四)统计信息(下)", "content": " 在 统计信息(上) 中,我们介绍了统计信息基本概念、TiDB 的统计信息收集/更新机制以及如何用统计信息来估计算子代价,本篇将会结合原理介绍 TiDB 的源码实现。文内会先介绍直方图和 Count-Min(CM) Sketch 的数据结构,然后介绍 TiDB 是如何实现统计信息的查询、收集以及更新的。数据结构定义 直方图的定义可以在 histograms.go 中找到,值得注意的是,对于桶的上下界,我们使用了在 《TiDB 源码阅读系列文章(十)Chunk 和执行框架简介》 中介绍到 Chunk 来存储,相比于用 Datum 的方式,可以减少内存分配开销。CM Sketch 的定义可以在 cmsketch.go 中找到,比较简单,包含了 CM Sketch 的核心——二维数组 table,并存储了其深度与宽度,以及总共插入的值的数量,当然这些都可以直接从 table 中得到。除此之外,对列和索引的统计信息,分别使用了 Column 和 Index 来记录,主要包含了直方图,CM Sketch 等。 统计信息创建 在执行 analyze 语句时,TiDB 会收集直方图和 CM Sketch 的信息。在执行 analyze 命令时,会先将需要 analyze 的列和索引在 builder.go 中切分成不同的任务,然后在 analyze.go 中将任务下推至 TiKV 上执行。由于在 TiDB 中也包含了 TiKV 部分的实现,因此在这里还是会以 TiDB 的代码来介绍。在这个部分中,我们会着重介绍直方图的创建。列直方图的创建 在统计信息(上)中提到,在建立列直方图的时候,会先进行抽样,然后再建立直方图。在 collect 函数中,我们实现了蓄水池抽样算法,用来生成均匀抽样集合。由于其原理和代码都比较简单,在这里不再介绍。采样完成后,在 BuildColumn 中,我们实现了列直方图的创建。首先将样本排序,确定每个桶的高度,然后顺序遍历每个值 V: 如果 V 等于上一个值,那么把 V 放在与上一个值同一个桶里,无论桶是不是已经满,这样可以保证每个值只存在于一个桶中。 如果不等于上一个值,那么判断当前桶是否已经满,就直接放入当前桶,并用 updateLastBucket 更改桶的上界和深度。 否则的话,用 AppendBucket 放入一个新的桶。 索引直方图的创建 在建立索引列直方图的时候,我们使用了 SortedBuilder 来维护建立直方图的中间状态。由于不能事先知道有多少行的数据,也就不能确定每一个桶的深度,不过由于索引列的数据是已经有序的,因次我们在 NewSortedBuilder 中将每个桶的初始深度设为 1。对于每一个数据,Iterate 会使用建立列直方图时类似的方法插入数据。如果在某一时刻,所需桶的个数超过了当前桶深度,那么用 mergeBucket 将之前的每两个桶合并为 1 个,并将桶深扩大一倍,然后继续插入。在收集了每一个 Region 上分别建立的直方图后,还需要用 MergeHistogram 把每个 Region 上的直方图进行合并。在这个函数中: 为了保证每个值只在一个桶中,我们处理了一下交界处桶的问题,即如果交界处两个桶的上界和下界 相等,那么需要先合并这两个桶; 在真正合并前,我们分别将两个直方图的平均桶深 调整 至大致相等; 如果直方图合并之后桶的个数超过了限制,那么把两两相邻的桶 合二为一。 统计信息维护 在 统计信息(上) 中,我们介绍了 TiDB 是如何更新直方图和 CM Sketch 的。对于 CM Sketch 其更新比较简单,在这里不再介绍。这个部分主要介绍一下 TiDB 是如何收集反馈信息和维护直方图的。反馈信息的收集 统计信息(上)中提到,为了不去假设所有桶贡献的误差都是均匀的,需要收集每一个桶的反馈信息,因此需要先把查询的范围按照直方图桶的边界切分成不相交的部分。在 SplitRange 中,我们按照直方图去切分查询的范围。由于目前直方图中的一个桶会包含上下界,为了方便,这里只按照上界去划分,即这里将第 i 个桶的范围看做 (i-1 桶的上界,i 桶的上界]。特别的,对于最后一个桶,将其的上界视为无穷大。比方说一个直方图包含 3 个桶,范围分别是: [2,5],[8,8],[10,13],查询的范围是 (3,20],那么最终切分得到的查询范围就是 (3,5],(5,8],(8,20]。将查询范围切分好后,会被存放在 QueryFeedback 中,以便在每个 Region 的结果返回时,调用 Update 函数来更新每个范围所包含的 key 数目。注意到这个函数需要两个参数:每个 Region 上扫描的 start key 以及 Region 上每一个扫描范围输出的 key 数目 output counts,那么要如何更新 QueryFeedback 中每个范围包含的 key 的数目呢?继续以划分好的 (3,5],(5,8],(8,20] 为例,假设这个请求需要发送到两个 region 上,region1 的范围是 [0,6),region2 的范围是 [6,30),由于 coprocessor 在发请求的时候还会根据 Region 的范围切分 range,因此 region1 的请求范围是 (3,5],(5,6),region2 的请求范围是 [6,8],(8,20]。为了将对应的 key 数目更新到 QueryFeedback 中,需要知道每一个 output count 对应的查询范围。注意到 coprocessor 返回的 output counts 其对应的 Range 都是连续的,并且同一个值只会对应一个 range,那么我们只需要知道第一个 output count 所对应的 range,即只需要知道这次扫描的 start key 就可以了。举个例子,对于 region1 来说,start key 是 3,那么 output counts 对应的 range 就是 (3,5],(5,8],对 region2 来说,start key 是 6,output countshangyipians 对应的 range 就是 (5,8],(8,20]。直方图的更新 在收集了 QueryFeedback 后,我们就可以去使用 UpdateHistogram 来更新直方图了。其大体上可以分为分裂与合并。在 splitBuckets 中,我们实现了直方图的分裂: 首先,由于桶与桶之间的反馈信息不相关,为了方便,先将 QueryFeedback 用 buildBucketFeedback 拆分了每一个桶的反馈信息,并存放在 BucketFeedback 中。 接着,使用 getSplitCount 来根据可用的桶的个数和反馈信息的总数来决定分裂的数目。 对于每一个桶,将可以分裂的桶按照反馈信息数目的比例均分,然后用 splitBucket 来分裂出需要的桶的数目: 首先,getBoundaries 会每隔几个点取一个作为边界,得到新的桶。 然后,对于每一个桶,refineBucketCount 用与新生成的桶重合部分最多的反馈信息更新桶的深度。 值得注意的是,在分裂的时候,如果一个桶过小,那么这个桶不会被分裂;如果一个分裂后生成的桶过小,那么它也不会被生成。在桶的分裂完成后,我们会使用 mergeBuckets 来合并桶,对于那些超过: 在分裂的时候,会记录每一个桶是不是新生成的,这样,对于原先就存在的桶,用 getBucketScore 计算合并的之后产生的误差,令第一个桶占合并后桶的比例为 r,那么令合并后产生的误差为 abs(合并前第一个桶的高度 - r * 两个桶的高度和)/ 合并前第一个桶的高度。 接着,对每一桶的合并的误差进行排序。 最后,按照合并的误差从下到大的顺序,合并需要的桶。 统计信息使用 在查询语句中,我们常常会使用一些过滤条件,而统计信息估算的主要作用就是估计经过这些过滤条件后的数据条数,以便优化器选择最优的执行计划。由于在单列上的查询比较简单,这里不再赘述,代码基本是按照 统计信息(上) 中的原理实现,感兴趣可以参考 histogram.go/lessRowCount 以及 cmsketch.go/queryValue。多列查询 统计信息(上)中提到,Selectivity 是统计信息模块对优化器提供的最重要的接口,处理了多列查询的情况。Selectivity 的一个最重要的任务就是将所有的查询条件分成尽量少的组,使得每一组中的条件都可以用某一列或者某一索引上的统计信息进行估计,这样我们就可以做尽量少的独立性假设。需要注意的是,我们将单列的统计信息分为 3 类:indexType 即索引列,pkType 即 Int 类型的主键,colType 即普通的列类型,如果一个条件可以同时被多种类型的统计信息覆盖,那么我们优先会选择 pkType 或者 indexType。在 Selectivity 中,有如下几个步骤: getMaskAndRange 为每一列和每一个索引计算了可以覆盖的过滤条件,用一个 int64 来当做一个 bitset,并把将该列可以覆盖的过滤条件的位置置为 1。 接下来在 getUsableSetsByGreedy 中,选择尽量少的 bitset,来覆盖尽量多的过滤条件。每一次在还没有使用的 bitset 中,选择一个可以覆盖最多尚未覆盖的过滤条件。并且如果可以覆盖同样多的过滤条件,我们会优先选择 pkType 或者 indexType。 用统计信息(上)提到的方法对每一个列和每一个索引上的统计信息进行估计,并用独立性假设将它们组合起来当做最终的结果。 总结 统计信息的收集和维护是数据库的核心功能,对于基于代价的查询优化器,统计信息的准确性直接影响了查询效率。在分布式数据库中,收集统计信息和单机差别不大,但是维护统计信息有比较大的挑战,比如怎样在多节点更新的情况下,准确及时的维护统计信息。对于直方图的动态更新,业界一般有两种方法: 对于每一次增删,都去更新对应的桶深。在一个桶的桶深过高的时候分裂桶,一般是把桶的宽度等分,不过这样很难准确的确定分界点,引起误差。 使用查询得到的真实数去反馈调整直方图,假定所有桶贡献的误差都是均匀的,用连续值假设去调整所有涉及到的桶。然而误差均匀的假设常常会引起问题,比如当新插入的值大于直方图的最大值时,就会把新插入的值引起的误差分摊到直方图中,从而引起误差。 目前 TiDB 的统计信息还是以单列的统计信息为主,为了减少独立性假设的使用,在将来 TiDB 会探索多列统计信息的收集和维护,为优化器提供更准确的统计信息。"}, {"url": "https://pingcap.com/weekly/2018-07-16-tidb-weekly/", "title": "Weekly update (July 09 ~ July 15, 2018)", "content": " Weekly update in TiDB Last week, we landed 30 PRs in the TiDB repositories.Added Support BIT_AND/BIT_XOR in the new aggregation framework Support COUNT in the new aggregation framework Support AVG(DISTINCT) in the new aggregation framework Add the GENERATION_EXPRESSION column in information_schema.columns Support more syntactic rules regarding the SET syntax Support ADMIN SHOW DDL JOBS <NUMBER> to specify the lines of the results Support showing AUTO_INCREMENT in information_schema.tables Fixed Fix a bug in INSERT SELECT FROM ON DUPLICATE KEY UPDATE Fix the numeric type overflow in the binary protocol Fix the results of decimal Minus/Round/Mul Improved Check the schema when the DDL fails Refine the explain result format Speed up autoAnalyze when data is unchanged Weekly update in TiKV and PD Last week, we landed 19 PRs in the TiKV and PD repositories.Added Add new builtin UDFs regexp and regexp_binary Introduce the loose channel Add options to disable replica-checker features Support filtering JSON output by calling the external jq Fixed Fix the unexpected behavior of tikv-ctl unsafe-recover command Improved Report approximate_keys instead of approximate_rows Add TiKV adopters and Roadmap Update rustc and clippy New contributor (Thanks!) docs: brunoban"}, {"url": "https://pingcap.com/blog-cn/tidb-source-code-reading-13/", "title": "TiDB 源码阅读系列文章(十三)索引范围计算简介", "content": " 简述 在数据库中处理查询请求时,如果可以尽早的将无关数据过滤掉,那么后续的算子就可以少做无用功,提升整个 SQL 的执行效率。过滤数据最常用的手段是使用索引,TiDB 的优化器也会尽量采用索引过滤的方式处理请求,利用索引有序的特点来提升查询效率。比如当查询条件为 a = 1 时,如果 a 这一列上有索引,我们就可以利用索引很快的把满足 a = 1 的数据拿出来,而不需要逐行检查 a 的值是否为 1。当然是否会选择索引过滤也取决于代价估算。索引分为单列索引和多列索引(组合索引),筛选条件也往往不会是简单的一个等值条件,可能是非常复杂的条件组合。TiDB 是如何分析这些复杂条件,来得到这些条件在对应的索引上的逻辑区间范围(range),就是本文要介绍的内容。关于 TiDB 如何构建索引,如何存储索引数据,希望读者能够有基本的了解(参考阅读:三篇文章了解 TiDB 技术内幕 - 说计算 )。这里是一个例子,展示这里所说的索引范围计算是做什么的,建表语句和查询语句如下:CREATE TABLE t (a int primary key, b int, c int); select * from t where ((a > 1 and a < 5 and b > 2) or (a > 8 and a < 10 and c > 3)) and d = 5; 计算索引逻辑区间范围的流程如下:从上图可以看出,整个流程分为从 Filter 中抽取可用索引的表达式以及利用选出的表达式构造数据范围两个步骤,接下来分别描述。抽取表达式 这个步骤是从 Filter 中将能够用上索引的表达式选出来。由于单列索引和多列索引在处理逻辑上有很大的不同,所以会分单列索引和多列索引两中情况进行讲解。单列索引 单列索引的情况相对来说比较简单。很多满足 Column op Constant 形式的简单表达式都可以用来计算 range,单个表达式的判断逻辑在 checker.go 的 conditionChecker 中。而对于包含了 AND 或者 OR 的复杂情况,我们可以按照下述规则进行处理: AND 表达式无关的 filter 并不会影响其可以计算 range 的子项。所以直接舍去无关的表示即可。以流程图中的一个子表达式 a > 1 and a < 5 and b > 2 为例,我们只要将 b > 2 扔掉,保留 a > 1 and a < 5 即可。 OR 表达式中,每个子项都要可以用来计算 range,如果有不可以计算 range 的子项,那么这整个表达式都不可用来计算 range。以 a = 1 or b = 2 为例,b = 2 这一子项不可以用来计算 a 的 range,所以这个表达式整体上无法计算 a 的 range。而如果是 a > 1 or ( a < 2 and b = 1),根据 1 中的规则,第二个子项会留下 a < 2 的部分,可以用来计算 a 的 range,因此整个表达式会返回 a > 1 and a < 2 来供接下来计算 range 的部分处理。 这里补充说明一点,TiDB 的主键在实现方式上限定了只有整数类型的单列主键会把主键值当做 RowID,然后编码成 RowKey,和这行数据存储在一起。其他类型的单列主键会作为普通的 unique key 看待,当查询的列包含索引上没有的列时,需要一次查索引 + 一次扫表。所以我们将这种整数类型作为主键的索引处理逻辑单独抽取出来,其入口函数为 DetachCondsForTableRange 。其中对 AND 表达式和 OR 表达式的处理入口分别为 detachColumnCNFConditions 和 detachColumnDNFConditions。这两个函数也用来处理其他类型的主键或者索引的的 range 计算。多列索引 多列索引的情况较单列索引而言会复杂一些,因为在处理 OR 表达式中列与列之间的关系需要考虑更多情况。TiDB 中为了简化 ranger 的逻辑,目前只考虑下列情况: AND 表达式中,只有当之前的列均为点查的情况下,才会考虑下一个列。e.g. 对于索引 (a, b, c),有条件 a > 1 and b = 1,那么会被选中的只有 a > 1。对于条件 a in (1, 2, 3) and b > 1,两个条件均会被选到用来计算 range。由于非点查的部分只会涉及到一个列,所以可以直接复用 detachColumnCNFConditions。 OR 表达式中,每个子项会视为 AND 表达式分开考虑。与单列索引的情况一样,如果其中一个子项无法用来计算索引,那么该 OR 表达式便完全无法计算索引。 多列索引处理的入口函数为 DetachCondAndBuildRangeForIndex,AND 表达式和 OR 表达式的处理入口分别为 detachCNFCondAndBuildRangeForIndex 和 detachDNFCondAndBuildRangeForIndex。(由于多列索引对 range 的处理相对单列索引而言会复杂一些,所以没有拆分为 DetachCondition 和 BuildRange 两部分,而是由 DetachCondAndBuildRangeForIndex 处理。)由于逻辑进行到了简化,因此目前 TiDB 的 ranger 存在无法正确处理的情况。比如: a = 1 and (b = 1 or b = 2) and c > 1。对于这个式子,当 (a, b ,c) 为索引时,如上述所言,由于 (b = 1 or b = 2) 形式上是 OR 表达式的情况,而非点查。所以会在 b 列停止,不会考虑 c > 1 的情况。所以目前为了兼容 TiDB 的逻辑,遇到这种情况尽量改写为 a = 1 and b in (1, 2) and c > 1 的形式。 类似的如 ((a = 1 and b = 1) or (a = 2 and b = 2)) and c = 1 形式的式子,前段 OR 表达式实际上为点查的行为,但是由于是 OR 连接起来的式子,所以在 TiDB 的逻辑中作为范围查询处理,因此 c = 1 不会作为索引的计算条件处理。而这时改写为 (a, b) in ((1, 1), (2, 2)) and c = 1 的形式也不会使 c = 1 选入索引计算的条件,原因是多列 in 的函数会被 TiDB 改写为 OR 连接的形式,所以 ((a = 1 and b = 1) or (a = 2 and b = 2)) 和 (a, b) in ((1, 1), (2, 2)) 在 TiDB 中是完全一致的行为。针对这种情况,目前的办法只有将这些条件都放入 OR 的子项中,针对这里用到的例子,那就是要改写为 ((a = 1 and b = 1 and c = 1) or (a = 2 and b = 2 and c = 1))。 计算逻辑区间 这一步骤中,利用上一步抽取出来的表达式估算出数据的逻辑区间范围,后续会根据这个逻辑区间以及数据编码方式构造物理区间进行数据访问。我们仍然分为单列索引和多列索引两个情况来介绍。单列索引 这种情况下,输入的表达式为 Column op Constant 形式的简单表达式由 OR 以及 AND 连接而成。我们对每一个具体的操作符,都设计了一段对应的计算 range 的逻辑,当遇到 AND 或者 OR 时,会对两个区间求交或者求并。在 point.go 中有一个 builder 的结构体用来处理上述逻辑。在这个阶段我们记录 range 时用 rangePoint 的结构来存储 range。// Point is the end point of range interval. type point struct { value types.Datum excl bool // exclude start bool } 每个 point 代表区间的一个端点,其中的 excl 表示端点为开区间的端点还是闭区间的端点。start 表示这个端点是左端点还是右端点。builder 中每个 buildFromXXX 的方法都是计算一个具体函数的 range 的方法。比如 buildFromIn 便是处理 in 函数 的方法。可以看到它首先对 in 函数的值列表的每个值都构造了一个 rangPoint 的单点区间,然后对这些区间放在一个 slice 中做排序以及去重。最终将去重后的结果输出。在 pointer.go 中还包含其他各类的函数的处理,具体可以翻阅源代码。除了对具体函数的处理外,pointer.go 中还有区间交和区间并的操作。intersection 和 union 分别代表区间交和区间并。两个函数的逻辑均通过 merge 方法进行处理,通过传入一个 flag 来区分。merge 函数做了如下两个假设: a, b 两个区间均已经做过去重 单个区间序列内部不会有重叠的部分 merge 函数使用 inRangeCount 来记录当前位置被 a, b 两个区间序列覆盖的情况。区间求并的情况时,只要 a, b 两个区间序列中有一个区间序列覆盖便可以作为解输出,被两个区间同时覆盖的端点必然是属于一个更大的区间的内部不需要输出。所以当 inRangeCount 为 1 时,即为需要输出的区间端点。当区间求交时,需要两个序列都覆盖到才是可以输出的端点,所以当 inRangeCount 为 2 时,即为需要输出的区间端点。在得到最后的区间端点序列后,由 points2TableRanges 转化为对外暴露的 range 结构,由 BuildTableRange 输出到 plan package。// NewRange represents a range generated in physical plan building phase. type NewRange struct { LowVal []types.Datum HighVal []types.Datum LowExclude bool // Low value is exclusive. HighExclude bool // High value is exclusive. } 在现在的 TiDB 中,单列索引和多列索引使用了相同的 range 结构,所以这里的端点值为 slice 的形式。多列索引 对于多列索引,当其为 AND 表达式时,根据前述我们可以知道,其形式必为索引前缀列上的等值条件再加上关于前缀之后一个列的复杂条件组成。所以我们只需要按顺序处理点查的等值条件部分,将点查的区间依次 append 到 NewRange 中的 LowVal 和 HighVal 两个 Slice 中即可(appendPoints2Ranges)。处理到最后一列时,将之前的 NewRange 按最后非点查列所计算得到的区间个数拷贝一下,再依次 append 即可。具体代码可见 buildCNFIndexRange。对于 OR 表达式的情况,由于此时 range 已经无法转回 point 的结构。所以这里重新实现了一下区间并的操作。实现的形式便是比较常见的将区间按左端点排序,在依次扫过区间的同时,记录当前所有重叠过的区间的最右右端点来进行做区间并的算法。区间并的具体的实现可见 unionRanges 方法。Future Plan 目前 TiDB 对单列索引的处理在逻辑上已经非常完备,在实际表现上可能由于没有对部分函数实现计算 range 的逻辑而有遗漏。这部分会根据情况进行优化。 如上文提到的,目前 TiDB 为了简化 ranger 的逻辑,对多列索引做了一些假设。未来会尝试去掉或者弱化这些假设,或者在前期对 SQL 进行更充分的改写使得 SQL 不会触发这些假设,来提供更加强大的功能,免于手动 rewrite 的麻烦。 目前 TiDB 对简单式子的形式的检查限定在了 Column op Constant 的形式。所以诸如 from_unixtime(timestamp_col) op datetime_constant 形式的条件是无法计算索引的,也需要手动 rewrite 为 timestamp_col op timestamp_constant 才可以使用到索引。这部分也会考虑进行改进以提升用户体验。 "}, {"url": "https://pingcap.com/blog/tispark-more-data-insights-no-more-etl/", "title": "TiSpark: More Data Insights, Less ETL", "content": " Author: Shawn Ma is a Tech Lead at PingCAP in the OLAP team. Previously, he was Tech Lead at Netease and Quantcast. He received his Masters in Computer Science from University of California–Irvine.When we released TiDB 2.0 in April, part of that announcement also included the release of TiSpark 1.0–an integral part of the TiDB platform that makes complex analytics on “fresh” transactional data possible. Since then, many people in the TiDB community have been asking for more information about TiSpark. In this post, I will explain the motivation, inner workings, and future roadmap of this project.Motivation The motivation behind building TiSpark was to enable real-time analytics on TiDB without the delay and challenges of ETL. Extract, transform, and load (ETL)–a process to extract data from operational databases, transform that data, then load it into a database designed to supporting analytics–has been one of the most complex, tedious, error-prone, and therefore disliked tasks for many data engineers. However, it was a necessary evil to make data useful, because there hasn’t been good solutions on the market to render ETL obsolete–until now.With the emergence of open-source database solutions like TiDB, the promise of a hybrid transactional and analytical processing (HTAP) architecture, a term first coined by Gartner, is fast becoming a reality. Whether you subscribe to HTAP or other similar terms, like hybrid operational and analytical workloads (HOAP) (by 451 Research) or “Translytical” (by Forrester), it’s clear that the industry is calling for an end to the separation of the online transactional processing (OLTP) and online analytical processing (OLAP). No one wants to deal with ETL anymore.To make this possible, PingCAP and its open source contributors built TiDB and TiSpark, which was recognized in a recent report from 451 Research as an open source, modular NewSQL database that can be deployed to handle both operational and analytical workloads. TiSpark, which tightly integrates Apache Spark with TiKV, a distributed transactional key-value store on the TiDB platform, allows our customers to access operational data that was just recorded inside TiKV and run complex analytical queries on it right away.(If you are interested in experiencing an HTAP database on your laptop with TiDB + TiSpark, check out this 5-minute tutorial to spin up a cluster using Docker-Compose!)So How Does TiSpark Work? TiSpark leverages the power and popularity of Apache Spark with TiKV to enhance TiDB’s OLAP capabilities. Spark is a unified analytics engine that supports many big data use cases with a nice SQL interface (aka Spark SQL). TiDB from its very first day was built to be a relational SQL database with horizontal scalability; currently it’s compatible with MySQL. While TiDB has a complex and powerful optimizer and coprocessor architecture to support ad-hoc OLAP queries using MySQL, it’s even better to leverage a feature-rich engine like Spark to complete the missing piece in the HTAP puzzle. Thus, TiSpark was born.TiSpark is a connector that supports the following features: Complex calculation pushdown: this feature produces better performance by pushing down complex calculations to TiKV Key-range pruning: examines the sorted keys in TiKV and only returns the results we need Index support for: Clustered index/non-clustered index Index only query optimization Cost-based optimization for: Histogram support Index selection Here’s high-level overview of TiSpark’s architecture:As you can see from the architecture diagram, TiSpark works with Placement Driver (PD), the metadata cluster of TiDB to retrieve snapshots of data location, drives the query plans into the coprocessor layer, and retrieves the data directly from TiKV, where data is actually stored and persisted.Before we go further, let’s have a better understanding of TiKV first. TiKV has a computing module called coprocessor, which can process most of the expression evaluations inside of TiKV itself. And as your TiKV cluster grows, coprocessors expand as well. This is one of the most important reasons why TiDB as a whole scales so well both in terms of capacity and performance.For TiSpark to leverage these features inside TiKV, it makes use of Spark’s extension point called ‘ExperimentalMethods,’ because the current Spark data source API doesn’t give users the ability to execute complex calculations pushdown.These extension points expose SQL compiler’s optimization and planning details, thus allowing developers to configure the internal behaviors of almost every aspect of SQL compilation. They are at the core of TiSpark’s power. Now, we can inject our own rules and do extra work to push down more computations, such as predicates, aggregation pushdown, and Top-N pushdown (LIMIT clause with ORDER BY).TiSpark in Action Let’s use an example to illustrate how TiSpark works in action.Suppose we have a student table, and there are two indices associated with it: primary index (clustered index) on column studentId and a secondary index on school column. We want to run the following query on this table:select class, avg(score) from student WHERE school = 'engineering' and lottery(name) = 'picked' and studentId >= 8000 and studentId < 10100 group by class; The above query contains two predicates, each of which matches an index. TiSpark will first analyze the predicates combination and “approximate” how many rows will be returned if a specific index is applied. The goal here is to find a way to access the table with minimum cost. The process of finding an access path will be explained later. For now, let’s first look at how predicates are processed.Path 1: Primary Index Assume we pick the studentID index, the primary index, to access the table. The process is as follows: Transform the predicates “studentId >= 8000 and studentId < 10100” into a close-open interval on studentID: [8000, 10100); Prune the irrelevant ‘regions’ according to the above interval and the internal data distribution information in TiKV. For the clustered index column, TiKV uses the column to split and distribute data among different TiKV nodes. If we have a value interval on ‘studentId,’ we can directly prune all the ‘regions’ that are outside of the interval. Convert the interval into coprocessor requests [8000, 10000), [10000, 10100), respectively, for both region 2 and 3 (and ignore region 1, as illustrated below) and get the data via a sequential scan. Path 2: Secondary Index So what if we choose a different path by using the ‘school’ column index instead of the primary index? TiSpark will then go through a different procedure for secondary index. A secondary index in TiKV is encoded like main table data. (For more detailed info on how TiKV encodes data, please see this post.) The difference is the split / sort key is not on primary key but on the index keys, and primary key is attached at the end for each index entry.TiSpark reads all index entries per value range “school = ‘engineering’” to retrieve all primary keys in the similar way illustrated above. We don’t directly search the main table via primary keys retrieved. Instead, we do a shuffle by regionID for each primary key, and then in each of the executor, TiSpark tries to merges all the keys into continuous range. By doing so, TiSpark transforms point queries into range queries and improves performance. If there are cases where primary keys are sparse and scattered, then for that specific region, the system automatically adapts by downgrading point queries to a single region scan to avoid performance hit.So Which Path Does TiSpark Choose? TiSpark relies on a histogram built within TiDB to estimate cost and pick which …"}, {"url": "https://pingcap.com/meetup/meetup-20180710-no71/", "title": "【Infra Meetup No.71】TiDB 2.1 新特性与未来规划", "content": " 在上周六举办的 Infra Meetup No.71 上,我司申砾老师重点介绍了 TiDB 2.1 Beta 版本在 Raft / PD / SQL 执行引擎等方面的新特性以及未来的规划(中间穿插着我司 CTO 的各种「插播新闻」😂)。当天虽然下着小雨,但丝毫没有影响大家的热情,活动结束后还有不少童鞋留下来讨论哦~以下是现场视频&文字回顾,enjoy !视频回顾 视频 | Infra Meetup No.72:TiDB 2.1 新特性与未来规划可下载 完整 PPT 配合观看干货节选 TiDB 2.0 版本于今年 4 月底发布,经过两个月的开发,2.1-Beta 版本于 6 月底发布。这个版本在 2.0 的基础之上做了不少改进。在 Raft 方面,2.1 最大的变化是引入了 Learner 和 PreVote 两个特性。其中 Learner 可以加强调度过程中的数据安全性,并且为将来 OLAP 请求读 Learner 副本打下基础;PreVote 可以增强系统的稳定性,降低诸如网络隔离后节点重新加入造成的系统抖动。在 PD 方面,2.1 优化了热点调度功能,收集更详细更准确的集群负载信息,并做更合理的调度在 SQL 优化器方面对 CBO 框架做了进一步改进,提升代价估算准确度。在 SQL 执行引擎方面,将 Hash 聚合算子以及 Projection 算子做了并行化,提升大数据量下查询的性能。同时我们也在探索 OLTP 场景下的性能提升方案,预计到 2.1 正式版本时可以看到一些明显的进步。对于下一步的计划,我们依然将系统的正确性、稳定性放在首位,在此基础之上尽可能提升性能,比如我们准备的大杀器 ——新一代存储引擎,在内部原型测试中表现出良好的性能。另外,TiDB 作为一个开源项目,非常欢迎大家参与,我们也会将 TiDB 源码阅读系列文章持续写下去,并且将更多的内部设计文档开源处理,敬请期待。附:TiDB 2.1 Beta Release Notes PingCAP Infra Meetup作为一个基础架构领域的前沿技术公司,PingCAP 希望能为国内真正关注技术本身的 Hackers 打造一个自由分享的平台。自 2016 年 3 月 5 日开始,我们定期在周六的上午举办 Infra Meetup,邀请业内大牛与大家深度探讨基础架构领域的前瞻性技术思考与经验。在这里,我们希望提供一个高水准的前沿技术讨论空间,让大家真正感受到自由的开源精神魅力。 "}, {"url": "https://pingcap.com/weekly/2018-07-09-tidb-weekly/", "title": "Weekly update (July 02 ~ July 08, 2018)", "content": " Weekly update in TiDB Last week, we landed 34 PRs in the TiDB repositories.Added Support session variables warning_count and error_count Support BIT_OR in the new aggregation function framework Fixed Fix the privilege bug when reusing chunks Fix the issue that the Hash Aggregate operator cannot exit Fix a panic on Stream Aggregate Fix the results of SHOW CREATE TABLE when adding indices Fix the results of non-integer inputs for bit related aggregate functions Improved Use feedback to refine updating statistics information Refactor statistics updating mechanism to speed up analyzing tables Allow the user to kill his own connections without the SUPER privilege Weekly update in TiSpark Last week, we landed 5 PRs in the TiSpark repositories.Improved Allow TiSpark to retrieve row ID Add more rules for scalafmt Fixed Fix the issue that the scan iterator throws NoSuchElement Exception when encountering the last Region Fix the issue that tispark-sql dbName is displayed as the table name Weekly update in TiKV and PD Last week, we landed 26 PRs in the TiKV and PD repositories.Added Add a new scalar function multiply_int_unsigned Support getting Region approximate middle key by tikv-ctl Add an option to restrict the number of RocksDB log files Add the development workflow file for PD Fixed Fix the split check bug when region_max_size equals to region_split_size Fix the panic issue when no operator is produced by the adjacent Region scheduler Fix the issue that the store space is used up due to moving replicas Improved Use crossbeam-channel to improve the performance Enlarge the total slots of the scheduler latch Exit all Goroutines ASAP when the PD client is closed Send back HTTP 400 where there is a client error New contributors (Thanks!) TiDB: zbdba TiSpark: gkdoc TiKV: GuillaumeGomez "}, {"url": "https://pingcap.com/blog-cn/tidb-source-code-reading-12/", "title": "TiDB 源码阅读系列文章(十二)统计信息(上)", "content": " 在 TiDB 里,SQL 优化的过程可以分为逻辑优化和物理优化两个部分,在物理优化阶段需要为逻辑查询计划中的算子估算运行代价,并选择其中代价最低的一条查询路径作为最终的查询计划。这里非常关键的一点是如何估算查询代价,本文所介绍的统计信息是这个估算过程的核心模块。这部分内容非常复杂,所以会分成两篇文章来介绍。本篇文章介绍统计信息基本概念、TiDB 的统计信息收集/更新机制以及如何用统计信息来估计算子代价。上篇侧重于介绍原理,下篇会结合原理介绍 TiDB 的源码实现。统计信息是什么 为了得到查询路径的执行代价,最简单的办法就是实际执行这个查询计划,不过这样子做就失去了优化器的意义。不过,优化器并不需要知道准确的代价,只需要一个估算值,以便能够区分开代价差别较大的执行计划。因此,数据库常常会维护一些实际数据的概括信息,用以快速的估计代价,这便是统计信息。在 TiDB 中,我们维护的统计信息包括表的总行数,列的等深直方图,Count-Min Sketch,Null 值的个数,平均长度,不同值的数目等等。下面会简单介绍一下直方图和 Count-Min Sketch。直方图简介 直方图是一种对数据分布情况进行描述的工具,它会按照数据的值大小进行分桶,并用一些简单的数据来描述每个桶,比如落在桶里的值的个数。大多数数据库都会选择用直方图来进行区间查询的估算。根据分桶策略的不同,常见的直方图可以分为等深直方图和等宽直方图。在 TiDB 中,我们选择了等深直方图,于 1984 年在 Accurate estimation of the number of tuples satisfying a condition 文献中提出。相比于等宽直方图,等深直方图在最坏情况下也可以很好的保证误差。所谓的等深直方图,就是落入每个桶里的值数量尽量相等。举个例子,比方说对于给定的集合 {1.6, 1.9, 1.9, 2.0, 2.4, 2.6, 2.7, 2.7, 2.8, 2.9, 3.4, 3.5},并且生成 4 个桶,那么最终的等深直方图就会如下图所示,包含四个桶 [1.6, 1.9],[2.0, 2.6],[2.7, 2.8],[2.9, 3.5],其桶深均为 3。Count-Min Sketch 简介 Count-Min Sketch 是一种可以处理等值查询,Join 大小估计等的数据结构,并且可以提供很强的准确性保证。自 2003 年在文献 An improved data stream summary: The count-min sketch and its applications 中提出以来,由于其创建和使用的简单性获得了广泛的使用。Count-Min Sketch 维护了一个 d*w 的计数数组,对于每一个值,用 d 个独立的 hash 函数映射到每一行的一列中,并对应修改这 d 个位置的计数值。如下图所示:这样在查询一个值出现了多少次的时候,依旧用 d 个 hash 函数找到每一行中被映射到的位置,取这 d 个值的最小值作为估计值。直方图和 CM-Sketch 是常用的两种数据概要手段,想了解更多相关技术,可以参考 《Synopses for Massive Data: Samples,Histograms, Wavelets, Sketches》。统计信息创建 通过上面的描述,我们知道统计信息主要需要创建和维护的是直方图和 Count-Min Sketch。通过执行 analyze 语句,TiDB 会收集上述所需要的信息。在执行 analyze 语句的时候,TiDB 会将 analyze 请求下推到每一个 Region 上,然后将每一个 Region 的结果合并起来。对于 Count-Min Sketch,其创建和合并都比较简单,在这里略去不讲。以下主要介绍列和索引的直方图的创建。列直方图的创建 在创建直方图的时候,需要数据是有序的,而排序的代价往往很高,因此我们在 TiDB 中实现了抽样算法,对抽样之后的数据进行排序,建立直方图,即会在每一个 Region 上进行抽样,随后在合并结果的时候再进行抽样。在 sample.go 中,我们实现了蓄水池抽样算法,用来生成均匀抽样集合。令样本集合的容量为 S,在任一时刻 n,数据流中的元素都以 S/n 的概率被选取到样本集合中去。如果样本集合大小超出 S,则从中随机去除一个样本。举个例子,假如样本池大小为 S = 100 ,从头开始扫描全表,当读到的记录个数 n < 100 时,会把每一条记录都加入采样池,这样保证了在记录总数小于采样池大小时,所有记录都会被选中。而当扫描到的第 n = 101 条时,用概率 P = S/n = 100⁄101 决定是否把这个新的记录加入采样池,如果加入了采样池,采样池的总数会超过 S 的限制,这时需要随机选择一个旧的采样丢掉,保证采样池大小不会超过限制。采样完成后,将所有的数据排序,由于知道采样过后总的行数和直方图的桶数,因此就可以知道每个桶的深度。这样就可以顺序遍历每个值 V: 如果 V 等于上一个值,那么把 V 放在与上一个值同一个桶里,无论桶是不是已经满,这样可以保证每个值只存在于一个桶中。 如果不等于,那么判断当前桶是否已经满,如果不是的话,就直接放入当前桶,否则的话,就放入下一个桶。 索引直方图的创建 在建立索引列直方图的时候,由于不能事先知道有多少行的数据,也就不能确定每一个桶的深度,不过由于索引列的数据是已经有序的,因次可以采用如下算法:在确定了桶的个数之后,将每个桶的初始深度设为 1,用前面列直方图的创建方法插入数据,这样如果到某一时刻所需桶的个数超过了当前桶深度,那么将桶深扩大一倍,将之前的每两个桶合并为 1 个,然后继续插入。在收集了每一个 Region 上分别建立的直方图后,还需要把每个 Region 上的直方图进行合并。对于两个相邻 Region 上的直方图,由于索引是有序的,因此前一个的上界不会大于后一个的下界。不过为了保证每个值只在一个桶里,我们还需要先处理一下交界处桶的问题,即如果交界处两个桶的上界和下界相等,那么需要先合并这两个桶。如果直方图合并之后桶的个数超过了限制,那么只需要把两两相邻的桶合二为一。统计信息维护 在 2.0 版本中,TiDB 引入了动态更新机制(2.0 版本默认没有打开, 2.1-beta 版本中已经默认打开),可以根据查询的结果去动态调整统计信息。对于直方图,需要调整桶高和桶的边界;对于 CM Sketch,需要调整计数数组,使得估计值和查询的结果相等。桶高的更新 在范围查询的时候,涉及的桶都有可能对最终的结果贡献一些误差。因此,一种更新的方法便是假定所有桶贡献的误差都是均匀的,即如果最终估计的结果为 E,实际的结果为 R,某一个桶的估计结果为 b = 桶高 h * 覆盖比例 r,那么就可以将这个桶的桶高调整为 (b / r) * (R / E) = h * (R / E)。不过如果可以知道落在每一个桶范围中的实际结果,便可以不去假定所有桶贡献的误差都是均匀的。为了知道落在每一个桶范围中的实际结果,需要先把查询的范围按照直方图桶的边界切分成不相交的部分,这样 TiKV 在执行查询的时候,可以统计出每一个范围中实际含有的行数目。这样我们便可以按照类似于前述的方法调整每一个桶,不过这个时候不需要假定每个桶贡献的误差都是均匀的,因为我们可以准确知道每一个桶贡献的误差。桶边界的更新 在用直方图估计的时候,对于那些只被查询范围覆盖了一部分的桶,主要的误差来自连续平均分布假设。这样桶边界更新的主要目便是使得查询的边界能尽量的落在与桶的边界不远的地方。桶边界的更新主要方法包括分裂和合并。对于分裂,需要解决的问题是哪些桶需要分裂,分裂成几个,分裂的边界在哪里: 哪些桶需要分裂,分裂成几个:如果决定了每一次更新最多分裂 10 个桶,那么如果一个桶上落入了 10% 的查询点,那个这个桶就可以分裂一次,如果落入了 20% 的查询点,那么这个桶就可以分裂两次,以此类推。 分裂的边界:由于目标是使得查询的边界能尽量的落在与桶的边界不远的地方,那么如果这个桶要分裂 N 次,就需要选择不超过 N 个查询点,使得剩下的查询点与这 N 个查询点的最近距离之和最小。不过这种方法比较复杂,我们也可以采用比较简单的方法,即假定每个不同的查询点之间的距离都是相等的,这样只需要每隔几个点取一个作为边界就可以。 分裂完成后,我们还要去合并桶。首先分裂得来的桶是不能合并的;除此之外,考虑连续的两个桶,如果第一个桶占合并后桶的比例为 r,那么令合并后产生的误差为 abs(合并前第一个桶的高度 - r * 两个桶的高度和) / 合并前第一个桶的高度,就只需要去合并误差最小的那些连续的桶。Count-Min Sketch 的更新 CM Sketch 的更新比较简单,对于某一个等值查询的反馈结果 x,其估计值是 y,那么我们只需要将这个值涉及到的所有点加上 c = x-y。统计信息使用 在查询语句中,我们常常会使用一些过滤条件,而统计信息估算的主要作用就是估计经过这些过滤条件后的数据条数,以便优化器选择最优的执行计划。在这篇 文档 中,介绍到 explain 输出结果中会包含的一列 count,即预计当前 operator 会输出的数据条数,便是基于统计信息以及 operator 的执行逻辑估算而来。在这个部分中,我们会先从最简单的单一列上的过滤条件开始,然后考虑如何处理多列的情况。范围查询 对于某一列上的范围查询,TiDB 选择了常用的等深直方图来进行估算。在前面介绍等深直方图时,我们得到了一个包含四个桶 [1.6, 1.9],[2.0, 2.6],[2.7, 2.8],[2.9, 3.5],其桶深均为 3 的直方图。假设我们得到了这样一个直方图,并且想知道落在区间 [1.7, 2.8] 范围内的有多少值。把这个区间对应到直方图上,可以看到有两个桶是被完全覆盖的,即桶 [2.0, 2.6] 和桶 [2.7,2.8],因此区间 [2.0, 2.8] 内一共有 6 个值;但是第一个桶只被覆盖了一部分,那么问题就变成了已经知道区间 [1.6, 1.9] 范围内有 3 个值,怎样估算 [1.7, 1.9] 内有多少个值呢?一个常用的方法是假设这个范围的值是连续且均匀的,那么我们就可以按照查范围占桶的比例去估算,也就是 (1.9 - 1.7) / (1.9 - 1.6) * 3 = 2。不过这里还有一个问题是估算的时候要去算比例,这对于数值类型很简单,对于其他类型,比方说字符串类型怎么办呢?一个方法是把字符串映射成数字,然后计算比例,具体可以参见 statistics/scalar.go。等值查询 对于类似查询等于某个值的这样的等值查询,直方图就捉襟见肘了。一般常用的估计方法是假设每个值出现的次数都相等,这样就可以用(总行数/不同值的数量)来估计。不过在 TiDB 中,我们选择了 Count-Min Sketch 的来进行等值查询的估算。由于 Count-Min Sketch 估计的结果总是不小于实际值,因此在 TiDB 中,我们选择了文献 New estimation algorithms for streaming data: Count-min can do more 中提出了一种 Count-Mean-Min Sketch,其与 Count-Min Sketch 在更新的时候是一样的,区别在与查询的时候:对于每一行 i,若 hash 函数映射到了值 j,那么用 (N - CM[i, j]) / (w-1)(N 是总共的插入的值数量)作为其他值产生的噪音,因此用 CM[i,j] - (N - CM[i, j]) / (w-1) 这一行的估计值,然后用所有行的估计值的中位数作为最后的估计值。多列查询 上面两个小节介绍了 TiDB 是如何对单列上的查询条件进行估计的,不过实际的查询语句中往往包含多个列上的多个查询条件,因此我们需要考虑如何处理多列的情况。在 TiDB 中,selectivity.go 中的 Selectivity 函数实现了这个功能,它是统计信息模块对优化器提供的最重要的接口。在处理多列之间的查询条件的时候,一个常见的做法是认为不同列之间是相互独立的,因此我们只需要把不同列之间的过滤率乘起来。不过,对于索引上的可以用来构造索引扫描的范围的过滤条件,即对于一个 (a, b, c) 这样的索引,类似 (a = 1 and b = 1 and c < 5) 或者 (a = 1 and b = 1) 这样的条件,将索引中的值编码后,就可以用前面提到的方法进行估算,这样就不需要假定列之间是相互独立的。因此,Selectivity 的一个最重要的任务就是将所有的查询条件分成尽量少的组,使得每一组中的条件都可以用某一列或者某一索引上的统计信息进行估计,这样我们就可以做尽量少的独立性假设。在 Selectivity 中,首先计算了每一列和每一个索引可以覆盖的过滤条件,并用一个 int64 来当做一个 bitset,将该列可以覆盖的过滤条件的位置置为 1。接下来的任务就是选择尽量少的 bitset,来覆盖尽量多的过滤条件,在这一步中,我们使用了贪心算法,即每一次在还没有使用的 bitset 中,选择一个可以覆盖最多尚未覆盖的过滤条件。最后一步便是用前面提到的方法对每一个列和每一个索引上的统计信息进行估计,并用独立性假设将它们组合起来当做最终的结果。"}, {"url": "https://pingcap.com/weekly/2018-07-02-tidb-weekly/", "title": "Weekly update (June 25 ~ July 01, 2018)", "content": " Weekly update in TiDB Last week, we landed 39 PRs in the TiDB repositories.Added Add a session variable tidb_ddl_reorg_worker_cnt to control the number of the DDL organization workers Support parallel HASH aggregation and greatly improve the performance of the aggregation function Print explain results in a tree style Support the SHOW ERRORS statement and improve the SHOW WARNINGS statement Fixed Make the INSERT IGNORE statement ignore BadNullError Fix a bug when only_full_group_by is set in SQL_MODE Fix the wrong results of avg(double) Make the CREATE TABLE IF NOT EXISTS LIKE statement work again Set the correct startHandle when some errors occur in adding indexes Fix a bug in pushing down TopN Fix the response result bug of COM_FIELD_LIST Fix a bug of the str_to_date() function Fix a bug of the INSERT statement when the field type is unsigned float/double Improved Use the average error of the row count which is estimated by statistics to determine the pseudo column Use CorrelatedColumn to calculate range Make the frequency of updating the statistic metadata depend on the table size Refactor the execution framework of the aggregate functions Speed up the CreateTable operation Stop calling expression.Clone in the plan package except ResolveIndices Handle N as NULL in LOAD DATA Avoid holding the Write lock for a long time Reduce the memory usage in the INSERT INTO SELECT statement Enhance the row count estimation when the correlated column exists Check the character set capitalization when creating a table Improve the accessPath for the unique key Weekly update in TiKV and PD Last week, we landed 25 PRs in the TiKV and PD repositories.Added Support splitting a Region by key using tikv-ctl Provide PerfContext statistics in Coprocessor Fuzz decimals Collect thread state metrics Fixed Fix the issue that the store runs out of space due to moving replicas Fix a bug in do_sub when the last nonzero digit is before the point Fix potential stale Read during merging Handle heartbeats of Regions with changed peers Improved Return the UnknownSignature error for unimplemented signatures Remove Box<> around Cursor, Snapshot and Engine Upgrade Rust to the nightly-2018-06-14 version New contributors (Thanks!) TiDB: cityonsky mail2fish Docs: yejiayu "}, {"url": "https://pingcap.com/success-stories/tidb-in-eleme/", "title": "Ele.me? TiDB At Your Service", "content": " Industry: Food DeliveryAuthors: Yanzhao Zhang (Senior Database Engineer at Ele.me) and Dongming Chen (Senior Infrastructure Engineer at Ele.me)Ele.me, which means “Are you hungry?” in Chinese, is the largest online food delivery platform in China. Our platform allows users to order all kinds of food and beverages and get their takeout delivered within 30 minutes. Currently, with 3 million scooter-riding delivery staff, Ele.me is serving 260 million customers and 1.3 million vendors in over 2,000 cities in China. In April 2018, Ele.me was acquired by Alibaba for $9.5 billion USD.With a fast-growing business comes soaring data size, which has placed tremendous pressure on Ele.me’s backend system, especially the database. How to tackle the challenges that come with mounting data has been a nightmare until we found TiDB, a MySQL compatible distributed hybrid transactional and analytical processing (HTAP) database, and its distributed key-value storage engine TiKV, both built and supported by PingCAP. Finally, we can harness the power of our data and not be intimidated by it.Currently, our TiKV deployment serves 80% of the traffic on the entire Ele.me platform, covering every activity from making orders to processing delivery. Our TiDB deployment holds 45% of our entire archived data. In this post, we will share how and why we chose TiDB and TiKV, how we are using them, best practice suggestions, and our experience in working hand-in-hand with the PingCAP team.Our Evaluation Process Before choosing TiDB/TiKV, we carefully evaluated other options – TokuDB, MySQL Cluster, Percona XtraDB Cluster, Cassandra, Vertica, Apache HBase, and Google Spanner. Here’s what we found: TokuDB, a storage engine for MySQL and MariaDB, supports safe and fast DDL as a plug-in of MySQL. Applications which run on MySQL can work on TokuDB quite easily, but it is only a plug-in storage engine without elastic scalability. MySQL Cluster and Percona XtraDB Cluster are scalable but only in their computing capability, not storage capacity. DDL for big tables also remains a tough task. Column-oriented databases like Cassandra and Vertica support elastic scalability of both computing and storage with safe and fast DDL, but Cassandra is a non-relational database and does not support distributed transactions while Vertica is not designed for OLTP workloads. All of our existing MySQL-based applications must be transformed to be compatible with them, which creates a lot of work. HBase has the same advantages and disadvantages of column-oriented databases. In addition, its operation and maintenance costs is too high for our archive job. Google Spanner is a relational database which supports horizontal scalability, fast online DDL, and distributed transactions. But it does not support MySQL protocol and is only available on Google Cloud Platform. Why TiDB and TiKV? TiDB and TiKV support fast online DDL, horizontal scalability, and high availability by applying the Raft consensus protocol. It is also compatible with MySQL. TiDB presents a layered, modular architecture and allows us to use different components flexibly to meet our needs. Additionally, TiDB has an active open source community (more than 16,000 Github stars total), which gives us a lot of confidence in its pace of development, bug fixes, and future features. TiDB Architecture Use Case 1: Unifying Data Storage in TiKV Most of our data is in key-value structure. Before using TiKV, our data was scattered among different databases, including MySQL, Redis, MongoDB, and Cassandra, making it very hard to scale, manage, and operate, not to mention overall poor performance. We needed a unified key-value storage system with the following technical criteria: Large capacity to store at least dozens of TBs of data; High QPS performance with low latency; High availability and fault-tolerance. Data must be stored persistently and safely even with machine downtime. (The food delivery business demands higher real time data processing capability and availability compared with traditional E-commerce services, especially during peak hours.) Easy operation and maintenance, with simple data migration and cluster scaling without interruption. Redis on TiKV TiKV, as a standalone component of the TiDB platform, meets all of our criteria, and can serve as a building block for other client protocols. We’ve been using Redis and wanted to keep using it with TiKV. Redis on TiKV In this architecture, the upper layer translates the Redis protocol, while the TiKV layer implements distributed system features, including horizontal scalability, high availability and strong consistency using data partition, the Raft protocol, MVCC and distributed transaction. TiKV Architecture With these components working together, we were able to build our own Redis proxy on top of TiKV, so we can tap into its power while keeping the interface we like to use best.Ele.me’s Redis LayerWe built the ekvproxy service, where we wrapped the TiKV SDK to parse the Redis protocol and transformed it to communicate with TiKV. Extensions like compression and traffic control were implemented on this foundation. Our team can now use the official Redis client to access our key-value service backed by TiKV without changing their workflow or behavior.The PingCAP team was instrumental in helping us implement the Raw SCAN feature of TiKV, so our service can be better compatible with the Redis protocol.In-Production Scale In the second half of 2017, we deployed TiKV as Ele.me’s main key-value storage system, which supports 80% of our traffic. The scale and status of our deployment is as follow: A dozen TiKV clusters in four data centers located in Beijing, Shanghai and Guangzhou with 100+ nodes holding dozens of TBs of data; A complete monitor alert system which all TiKV clusters connect to. It sends the alert messages instantly when problems occur, guaranteeing timely troubleshooting; During peak traffic time, the Write QPS is nearly 50,000 and the Read QPS is approximately 100,000 in the busiest clusters; We’ve deployed TiKV for almost a year, and thus far, all clusters have been running smoothly without any incident. Use Case 2: TiDB As Archive As our business continues to grow, so does our data volume, which constantly consumes more physical resources like disks and CPUs and affects performance.To fix this, we often archive data on a regular basis from online services to offline storage. Some of our online services only need data from the last three weeks or three months.Our Pain Points MySQL is our main database solution at Ele.me for archiving. To archive a large amount of data, we deployed several highly available master-slave MySQL clusters on machines with large disk capacity. During the archiving process, we confronted three pain points:Pain Point 1: Changing the table schema was a thorny task, and we needed DDL support. A standard archive process works well, when the data size increases gently and the table schema is fixed. But for Ele.me, the data volume is massive, grows quickly, and our services are constantly changing, which requires frequent modifications to the table schema.Pain Point 2: Scaling the storage capacity horizontally was difficult. MySQL does not scale easily, and we keep on adding large disks but run out of room quickly. We had to constantly create new archive clusters, posing risks to our applications that need access to the archive from time to time.Pain Point 3: It was time-consuming to resynchronize data after a failure recovery. Although the archive cluster was highly available, recovering from a master switch from unexpected downtime took a long time because of the nature of a master-slave architecture.Thankfully, TiDB has the right features and design to provide online DDL, simple horizontal scalability, and Raft-based auto-recovery and self-healing, to help us solve all three pain points.Adoption Process Proof of Concept Setup Initially …"}, {"url": "https://pingcap.com/blog-cn/tidb-source-code-reading-11/", "title": "TiDB 源码阅读系列文章(十一)Index Lookup Join", "content": " 什么是 Index Lookup Join Nested Loop Join 在介绍 Index Lookup Join 之前,我们首先看一下什么是 Nested Loop Join(NLJ)。 NLJ 的具体定义可以参考 Wikipedia。NLJ 是最为简单暴力的 Join 算法,其执行过程简述如下: 遍历 Outer 表,取一条数据 r; 遍历 Inner 表,对于 Inner 表中的每条数据,与 r 进行 join 操作并输出 join 结果; 重复步骤 1,2 直至遍历完 Outer 表中的所有数据。 NLJ 算法实现非常简单并且 join 结果的顺序与 Outer 表的数据顺序一致。但是存在性能上的问题:执行过程中,对于每一条 OuterRow,我们都需要对 Inner 表进行一次全表扫操作,这将消耗大量时间。为了减少对于 Inner 表的全表扫次数,我们可以将上述步骤 1 优化为每次从 Outer 表中读取一个 batch 的数据,优化后的算法即 Block Nested-Loop Join(BNJ),BNJ 的具体定义可以参考 Wikipedia。Index Lookup Join 对于 BNJ 算法,我们注意到,对于 Outer 表中每个 batch,我们并没有必要对 Inner 表都进行一次全表扫操作,很多时候可以通过索引减少数据读取的代价。Index Lookup Join(ILJ) 在 BNJ 基础上进行了改进,其执行过程简述如下: 从 Outer 表中取一批数据,设为 B; 通过 Join Key 以及 B 中的数据构造 Inner 表取值范围,只读取对应取值范围的数据,设为 S; 对 B 中的每一行数据,与 S 中的每一条数据执行 Join 操作并输出结果; 重复步骤 1,2,3,直至遍历完 Outer 表中的所有数据。 TiDB Index Lookup Join 的实现 TiDB 的 ILJ 算子是一个多线程的实现,主要的线程有: Main Thead,Outer Worker,和 Inner Worker: Outer Worker 一个: 按 batch 遍历 Outer 表,并封装对应的 task 将 task 发送给 Inner Worker 和 Main Thread Inner Worker N 个: 读取 Outer Worker 构建的 task 根据 task 中的 Outer 表数据,构建 Inner 表的扫描范围,并构造相应的物理执行算子读取该范围内的 Inner 表数据 对读取的 Inner 表数据创建对应的哈希表并存入 task Main Thread 一个: 启动 Outer Worker 及 Inner Workers 读取 Outer Worker 构建的 task,并对每行 Outer 数据在对应的哈希表中 probe 对 probe 到的数据进行 join 并返回执行结果 这个算子有如下特点: Join 结果的顺序与 Outer 表的数据顺序一致,这样对上一层算子可以提供顺序保证; 对于 Outer 表中的每个 batch,只在 Inner 表中扫描部分数据,提升单个 batch 的处理效率; Outer 表的读数据操作,Inner 表的读数据操作,及 Join 操作并行执行,整体上是一个并行+Pipeline 的方式,尽可能提升执行效率。 执行阶段详述 TiDB 中 ILJ 的执行阶段可划分为如下图所示的 5 步:1. 启动 Outer Worker 及 Inner Workers这部分工作由 startWorkers 函数完成。该函数会 启动一个 Outer Worker 和 多个 Inner Worker。Inner Woker 的数量可以通过 tidb_index_lookup_concurrency 这个系统变量进行设置,默认为 4。2. 读取 Outer 表数据这部分工作由 buildTask 函数完成。此处主要注意两点:第一点,对于每次读取的 batch 大小,如果将其设置为固定值,则可能会出现如下问题: 若设置的 batch 值较大,但 Outer 表数据量较小时。各个 Inner Worker 所需处理的任务量可能会不均匀,出现数据倾斜的情况,导致并发整体性能相对单线程提升有限。 若设置的 batch 值较小,但 Outer 表数据量较大时。Inner Worker 处理任务时间短,需要频繁从管道中取任务,CPU 不能被持续高效利用,由此带来大量的线程切换开销。此外, 当 batch 值较小时,同一批 inner 表数据能会被反复读取多次,带来更大的网络开销,对整体性能产生极大影响。 因此,我们通过指数递增的方式动态控制 batch 的大小(由函数 increaseBatchSize 完成),以避免上述问题,batch size 的最大值由 session 变量 tidb_index_join_batch_size 控制,默认是 25000。读取到的 batch 存储在 lookUpJoinTask.outerResult 中。第二点,如果 Outer 表的过滤条件不为空,我们需要对 outerResult 中的数据进行过滤(由函数 VectorizedFilter 完成)。outerResult 是 Chunk 类型(Chunk 的介绍请参考 TiDB 源码阅读系列文章(十)),如果对满足过滤条件的行进行提取并重新构建对象进行存储,会带来不必要的时间和内存开销。VectorizedFilter 函数通过一个长度与 outerResult 实际数据行数相等的 bool slice 记录 outerResult 中的每一行是否满足过滤条件以避免上述开销。 该 bool slice 存储在 lookUpJoinTask.outerMatch 中。3. Outer Worker 将 task 发送给 Inner Worker 和 Main ThreadInner Worker 需要根据 Outer 表每个 batch 的数据,构建 Inner 表的数据扫描范围并读取数据,因此 Outer Worker 需要将 task 发送给 Inner Worker。如前文所述,ILJ 多线程并发执行,且 Join 结果的顺序与 Outer 表的数据顺序一致。 为了实现这一点,Outer Worker 通过管道将 task 发送给 Main Thread,Main Thread 从管道中按序读取 task 并执行 Join 操作,这样便可以实现在多线程并发执行的情况下的保序需求。4. Inner Worker 读取 inner 表数据这部分工作由 handleTask 这个函数完成。handleTask 有如下几个步骤: constructDatumLookupKeys 函数计算 Outer 表对应的 Join Keys 的值,我们可以根据 Join Keys 的值从 Inner 表中仅查询所需要的数据即可,而不用对 Inner 表中的所有数据进行遍历。为了避免对同一个 batch 中相同的 Join Keys 重复查询 Inner 表中的数据,sortAndDedupDatumLookUpKeys 会在查询前对前面计算出的 Join Keys 的值进行去重。 fetchInnerResult 函数利用去重后的 Join Keys 构造对 Inner 表进行查询的执行器,并读取数据存储于 task.innerResult 中。 buildLookUpMap 函数对读取的 Inner 数据按照对应的 Join Keys 构建哈希表,存储于 task.lookupMap 中。 上述步骤完成后,Inner Worker 向 task.doneCh 中发送数据,以唤醒 Main Thread 进行接下来的工作。5. Main Thread 执行 Join 操作这部分工作由 prepareJoinResult 函数完成。prepareJoinResult 有如下几个步骤: getFinishedTask 从 resultCh 中读取 task,并等待 task.doneCh 发送来的数据,若该 task 没有完成,则阻塞住; 接下来的步骤与 Hash Join类似(参考 TiDB 源码阅读系列文章(九)),lookUpMatchedInners 取一行 OuterRow 对应的 Join Key,从 task.lookupMap 中 probe 对应的 Inner 表的数据; 主线程对该 OuterRow,与取出的对应的 InnerRows 执行 Join 操作,写满存储结果的 chk 后返回。 示例 CREATE TABLE `t` ( `a` int(11) DEFAULT NULL, `pk` int(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY (`pk`) ); CREATE TABLE `s` ( `a` int(11) DEFAULT NULL, KEY `idx_s_a` (`a`) ); ​ insert into t(`a`) value(1),(1),(1),(4),(4),(5); insert into s value(1),(2),(3),(4); ​ select /*+ TIDB_INLJ(t) */ * from t left join s on t.a = s.a; 在上例中, t 为 Outer 表,s 为 Inner 表。 /** TIDN_INLJ */ 可以让优化器尽可能选择 Index Lookup Join 算法。设 Outer 表读数据 batch 的初始大小为 2 行,Inner Worker 数量为 2。查询语句的一种可能的执行流程如下图所示,其中由上往下箭头表示时间线:"}, {"url": "https://pingcap.com/meetup/meetup-20180626-no70/", "title": "【Infra Meetup No.70】Paper Party:CEO 解读 TiDB 下一代存储引擎", "content": " 上周六举办的 Infra Meetup No.70,我们换了一个开阔些的场地——嗯,没看错,是我司的一间办公室,然而掏空了房间里的椅子沙发,还是不够坐。爆满的原因当然是我司 CEO 刘奇的「重磅分享」:刘奇分享了受威斯康辛的论文启发的 TiDB 下一代存储引擎的设计考量及实践,以及「关门福利」——非常强悍的测试结果,以下是现场视频 & 文字回顾,enjoy!视频回顾 视频 | Infra Meetup No.70:CEO 解读 TiDB 下一代存储引擎论文 slides 链接我司 CEO 刘奇首先为大家介绍了新的磁盘进化发展趋势,如何做软硬件协同设计,以及硬件的发展对数据库系统架构的影响。干货节选 存储引擎是数据库的核心组件之一,目前 TiDB 使用 LSM-Tree 作为底层的存储引擎,其良好的顺序写入特性得到了很大的发挥。然而 LSM-Tree 模型本身也不是尽善尽美,其中较为突出的缺点是写放大比较严重。该问题也吸引了不少学者的研究,也有不少改进论文出现。来自威斯康辛的论文 WiscKey: Separating Keys from Values in SSD-conscious Storage 是其中的典型代表。刘奇接着介绍了新一代存储引擎利用新的硬件特性的方式(比如充分发挥 SSD/NVMe/Optane 的多通道写入对存储引擎的提升),并解读了威斯康辛的论文在这方面的实践——利用多通道的并行能力来弥补 Key-Value 分离带来的开销。这个方法实现简单,效果极佳。TiDB 的新一代存储模型也受到这篇论文的启发。最后,刘奇分享了 PingCAP 在这方面的思考与实践,以及对下一代存储引擎设计的具体考量,并展示了正在研发的 TiDB 下一代存储引擎的强悍实测性能。测试结果显示,相比当前的版本,系统整体性能提升了 2-10 倍。 PingCAP Infra Meetup作为一个基础架构领域的前沿技术公司,PingCAP 希望能为国内真正关注技术本身的 Hackers 打造一个自由分享的平台。自 2016 年 3 月 5 日开始,我们定期在周六的上午举办 Infra Meetup,邀请业内大牛与大家深度探讨基础架构领域的前瞻性技术思考与经验。在这里,我们希望提供一个高水准的前沿技术讨论空间,让大家真正感受到自由的开源精神魅力。 "}, {"url": "https://pingcap.com/weekly/2018-06-25-tidb-weekly/", "title": "Weekly update (June 18 ~ June 24, 2018)", "content": " Weekly update in TiDB Last week, we landed 18 PRs in the TiDB repositories.Added Support the binary fetch command Add a variable to disable auto-retry of the transaction block Fixed Allow comments to end up with multiple asterisks as MySQL does Improved Allow using IndexJoin in more scenarios Improve the performance of the insert ignore on duplicate key update statement Optimize the accuracy of index row count estimation Weekly update in TiSpark Last week, we landed 5 PRs in the TiSpark repositories.Added Add deployment tools and information in pom Add the code coverage report tool Weekly update in TiKV and PD Last week, we landed 19 PRs in the TiKV and PD repositories.Added Count each index prefix when executing the Analyze operation Allow configuring the timespan of log rotation Provide more RocksDB metrics Fixed Fix TiKV panic when multiplying specific decimals Improved Change the maximum size of the bucket for snapshot from 2G to 1T Improve TiKV metrics performance PR1 PR2 Preserve logs instead of dropping logs when logs overflow New contributors (Thanks!) TiDB: mz1999 liuzhengyang "}, {"url": "https://pingcap.com/weekly/2018-06-19-tidb-weekly/", "title": "Weekly update (June 11 ~ June 17, 2018)", "content": " Weekly update in TiDB Last week, we landed 26 PRs in the TiDB repositories.Added Support the MySQL syntax show privileges Add the limit for the number of columns when adding columns Add the sanity check of the precision and the scale for numeric types Fixed Fix the wrong results of the CONCAT_WS built-in function Fix a bug in right join when some predicates are pushed to the right table Fix the missing start timestamp for TableDual in a transaction Improved Refactor the structure of the DDL package Remove new lines and add the user information in the query log Make the limitation of query memory usage configurable Change the factor of the descending scan according to the improvement of descending scan performance in TiKV Weekly update in TiKV and PD Last week, we landed 28 PRs in the TiKV and PD repositories.Added Enable prevote in PD by default Process approximate rows in Region Fixed Fix the issue of escaping the xFF sequences to a single byte Improved Shrink the pending command queue in ApplyDelegate Output a log when GC finds too many versions for a single key Upgrade protobuf and grpcio Support initialization empty Region in tikv-ctl Adjust the pending peer filter New contributors (Thanks!) TiDB: chenyang8094 Angryrou TiKV: kbacha maninalift "}, {"url": "https://pingcap.com/blog-cn/10-questions-tidb-structure/", "title": "十问 TiDB :关于架构设计的一些思考", "content": " “我希望能够把 TiDB 的设计的一些理念能够更好的传达给大家,相信大家理解了背后原因后,就能够把 TiDB 用的更好。” 做 TiDB 的缘起是从思考一个问题开始的:为什么在数据库领域有这么多永远也躲不开的坑?从 2015 年我们写下第一行代码,3 年以来我们迎面遇到无数个问题,一边思考一边做,尽量用最小的代价来快速奔跑。作为一个开源项目,TiDB 是我们基础架构工程师和社区一起努力的结果,TiDB 已经发版到 2.0,有了一个比较稳定的形态,大量在生产环境使用的伙伴们。可以负责任的说,我们做的任何决定都经过了非常慎重的思考和实践,是经过内部和社区一起论证产生的结果。它未必是最好的,但是在这个阶段应该是最适合我们的,而且大家也可以看到 TiDB 在快速迭代进化。这篇文章是关于 TiDB 代表性“为什么”的 TOP 10,希望大家在了解了我们这些背后的选择之后,能更加纯熟的使用 TiDB,让它在适合的环境里更好的发挥价值。这个世界有很多人,感觉大于思想,疑问多于答案。感恩大家保持疑问,我们承诺回馈我们的思考过程,毕竟有时候很多思考也很有意思。一、为什么分布式系统并不是银弹 其实并没有什么技术是完美和包治百病的,在存储领域更是如此,如果你的数据能够在一个 MySQL 装下并且服务器的压力不大,或者对复杂查询性能要求不高,其实分布式数据库并不是一个特别好的选择。 选用分布式的架构就意味着引入额外的维护成本,而且这个成本对于特别小的业务来说是不太划算的,即使你说需要高可用的能力,那 MySQL 的主从复制 + GTID 的方案可能也基本够用,这不够的话,还有最近引入的 Group Replication。而且 MySQL 的社区足够庞大,你能 Google 找到几乎一切常见问题的答案。我们做 TiDB 的初衷并不是想要在小数据量下取代 MySQL,而是尝试去解决基于单机数据库解决不了的一些本质的问题。有很多朋友问我选择分布式数据库的一个比较合适的时机是什么?我觉得对于每个公司或者每个业务都不太一样,我并不希望一刀切的给个普适的标准(也可能这个标准并不存在),但是有一些事件开始出现的时候:比如是当你发现你的数据库已经到了你每天开始绞尽脑汁思考数据备份迁移扩容,开始隔三差五的想着优化存储空间和复杂的慢查询,或者你开始不自觉的调研数据库中间件方案时,或者人肉在代码里面做 sharding 的时候,这时给自己提个醒,看看 TiDB 是否能够帮助你,我相信大多数时候应该是可以的。而且另一方面,选择 TiDB 和选择 MySQL 并不是一刀切的有你没他的过程,我们为了能让 MySQL 的用户尽可能减小迁移和改造成本,做了大量的工具能让整个数据迁移和灰度上线变得平滑,甚至从 TiDB 无缝的迁移回来,而且有些小数据量的业务你仍然可以继续使用 MySQL。所以一开始如果你的业务和数据量还小,大胆放心的用 MySQL 吧,MySQL still rocks,TiDB 在未来等你。二、为什么是 MySQL 和上面提到的一样,并不是 MySQL 不好我们要取代他,而是选择兼容 MySQL 的生态对我们来说是最贴近用户实际场景的选择: MySQL 的社区足够大,有着特别良好的群众基础,作为一个新的数据库来说,如果需要用户去学习一套新的语法,同时伴随很重的业务迁移的话,是很不利于新项目冷启动的。 MySQL 那么长时间积累下来大量的测试用例和各种依赖 MySQL 的第三方框架和工具的测试用例是我们一个很重要的测试资源,特别是在早期,你如何证明你的数据库是对的,MySQL 的测试就是我们的一把尺子。 已经有大量的已有业务正在使用 MySQL,同时也遇到了扩展性的问题,如果放弃这部分有直接痛点的场景和用户,也是不明智的。 另一方面来看,MySQL 自从被 Oracle 收购后,不管是性能还是稳定性这几年都在稳步的提升,甚至在某些场景下,已经开始有替换 Oracle 的能力,从大的发展趋势上来说,是非常健康的,所以跟随着这个健康的社区一起成长,对我们来说也是一个商业上的策略。三、为什么 TiDB 的设计中 SQL 层和存储层是分开的 一个显而易见的原因是对运维的友好性。很多人觉得这个地方稍微有点反直觉,多一个组件不就会增加部署的复杂度吗?其实在实际生产环境中,运维并不仅仅包含部署。举个例子,如果在 SQL 层发现了一个 BUG 需要紧急的更新,如果所有部件都是耦合在一起的话,你面临的就是一次整个集群的滚动更新,如果分层得当的话,你可能需要的只是更新无状态的 SQL 层,反之亦然。另外一个更深层次的原因是成本。存储和 SQL 所依赖的计算资源是不一样的,存储会依赖 IO,而计算对 CPU 以及内存的要求会更高,无需配置 PCIe/NVMe/Optane 等磁盘,而且这两者是不一定对等的,如果全部耦合在一起的话,对于资源调度是不友好的。 对于 TiDB 来说,目标定位是支持 HTAP,即 OLTP 和 OLAP 需要在同一个系统内部完成。显然,不同的 workload 即使对于 SQL 层的物理资源需求也是不一样的,OLAP 请求更多的是吞吐偏好型以及长 query,部分请求会占用大量内存,而 OLTP 面向的是短平快的请求,优化的是延迟和 OPS (operation per second),在 TiDB 中 SQL 层是无状态的,所以你可以将不同的 workload 定向到不同的物理资源上做到隔离。还是那句话,对调度器友好,同时调度期的升级也不需要把整个集群全部升级一遍。另一方面,底层存储使用 KV 对数据进行抽象,是一个更加灵活的选择。一个好处是简单。对于 Scale-out 的需求,对 KV 键值对进行分片的难度远小于对带有复杂的表结构的结构化数据,另外,存储层抽象出来后也可以给计算带来新的选择,比如可以对接其他的计算引擎,和 TiDB SQL 层同时平行使用,TiSpark 就是一个很好的例子。从开发角度来说,这个拆分带来的灵活度还体现在可以选择不同的编程语言来开发。对于无状态的计算层来说,我们选择了 Go 这样开发效率极高的语言,而对于存储层项目 TiKV 来说,是更贴近系统底层,对于性能更加敏感,所以我们选择了 Rust,如果所有组件都耦合在一起很难进行这样的按需多语言的开发,对于开发团队而言,也可以实现专业的人干专业的事情,存储引擎的开发者和 SQL 优化器的开发者能够并行的开发。 另外对于分布式系统来说,所有的通信几乎都是 RPC,所以更明确的分层是一个很自然的而且代价不大的选择。四、为什么不复用 MySQL 的 SQL 层,而是选择自己重写 这点是我们和很多友商非常不一样的地方。 目前已有的很多方案,例如 Aurora 之类的,都是直接基于 MySQL 的源码,保留 SQL 层,下面替换存储引擎的方式实现扩展,这个方案有几个好处:一是 SQL 层代码直接复用,确实减轻了一开始的开发负担,二是面向用户这端确实能做到 100% 兼容 MySQL 应用。但是缺点也很明显,MySQL 已经是一个 20 多年的老项目,设计之初也没考虑分布式的场景,整个 SQL 层并不能很好的利用数据分布的特性生成更优的查询计划,虽然替换底层存储的方案使得存储层看上去能 Scale,但是计算层并没有,在一些比较复杂的 Query 上就能看出来。另外,如果需要真正能够大范围水平扩展的分布式事务,依靠 MySQL 原生的事务机制还是不够的。自己重写整个 SQL 层一开始看上去很困难,但其实只要想清楚,有很多在现代的应用里使用频度很小的语法,例如存储过程什么的,不去支持就好了,至少从 Parser 这层,工作量并不会很大。 同时优化器这边自己写的好处就是能够更好的与底层的存储配合,另外重写可以选择一些更现代的编程语言和工具,使得开发效率也更高,从长远来看,是个更加省事的选择。五、为什么用 RocksDB 和 Etcd Raft 很多工程师都有着一颗造轮子(玩具)的心,我们也是,但是做一个工业级的产品就完全不一样了,目前的环境下,做一个新的数据库,底层的存储数据结构能选的大概就两种:1. B+Tree, 2. LSM-Tree。但是对于 B+Tree 来说每个写入,都至少要写两次磁盘: 1. 在日志里; 2. 刷新脏页的时候,即使你的写可能就只改动了一个 Byte,这个 Byte 也会放大成一个页的写 (在 MySQL 里默认 InnoDB 的 Page size 是 16K),虽然说 LSM-Tree 也有写放大的问题,但是好处是 LSM-tree 将所有的随机写变成了顺序写(对应的 B+tree 在回刷脏页的时候可能页和页之间并不是连续的)。 另一方面,LSMTree 对压缩更友好,数据存储的格式相比 B+Tree 紧凑得多,Facebook 发表了一些关于 MyRocks 的文章对比在他们的 MySQL 从 InnoDB 切换成 MyRocks (Facebook 基于 RocksDB 的 MySQL 存储引擎)节省了很多的空间。所以 LSM-Tree 是我们的选择。选择 RocksDB 的出发点是 RocksDB 身后有个庞大且活跃的社区,同时 RocksDB 在 Facebook 已经有了大规模的应用,而且 RocksDB 的接口足够通用,并且相比原始的 LevelDB 暴露了很多参数可以进行针对性的调优。随着对于 RocksDB 理解和使用的不断深入,我们也已经成为 RocksDB 社区最大的使用者和贡献者之一,另外随着 RocksDB 的用户越来越多,这个项目也会变得越来越好,越来越稳定,可以看到在学术界很多基于 LSM-Tree 的改进都是基于 RocksDB 开发的,另外一些硬件厂商,特别是存储设备厂商很多会针对特定存储引擎进行优化,RocksDB 也是他们的首选之一。反过来,自己开发存储引擎的好处和问题同样明显,一是从开发到产品的周期会很长,而且要保证工业级的稳定性和质量不是一个简单的事情,需要投入大量的人力物力。好处是可以针对自己的 workload 进行定制的设计和优化,由于分布式系统天然的横向扩展性,单机有限的性能提升对比整个集群吞吐其实意义不大,把有限的精力投入到高可用和扩展性上是一个更加经济的选择。 另一方面,RocksDB 作为 LSM-Tree 其实现比工业级的 B+Tree 简单很多(参考对比 InnoDB),从易于掌握和维护方面来说,也是一个更好的选择。 当然,随着我们对存储的理解越来越深刻,发现很多专门针对数据库的优化在 RocksDB 上实现比较困难,这个时候就需要重新设计新的专门的引擎,就像 CPU 也能做图像处理,但远不如 GPU,而 GPU 做机器学习又不如专用的 TPU。选择 Etcd Raft 的理由也类似。先说说为什么是 Raft,在 TiDB 项目启动的时候,我们其实有过在 MultiPaxos 和 Raft 之间的纠结,后来结论是选择了 Raft。Raft 的算法整体实现起来更加工程化,从论文就能看出来,论文中甚至连 RPC 的结构都描述了出来,是一个对工业实现很友好的算法,而且当时工业界已经有一个经过大量用户考验的开源实现,就是 Etcd。而且 Etcd 更加吸引我们的地方是它对测试的态度,Etcd 将状态机的各个接口都抽象得很好,基本上可以做到与操作系统的 API 分离,极大降低了写单元测试的难度,同时设计了很多 hook 点能够做诸如错误注入等操作,看得出来设计者对于测试的重视程度。与其自己重新实现一个 Raft,不如借力社区,互相成长。现在我们也是 Etcd 社区的一个活跃的贡献者,一些重大的 Features 例如 Learner 等新特性,都是由我们设计和贡献给 Etcd 的,同时我们还在不断的为 Etcd 修复 Bug。没有完全复用 Etcd 的主要的原因是我们存储引擎的开发语言使用了 Rust,Etcd 是用 Go 写的,我们需要做的一个工作是将他们的 Raft 用 Rust 语言重写,为了完成这个事情,我们第一步是将 Etcd 的单元测试和集成测试先移植过来了(没错,这个也是选择 Etcd 的一个很重要的原因,有一个测试集作为参照),以免移植过程破坏了正确性。另外一方面,就如同前面所说,和 Etcd 不一样,TiKV 的 Raft 使用的是 Multi-Raft 的模型,同一个集群内会存在海量的互相独立 Raft 组,真正复杂的地方在如何安全和动态的分裂,移动及合并多个 Raft 组,我在我的 这篇文章 里面描述了这个过程。六、为什么有这样的硬件配置要求 我们其实对生产环境硬件的要求还是蛮高的,对于存储节点来说,SSD 或者 NVMe 或者 Optane 是刚需,另外对 CPU 及内存的使用要求也很高,同时对大规模的集群,网络也会有一些要求 (详见我们的官方文档推荐配置的 相关章节),其中一个很重要的原因是我们底层的选择了 RocksDB 的实现,对于 LSM Tree 来说因为存在写放大的天然特性,对磁盘吞吐需求会相应的更高,尤其是 RocksDB 还有类似并行 Compaction 等特性。 而且大多数机械磁盘的机器配置倾向于一台机器放更大容量的磁盘(相比 SSD),但是相应的内存却一般来说不会更大,例如 24T 的机械磁盘 + 64G 内存,磁盘存储的数据量看起来更大,但是大量的随机读会转化为磁盘的读,这时候,机械磁盘很容易出现 IO 瓶颈,另一方面,对于灾难恢复和数据迁移来说,也是不太友好的。另外,TiDB 的各个组件目前使用 gRPC 作为 RPC 框架,gRPC 是依赖 HTTP2 作为底层协议,相比很多朴素的 RPC 实现,会有一些额外的 CPU 开销。TiKV 内部使用 RocksDB 的方式会伴随大量的 Prefix Scan,这意味着大量的二分查找和字符串比较,这也是和很多传统的离线数据仓库很不一样的 Pattern,这个会是一个 CPU 密集型的操作。在 TiDB 的 SQL 层这端,SQL 是计算密集型的应用这个自然不用说,另外对内存也有一定的需求。由于 TiDB 的 SQL 是一个完整的 SQL 实现,表达力和众多中间件根本不是一个量级,有些算子,比如 Hashjoin,就是会在内存里开辟一块大内存来执行 Join,所以如果你的查询逻辑比较复杂,或者 Join 的一张子表比较大的情况下(偏 OLAP 实时分析业务),对内存的需求也是比较高的,我们并没有像单机数据库的优化器一样,比如 Order by 内存放不下,就退化到磁盘上,我们的哲学是尽可能的使用内存。 如果硬件资源不足,及时的通过拒绝执行和失败通知用户,因为有时候半死不活的系统反而更加可怕。另外一方面,还有很多用户使用 TiDB 的目的是用于替换线上 OLTP 业务,这类业务对于性能要求是比较高的。 一开始我们并没有在安装阶段严格检查用户的机器配置,结果很多用户在硬件明显没有匹配业务压力的情况下上线,可能一开始没什么问题,但是峰值压力一上来,可能就会造成故障,尽管 TiDB 和 TiKV 对这种情况做了层层的内部限流,但是很多情况也无济于事。 所以我们决定将配置检查作为部署脚本的强制检查,一是减少了很多沟通成本,二是可以让用户在上线时尽可能的减少后顾之忧。七、为什么用 Range-based 的分片策略,而不是 Hash-based Hash-based 的问题是实现有序的 Scan API 会比较困难,我们的目标是实现一个标准的关系型数据库,所以会有大量的顺序扫描的操作,比如 Table Scan,Index Scan 等。用 Hash 分片策略的一个问题就是,可能同一个表的数据是不连续的,一个顺序扫描即使几行都可能会跨越不同的机器,所以这个问题上没得选,只能是 Range 分片。 但是 Range 分片可能会造成一些问题,比如频繁读写小表问题以及单点顺序写入的问题。 在这里首先澄清一下,静态分片在我们这样的系统里面是不存在的,例如传统中间件方案那样简单的将数据分片和物理机一一对应的分片策略会造成: 动态添加节点后,需要考虑数据重新分布,这里必然需要做动态的数据迁移; 静态分片对于根据 workload 实时调度是不友好的,例如如果数据存在访问热点,系统需要能够快速进行数据迁移以便于将热点分散在不同的物理服务商上。 回到刚才提到的基于 Range 分片的问题,刚才我说过,对于顺序写入热点的问题确实存在,但也不是不可解。对于大压力的顺序写入的场景大多数是日志或者类似的场景,这类场景的典型特点是读写比悬殊(读 << 写),几乎没有 Update 和随机删除,针对这种场景,写入压力其实可以通过 Partition Table 解决,这个已经在 TiDB 的开发路线图里面,今年之内会和大家见面。另外还有一个频繁读写小表造成的热点问题。这个原因是,在底层,TiDB 的数据调度的最小单位是 Region,也就是一段段按字节序排序的键值 Key-Value Pairs (默认大小 96M),假设如果一个小表,总大小连 96M 都不到,访问还特别频繁,按照目前的机制,如果不强制的手动 Split,调度系统无论将这块数据调度到什么位置,新的位置都会出现热点,所以这个问题本质上是无解的。因此建议如果有类似的访问 pattern,尽可能的将通用的小表放到 Redis 之类的内存缓存中,或者甚至直接放在业务服务的内存里面(反正小)。八、为什么性能(延迟)不是唯一的评价标准 很多朋友问过我,TiDB 能替换 Redis 吗?大家对 Redis 和 TiDB 的喜爱之情我也很能理解,但是很遗憾,TiDB 并不是一个缓存服务,它支持跨行强一致事务,在非易失设备上实现持久化存储,而这些都是有代价的。简单来说,写磁盘的 IO 开销 (WAL,持久化),多副本高可用和保证分布式事务必然会牺牲延迟,更不用说做跨数据中心的同步了,在这点上,我认为如果需要很低延迟的响应速度(亚毫秒级)就需要在业务端做缓存了。TiDB 的定位是给业务提供一个可扩展的 The Source of Truth (真相之源),即使业务层的缓存失效,也有一个地方能够提供强一致的数据,而且业务不用关心容量问题。另一方面,衡量一个分布式系统更有意义的指标是吞吐,这个观点我在很多文章里已经提到过,提高并发度,如果系统的吞吐能够随着集群机器数量线性提升,而且延迟是稳定的才有意义,而且这样才能有无限的提升空间。 在实际的环境中,单个 TiDB 集群已经有一些用户使用到了百万级别的 QPS,这个在单机架构上是几乎不可能实现的。另外,这几年硬件的进步速度非常快,特别是 IO 相关的创新,比如 NVMe SSD 的普及,还有刚刚商用的持久化内存等新的存储介质。很多时候我们在软件层面上绞尽脑汁甚至牺牲代码的优雅换来一点点性能提升,很可能换块磁盘就能带来成倍的提升。我们公司内部有一句话:Make it right before making it fast。正确性和可靠性的位置是在性能之前的,毕竟在一个不稳定的系统上谈性能是没有意义的。九、为什么弹性伸缩能力如此重要 在业务初期,数据量不大,业务流量和压力不大的时候,基本随便什么数据库都能够搞定,但很多时候 …"}, {"url": "https://pingcap.com/blog-cn/tidb-source-code-reading-10/", "title": "TiDB 源码阅读系列文章(十)Chunk 和执行框架简介", "content": " 什么是 Chunk TiDB 2.0 中,我们引入了一个叫 Chunk 的数据结构用来在内存中存储内部数据,用于减小内存分配开销、降低内存占用以及实现内存使用量统计/控制,其特点如下: 只读 不支持随机写 只支持追加写 列存,同一列的数据连续的在内存中存放 Chunk 本质上是 Column 的集合,它负责连续的在内存中存储同一列的数据,接下来我们看看 Column 的实现。1. Column Column 的实现参考了 Apache Arrow,Column 的代码在 这里。根据所存储的数据类型,我们有两种 Column: 定长 Column:存储定长类型的数据,比如 Double、Bigint、Decimal 等 变长 Column:存储变长类型的数据,比如 Char、Varchar 等 哪些数据类型用定长 Column,哪些数据类型用变长 Column 可以看函数 addColumnByFieldType 。Column 里面的字段非常多,这里先简单介绍一下: length 用来表示这个 Column 有多少行数据。 nullCount 用来表示这个 Column 中有多少 NULL 数据。 nullBitmap 用来存储这个 Column 中每个元素是否是 NULL,需要特殊注意的是我们使用 0 表示 NULL,1 表示非 NULL,和 Apache Arrow 一样。 data 存储具体的数据,不管定长还是变长的 Column,所有的数据都存储在这个 byte slice 中。 offsets 给变长的 Column 使用,存储每个数据在 data 这个 slice 中的偏移量。 elemBuf 给定长的 Column 使用,当需要读或者写一个数据的时候,使用它来辅助 encode 和 decode。1.1 追加一个定长的非 NULL 值 追加一个元素需要根据具体的数据类型调用具体的 append 方法,比如: appendInt64、appendString 等。一个定长类型的 Column 可以用如下图表示:我们以 appendInt64 为例来看看如何追加一个定长类型的数据: 使用 unsafe.Pointer 把要 append 的数据先复制到 elemBuf 中; 将 elemBuf 中的数据 append 到 data 中; 往 nullBitmap 中 append 一个 1。 上面第 1 步在 appendInt64 这个函数中完成,第 2、3 步在 finishAppendFixed 这个函数中完成。其他定长类型元素的追加操作非常相似,感兴趣的同学可以接着看看 appendFloat32、appendTime 等函数。1.2 追加一个变长的非 NULL 值 而一个变长的 Column 可以用下图表示:我们以 appendString 为例来看看如何追加一个变长类型的数据: 把数据先 append 到 data 中; 往 nullBitmap 中 append 一个 1; 往 offsets 中 append 当前 data 的 size 作为下一个元素在 data 中的起始点。 上面第 1 步在 appendString 这个函数中完成,第 2、3 步在 finishAppendVar 这个函数中完成。其他变长类型元素的追加操作也是非常相似,感兴趣的同学可以接着看看 appendBytes、appendJSON 等函数。1.3 追加一个 NULL 值 我们使用 appendNull 函数来向一个 Column 中追加一个 NULL 值: 往 nullBitmap 中 append 一个 0; 如果是定长 Column,需要往 data 中 append 一个 elemBuf 长度的数据,用来占位; 如果是变长 Column,不用往 data中 append 数据,而是往 offsets 中 append 当前 data 的 size 作为下一个元素在 data 中的起始点。 2. Row 如上图所示:Chunk 中的 Row 是一个逻辑上的概念:Row 中的数据存储在 Chunk 的各个 Column 中,同一个 Row 中的数据在内存中没有连续存储在一起,我们在获取一个 Row 对象的时候也不需要进行数据拷贝。提供 Row 的概念是因为算子运行过程中,大多数情况都是以 Row 为单位访问和操作数据,比如聚合,排序等。 Row 提供了获取 Chunk 中数据的方法,比如 GetInt64、GetString、GetMyDecimal 等,前面介绍了往 Column 中 append 数据的方法,获取数据的方法可以由 append 数据的方法反推,代码也比较简单,这里就不再详细介绍了。3. 使用 目前 Chunk 这个包只对外暴露了 Chunk, Row 等接口,而没有暴露 Column,所以,写数据调用的是在 Chunk 上实现的对 Column 具体函数的 wrapper,比如 AppendInt64;读数据调用的是在 Row 上实现的 Getxxx 函数,比如 GetInt64。执行框架简介 1. 老执行框架简介 在重构前,TiDB 1.0 中使用的执行框架会不断调用 Child 的 Next 函数获取一个由 Datum 组成的 Row(和刚才介绍的 Chunk Row 是两个数据结构),这种执行方式的特点是:每次函数调用只返回一行数据,且不管是什么类型的数据都用 Datum 这个结构体来封装。这种方法的优点是:简单、易用。缺点是: 如果处理的数据量多,那么框架上的函数调用开销将会非常大; Datum 占用的无效内存太大,内存浪费比较多(存一个 8 字节的整数需要 56 字节); Datum 没有重用,golang 的 gc 压力大; 每个 Operator 一次只输出一行数据,要进行更加缓存友好的计算、更充分的利用 CPU 的 pipeline 非常困难; Datum 中的 interface 类型的数据,统计它的内存使用量比较困难。 2. 新执行框架简介 在重构后,TiDB 2.0 中使用的执行框架会不断调用 Child 的 NextChunk 函数,获取一个 Chunk 的数据。这种执行方式的特点是: 每次函数调用返回一批数据,数据量由一个叫 tidb_max_chunk_size 的 session 变量来控制,默认是 1024 行。因为 TiDB 是一个混合 TP 和 AP 的数据库,对于 AP 类型的查询来说,因为计算的数据量大,1024 没啥问题,但是对于 TP 请求来说,计算的数据量可能比较少,直接在一开始就分配 1024 行的内存并不是最佳的实践( 这里 有个 github issue 讨论这个问题,欢迎感兴趣的同学来讨论和解决)。 Child 把它产出的数据写入到 Parent 传下来的 Chunk 中。 这种执行方式的好处是: 减少了框架上的函数调用开销。比如同样输出 1024 行结果,现在的函数调用次数将会是以前的 1/1024。 内存使用更加高效。Chunk 中的数据组织非常紧凑,存一个 8 字节的整数几乎就只需要 8 字节,没有其他额外的内存开销了。 减轻了 golang 的 gc 压力。Chunk 占用的内存可以不断地重复利用,不用频繁的申请新内存,从而减轻了 golang 的 gc 压力。 查询的执行过程更加缓存友好。如我们之前所说,Chunk 按列来组织数据,在计算的过程中我们也尽量按列来计算,这样既能让一列的数据尽量长时间的待在 Cache 中,减轻 Cache Miss 率,也能充分利用起 CPU 的 pipeline。这一块在后续的源码分析文章中会有详细介绍,这里就不再展开了。 内存监控和控制更加方便。Chunk 中没有使用任何 interface,我们能很方便的直接获取一个 Chunk 当前所占用的内存的大小,具体可以看这个函数:MemoryUsage。关于 TiDB 内存控制,我们也会在后续文章中详细介绍,这里也不再展开了。 3. 新旧执行框架性能对比 采用了新的执行框架后,OLAP 类型语句的执行速度、内存使用效率都有极大提升,从 TPC-H 对比结果 看,性能有数量级的提升。"}, {"url": "https://pingcap.com/meetup/meetup-20180612-no69/", "title": "【Infra Meetup No.69】CASPaxos,一个有趣的 RSM 算法", "content": " 上周六,Infra Meetup 时隔一个月终于回归北京大本营,北京的朋友们格外热情,会议室最后都挤不下啦 ~现场有几位朋友拿着提前打印的论文认真地记笔记,分享结束后大家还围绕 CASPaxos 讨论了很久,瞬间有种“Paper Party”的感觉——看来 Infra Meetup 不定期的论文分享大大激发了社区小伙伴的“学术”之心啊!(不过,全场最大的亮点还是我司 CTO 的“魔性”PPT……)视频回顾 视频 | Infra Meetup No.69:CASPaxos,一个有趣的 RSM 算法配合 PPT 观看更佳~干货节选 本期 Meetup 我司 CTO 黄东旭分享了一篇有趣的论文——CASPaxos: Replicated State Machines without logs。他首先通过一个简单的例子通俗易懂地介绍了经典 Paxos 的算法。随后引入了 RSM(日志复制状态机)的概念 , 并指出 CASPaxos 其实是在经典 Paxos 的基础上进行了拓展,变成了没有日志的 RSM 。接着,他介绍了 CASPaxos 的主体算法,包括 membership change 算法以及用 CASPaxos 实现一个通用数据库时需要考虑的问题。来自大神的“魔性” PPT东旭接着对比了目前常用的 RSM 算法 ,比如 TiDB 中用到的 Raft 算法与 CASPaxos 的区别。相较而言,CASPaxos 目前是一个偏学术性的理论,在工业上应用的完整度和相关优化算法还不够。CASPaxos 的优点在于出现异常时的不可用时间非常短,并且没有额外的日志开销,缺陷是做数据丢失的故障恢复代价比较高,而且读依然是多数派读,对业务上的灵活性会有一些影响。P.S. 东旭还和现场的朋友们一起针对 CASPaxos 的缺点,大开脑洞,畅聊了一些可能的优化方法 。现场越聊越嗨,不得不说大家想法都很“清奇”啊 ( ´▽`) 。欢迎大家多来现场感受 Infra Meetup 的氛围哦~北京,我们下期再见! PingCAP Infra Meetup作为一个基础架构领域的前沿技术公司,PingCAP 希望能为国内真正关注技术本身的 Hackers 打造一个自由分享的平台。自 2016 年 3 月 5 日开始,我们定期在周六的上午举办 Infra Meetup,邀请业内大牛与大家深度探讨基础架构领域的前瞻性技术思考与经验。在这里,我们希望提供一个高水准的前沿技术讨论空间,让大家真正感受到自由的开源精神魅力。 "}, {"url": "https://pingcap.com/weekly/2018-06-11-tidb-weekly/", "title": "Weekly update (June 04 ~ June 10, 2018)", "content": " Weekly update in TiDB Last week, we landed 50 PRs in the TiDB repositories.Added Support ALTER TABLE RENAME KEY Support SHOW MASTER STATUS Support setting TSO into the tidb_snapshot session variable Support the ALTER TABLE DROP COLUMN CASCADE syntax Fixed Make TIDB_SMJ take effect when no index can be used Fix the SelectLock option for the UNION statement Fix a bug of the DROP USER statement Fix a bug of WrapWithCastAsJSON Detect the duplication of table alias for the JOIN statement Fix some bugs of the DECIMAL values Do not allow the YEAR type to have the UNSIGNED flag Refine row count estimation Fix a bug of failing to fetch the profile by pprof Fix the wrong result of the UNION statement Fix the wrong result of Merge Join Handle NULL datum when converting it to a string in statistics Fix the issue of checking LIMIT and ORDER BY in the UNION statement Improved Add max backoff settings for tikv-client Support parallel projection Make the error message of ADMIN CHECK TABLE more readable Improve the constant folding for the IF and IFNULL built-in functions Push the FLOOR built-in function to TiKV Push the built-in functions IS TRUE/IS FALSE to TiKV Append the current time into the error message when backoff occurs Refine the result of the EXPLAIN statement Weekly update in TiSpark Last week, we landed 2 PRs in the TiSpark repositories.Fixed Fix a test failure Weekly update in TiKV and PD Last week, we landed 20 PRs in the TiKV and PD repositories.Added Report the number of rows in the Region Fixed Fix a bug in do_sub Improved Increase metrics of sending and generating a snapshot Add ReadExecutor to execute the Get and Snap commands Upgrade etcd to master "}, {"url": "https://pingcap.com/blog/how_to_spin_up_an_htap_database_in_5_minutes_with_tidb_tispark/", "title": "How To Spin Up an HTAP Database in 5 Minutes with TiDB + TiSpark", "content": " TiDB is an open-source distributed Hybrid Transactional and Analytical Processing (HTAP) database built by PingCAP, powering companies to do real-time data analytics on live transactional data in the same data warehouse – minimize ETL, no more T+1, no more delays. More than 200 companies are now using TiDB in production. Its 2.0 version was launched in late April 2018 (read about it in this blog post).In this 5-minute tutorial, we will show you how to spin up a standard TiDB cluster using Docker Compose on your local computer, so you can get a taste of its hybrid power, before using it for work or your own project in production. A standard TiDB cluster includes TiDB (MySQL compatible stateless SQL layer), TiKV (a distributed transactional key-value store where the data is stored), and TiSpark (an Apache Spark plug-in that powers complex analytical queries within the TiDB ecosystem).Ready? Let’s get started!Setting Up Before we start deploying TiDB, we’ll need a few things first: wget, Git, Docker, and a MySQL client. If you don’t have them installed already, here are the instructions to get them. macOS Linux macOS Setting Up To install brew, go here. To install wget, use the command below in your Terminal:brew install wget --with-libressl To install Git, use the command below in your Terminal:brew install git Install Docker: https://www.docker.com/community-edition. Install a MySQL client:brew install mysql-client Linux Setting Up To install wget, Git, and MySQL, use the command below in your Terminal: For CentOS/Fedora:sudo yum install wget git mysql For Ubuntu/Debian:sudo apt install wget git mysql-client To install Docker, go here.After Docker is installed, use the following command to start it and add the current user to the Docker user group:sudo systemctl start docker # start docker daemo sudo usermod -aG docker $(whoami) # add the current user to the Docker user group, so you can run docker without sudo You need to log out and back in for this to take effect. Then use the following command to verify that Docker is running normally:docker info Spin up a TiDB cluster Now that Docker is set up, let’s deploy TiDB! Clone TiDB Docker Compose onto your laptop:git clone https://github.com/pingcap/tidb-docker-compose Optionally, you can use docker-compose pull to get the latest Docker images. Change your directory to tidb-docker-compose:cd tidb-docker-compose Deploy TiDB on your laptop:docker-compose up -d You can see messages in your terminal launching the default components of a TiDB cluster: 1 TiDB instance, 3 TiKV instances, 3 Placement Driver (PD) instances, Prometheus, Grafana, 2 TiSpark instances (one master, one slave), and a TiDB-Vision instance.Your terminal will show something like this:Congratulations! You have just deployed a TiDB cluster on your laptop!To check if your deployment is successful: Go to: http://localhost:3000 to launch Grafana with default user/password: admin/admin. Go to Home and click on the pull down menu to see dashboards of different TiDB components: TiDB, TiKV, PD, entire cluster. You will see a dashboard full of panels and stats on your current TiDB cluster. Feel free to play around in Grafana, e.g. TiDB-Cluster-TiKV, or TiDB-Cluster-PD. Grafana display of TiKV metrics Now go to TiDB-vision at http://localhost:8010 (TiDB-vision is a cluster visualization tool to see data transfer and load-balancing inside your cluster). You can see a ring of 3 TiKV nodes. TiKV applies the Raft consensus protocol to provide strong consistency and high availability. Light grey blocks are empty spaces, dark grey blocks are Raft followers, and dark green blocks are Raft leaders. If you see flashing green bands, that represent communications between TiKV nodes. It looks something like this: TiDB-vision Test TiDB compatibility with MySQL As we mentioned, TiDB is MySQL compatible. You can use TiDB as MySQL slaves with instant horizontal scalability. That’s how many innovative tech companies, like Mobike, use TiDB.To test out this MySQL compatibility: Keep the tidb-docker-compose running, and launch a new Terminal tab or window. Add MySQL to the path (if you haven’t already):export PATH=${PATH}:/usr/local/mysql/bin Launch a MySQL client that connects to TiDB:mysql -h 127.0.0.1 -P 4000 -u root Result: You will see the following message, which shows that TiDB is indeed connected to your MySQL instance: Note: TiDB version number may be different. Server version: 5.7.10-TiDB-v2.0.0-rc.4-31 The Compatibility of TiDB with MySQL Let’s get some data! Now we will grab some sample data that we can play around with. Open a new Terminal tab or window and download the tispark-sample-data.tar.gz file.wget http://download.pingcap.org/tispark-sample-data.tar.gz Unzip the sample file:tar zxvf tispark-sample-data.tar.gz Inject the sample test data from sample data folder to MySQL:mysql --local-infile=1 -u root -h 127.0.0.1 -P 4000 < tispark-sample-data/dss.ddl This will take a few seconds. Go back to your MySQL client window or tab, and see what’s in there:SHOW DATABASES; Result: You can see the TPCH_001 database on the list. That’s the sample data we just ported over.Now let’s go into TPCH_001:USE TPCH_001; SHOW TABLES; Result: You can see all the tables in TPCH_001, like NATION, ORDERS, etc. Let’s see what’s in the NATION table:SELECT * FROM NATION; Result: You’ll see a list of countries with some keys and comments.Launch TiSpark Now let’s launch TiSpark, the last missing piece of our hybrid database puzzle. In the same window where you downloaded TiSpark sample data (or open a new tab), go back to the tidb-docker-compose directory. Launch Spark within TiDB with the following command:docker-compose exec tispark-master /opt/spark-2.1.1-bin-hadoop2.7/bin/spark-shell This will take a few minutes. Result: Now you can Spark! Use the following three commands, one by one, to bind TiSpark to this Spark instance and map to the database TPCH_001, the same sample data that’s available in our MySQL instance:import org.apache.spark.sql.TiContext val ti = new TiContext(spark) ti.tidbMapDatabase("TPCH_001") It looks something like this: Now, let’s see what’s in the NATION table (should be the same as what we saw on our MySQL client):spark.sql("select * from nation").show(30); Result: Let’s get hybrid! Now, let’s go back to the MySQL tab or window, make some changes to our tables, and see if the changes show up on the TiSpark side. In the MySQL client, try this UPDATE:UPDATE NATION SET N_NATIONKEY=444 WHERE N_NAME="CANADA"; SELECT * FROM NATION; Then see if the update worked:SELECT * FROM NATION; Now go to the TiSpark Terminal window, and see if you can see the same update:spark.sql("select * from nation").show(30); Result: The UPDATE you made on the MySQL side shows up immediately in TiSpark! You can see that both the MySQL and TiSpark clients return the same results – fresh data for you to do analytics on right away. Voila!Summary With this simple deployment of TiDB on your local machine, you now have a functioning Hybrid Transactional and Analytical processing (HTAP) database. You can continue to make changes to the data in your MySQL client (simulating transactional workloads) and analyze the data with those changes in TiSpark (simulating real-time analytics).Of course, launching TiDB on your local machine is purely for experimental purposes. If you are interested in trying out TiDB for your production environment, send us a note: info@pingcap.com or reach out on our website. We’d be happy to help you!"}, {"url": "https://pingcap.com/blog-cn/tidb-source-code-reading-9/", "title": "TiDB 源码阅读系列文章(九)Hash Join", "content": " 什么是 Hash Join Hash Join 的基本定义可以参考维基百科:Hash join。简单来说,A 表和 B 表的 Hash Join 需要我们选择一个 Inner 表来构造哈希表,然后对 Outer 表的每一行数据都去这个哈希表中查找是否有匹配的数据。我们不用 “小表” 和 “大表” 这两个术语是因为:对于类似 Left Outer Join 这种 Outer Join 来说,如果我们使用 Hash Join,不管 Left 表相对于 Right 表而言是大表还是小表,我们都只能使用 Right 表充当 Inner 表并在之上建哈希表,使用 Left 表来当 Outer 表,也就是我们的驱动表。使用 Inner 和 Outer 更准确,没有迷惑性。在 Build 阶段,对 Inner 表建哈希表,在 Probe 阶段,对由 Outer 表驱动执行 Join 过程。TiDB Hash Join 实现 TiDB 的 Hash Join 是一个多线程版本的实现,主要任务有: Main Thread,一个,执行下列任务: 读取所有的 Inner 表数据; 根据 Inner 表数据构造哈希表; 启动 Outer Fetcher 和 Join Worker 开始后台工作,生成 Join 结果,各个 goroutine 的启动过程由 fetchOuterAndProbeHashTable 这个函数完成; 将 Join Worker 计算出的 Join 结果返回给 NextChunk 接口的调用方法。 Outer Fetcher,一个,负责读取 Outer 表的数据并分发给各个 Join Worker; Join Worker,多个,负责查哈希表、Join 匹配的 Inner 和 Outer 表的数据,并把结果传递给 Main Thread。 接下来我们细致的介绍 Hash Join 的各个阶段。Main Thread 读 Inner 表数据 读 Inner 表数据的过程由 fetchInnerRows 这个函数完成。这个过程会不断调用 Child 的 NextChunk 接口,把每次函数调用所获取的 Chunk 存储到 innerResult 这个 List 中供接下来的计算使用。Main Thread 构造哈希表 构造哈希表的过程由 buildHashTableForList 这个函数完成。我们这里使用的哈希表(存储在变量 hashTable 中)本质上是一个 MVMap。MVMap 的 Key 和 Value 都是 []byte 类型的数据,和普通 map 不同的是,MVMap 允许一个 Key 拥有多个 Value。这个特性对于 Hash Join 来说非常方便和实用,因为表中同一个 Join Key 可能对应多行数据。构造哈希表的过程中,我们会遍历 Inner 表的每行数据(上文提到,此时所有的数据都已经存储在了 innerResult 中),对每行数据做如下操作: 计算该行数据的 Join Key,得到一个 []byte,它将作为 MVMap 的 Key; 计算该行数据的位置信息,得到另一个 []byte,它将作为 MVMap 的 Value; 将这个 (Key, Value) 放入 MVMap 中。 Outer Fetcher Outer Fetcher 是一个后台 goroutine,他的主要计算逻辑在 fetchOuterChunks 这个函数中。它会不断的读大表的数据,并将获得的 Outer 表的数据分发给各个 Join Worker。这里多线程之间的资源交互可以用下图表示:上图中涉及到了两个 channel: outerResultChs[i]:每个 Join Worker 一个,Outer Fetcher 将获取到的 Outer Chunk 写入到这个 channel 中供相应的 Join Worker 使用; outerChkResourceCh:当 Join Worker 用完了当前的 Outer Chunk 后,它需要把这个 Chunk 以及自己对应的 outerResultChs[i] 的地址一起写入到 outerChkResourceCh 这个 channel 中,告诉 Outer Fetcher 两个信息: 我提供了一个 Chunk 给你,你直接用这个 Chunk 去拉 Outer 数据吧,不用再重新申请内存了; 我的 Outer Chunk 已经用完了,你需要把拉取到的 Outer 数据直接传给我,不要给别人了。 所以,整体上 Outer Fetcher 的计算逻辑是: 从 outerChkResourceCh 中获取一个 outerChkResource,存储在变量 outerResource 中; 从 Child 拉取数据,将数据写入到 outerResource 的 chk 字段中; 将这个 chk 发给需要 Outer 表的数据的 Join Worker 的 outerResultChs[i] 中去,这个信息记录在了 outerResource 的 dest 字段中。 Join Worker 每个 Join Worker 都是一个后台 goroutine,主要计算逻辑在 runJoinWorker4Chunk 这个函数中。Join Worker 的数量由 tidb_hash_join_concurrency 这个 session 变量来控制,默认是 5 个。上图中涉及到两个 channel: joinChkResourceCh[i]:每个 Join Worker 一个,用来存 Join 的结果; joinResultCh:Join Worker 将 Join 的结果 Chunk 以及它的 joinChkResourceCh 地址写入到这个 channel 中,告诉 Main Thread 两件事: 我计算出了一个 Join 的结果 Chunk 给你,你读到这个数据后可以直接返回给你 Next 函数的调用方; 你用完这个 Chunk 后赶紧还给我,不要给别人,我好继续干活。 所以,整体上 Join Worker 的计算逻辑是: 获取一个 Outer Chunk; 获取一个 Join Chunk Resource; 查哈希表,将匹配的 Outer Row 和 Inner Rows 写到 Join Chunk 中; 将写满了的 Join Chunk 发送给 Main Thread。 Main Thread 主线程的计算逻辑由 NextChunk 这个函数完成。主线程的计算逻辑非常简单: 从 joinResultCh 中获取一个 Join Chunk; 将调用方传下来的 chk 和 Join Chunk 中的数据交换; 把 Join Chunk 还给对应的 Join Worker。 Hash Join FAQ 如何确定 Inner 和 Outer 表? Left Outer Join:左表是 Outer 表,右表是 Inner 表; Right Outer Join:跟 Left Outer Join 相反,右表是 Outer 表,左表是 Inner 表; Inner Join:优化器估算出的较大表是 Outer 表,较小的表是 Inner 表; Semi Join、Anti Semi Join、Left Outer Semi Join 或 Anti Left Outer Semi Join:左表是 Outer 表,右表是 Inner 表。 Join Key 中 NULL 值的问题 NULL 和 NULL 不等,所以: 在用 Inner 表建 NULL 值的时候会忽略掉 Join Key 中有 NULL 的数据(代码在 这里); 当 Outer 表中某行数据的 Join Key 中有 NULL 值的时候我们不会去查哈希表(代码在 这里)。 Join 中的 4 种 Filter Inner 表上的 Filter:这种 Filter 目前被优化器推到了 Hash Join Inner 表上面,在 Hash Join 实现的过程中不用考虑这种 Filter 了。推下去的原因是能够尽早的在 coprocessor 上就把不能匹配到的 Inner 表数据给过滤掉,给上层计算减压。 Outer 表上的 Filter:这种 Filter 的计算目前在 join2Chunk 中,由 Join Worker 进行。当 Join Worker 拿到一个 Outer Chunk 以后需要先计算 Outer Filter,如果通过了 Outer Filter 再去查哈希表。 两个表上的等值条件:这就是我们说的 Join Key。比如 A 表和 B 表的等值条件是:A.col1=B.col2 and A.col3=B.col4,那么 A 表和 B 表上的 Join Key 分别是 (col1, col3) 和 (col2, col4)。 两个表上的非等值条件:这种 Filter 需要在 Join 的结果集上计算,如果能够过这个 Filter 才认为两行数据能够匹配。这个 Filter 的计算过程交给了 joinResultGenerator。 Join 方式的实现 目前 TiDB 支持的 Join 方式有 7 种,我们使用 joinResultGenerator 这个接口来定义两行数据的 Join 方式,实现一种具体的 Join 方式需要特殊的去实现 joinResultGenerator 这个接口,目前有 7 种实现: semiJoinResultGenerator:实现了 Semi Join 的链接方式,当一个 Outer Row 和至少一个 Inner Row 匹配时,输出这个 Outer Row。 antiSemiJoinResultGenerator:实现了 Anti Semi Join 的链接方式,当 Outer Row 和所有的 Inner Row 都不能匹配时才输出这个 Outer Row。 leftOuterSemiJoinResultGenerator:实现了 Left Outer Semi Join 的链接方式,Join 的结果是 Outer Row + 一个布尔值,如果该 Outer Row 能和至少一个 Inner Row 匹配,则输出该 Outer Row + True,否则输出 Outer Row + False。 antiLeftOuterSemiJoinResultGenerator:实现了 Anti Left Outer Semi Join 的链接方式,Join 的结果也是 Outer Row + 一个布尔值,不同的是,如果该 Outer Row 不能和任何 Inner Row 匹配上,则输出 Outer Row + True,否则输出 Outer Row + False。 leftOuterJoinResultGenerator:实现了 Left Outer Join 的链接方式,如果 Outer Row 不能和任何 Inner Row 匹配,则输出 Outer Row + NULL 填充的 Inner Row,否则输出每个匹配的 Outer Row + Inner Row。 rightOuterJoinResultGenerator:实现了 Right Outer Join 的链接方式,如果 Outer Row 不能和 Inner Row 匹配,则输出 NULL 填充的 Inner Row + Outer Row,否则输出每个匹配的 Inner Row + Outer Row。 innerJoinResultGenerator:实现了 Inner Join 的链接方式,如果 Outer Row 不能和 Inner Row 匹配,不输出任何数据,否则根据 Outer Row 是左表还是右表选择性的输出每个匹配的 Inner Row + Outer Row 或者 Outer Row + Inner Row。 "}, {"url": "https://pingcap.com/weekly/2018-06-04-tidb-weekly/", "title": "Weekly update (May 28 ~ June 03, 2018)", "content": " Weekly update in TiDB Last week, we landed 50 PRs in the TiDB repositories.Added Support the Trace syntax Support the TIDB_IS_DDL_OWNER builtin function Support ALL for builtin aggregate function BIT_AND/BIT_OR/BIT_XOR Fixed Check the correctness of decimal’s exponent part Fix the affected row count for the UPDATE statement Fix the range construction for the IN builtin function Fix the empty result of the JOIN statement Fix row count estimation for the LIMIT operator Fix the error message of the DIV builtin function Check the schema name of the column for the CREATE TABLE statement Fix the side effect of casting one decimal to another decimal Improved Push ABS to TiKV Wait for a while when some errors occurred to avoid retrying the DDL job too many times Unify the log format of the connection ID Ignore foreign keys in the SHOW CREATE TABLE statement Change statistics delta update duration to 1 minute Check invalid tasks after physical optimization Unify the DDL logs Weekly update in TiSpark Last week, we landed 2 PRs in the TiSpark repositories.Fixed Fix the ScanIterator logic where the index may be out of bound Improved Update gRPC version to 1.12.0 Weekly update in TiKV and PD Last week, we landed 20 PRs in the TiKV and PD repositories.Added Encode and decode for arrow chunk Fixed Report an error instead of getting a result if the divisor/dividend is 0 in do_div_mod Fix the bug that the Learner flag mistakenly reports to PD Improved Remove NumberDecoder trait from codec Use the average Region size to check if stores need balance Check the Region epoch before adding operators New contributors (Thanks!) TiDB: 谷月轩 bb7133 TiKV: bb7133 "}, {"url": "https://pingcap.com/meetup/meetup-20180531-no68/", "title": "【Infra Meetup No.68】虚怀迎远客 魔都 Talk 「长」", "content": " 距离去年在上海举办的 TechDay 已经过去了近一年,上海社区小伙伴们积攒已久的热情终于在上周六的 Infra Meetup 现场释放了出来~ 现场爆满不说,Q&A 环节大家都抢着与讲师互动,结束后还有小伙伴意犹未尽,强烈要求多在上海举办这样的技术交流趴(我们会努力的,嗯💪)。以下是现场视频&文字回顾,enjoy! 现场同学坐定之后,我司 CTO 黄东旭简短开场,欢迎 Percona CEO Peter Zaitsev 做客 Infra Meetup No.68 上海站~随后 Peter 带来了 Using MySQL for Distributed Database Architectures 的主题演讲。Using MySQL for Distributed Database Architectures Percona CEO Peter Zaitsev视频链接:1st Talk by Peter ZaitsevPeter 首先介绍了 MySQL 最近几个版本迭代的性能升级数据。他认为 MySQL 单机性能提升很大,但是与分布式数据库在应用场景上仍有较大的区别,很多问题是单机解决不了的。从而引出了基于 MySQL 做分布式尝试的方法论,并从高可用、扩展性、数据分布策略几个方面进行了详细解读。随后分享了在 MySQL 上实现分布式计算和分布式系统的方法。Peter 提到不同业务对数据库的需求不一样,对隔离级别和一致性的要求也不一样, 需要仔细思考相关配置。他重点介绍了 Percona 数据库管理工具和集群方案,同时分享了对市面上常见的基于 MySQL 分片的中间件的看法,以及对 TiDB 等 NewSQL 未来发展的期待。How to build a Self-Driving database PingCAP CTO 黄东旭视频链接:2nd Talk by Ed Huang智能化和自动化运维是当今数据库界的大趋势。在本次分享中,我司 CTO 黄东旭首先介绍了人工智能技术在数据库中可能的应用方向,以及在 TiDB 中的落地情况(包括 SQL 优化器的优化模型、 智能的数据调度、自动监控和运维系统等),最后展望了一下未来 TiDB 的技术 Roadmap。(我司 CTO 被上海朋友们的热情所感染,非常激动滴…讲超时了,所以现场有些同学没有机会提问,非常遗憾。下次我们一定留足时间给大家好好交流~)社区闪电 Talk 视频链接:Community Lightning Talk * 4除了 Peter 和东旭带来的精彩分享,上海社区伙伴还用心准备了四个闪电 Talk,分享自己的 TiDB 实践经验。不知道大家听完之后有没有激发出更多的 TiDB 实践想法和方向呢?TiDB 在金融聚合支付业务的实践 Ping++ DBA 宋涛介绍了过去调研的阿里云上的一些数仓方案,比如 ODPS 和 ADS 以及相关的优势和痛点,以及为何 Ping++ 最终选择 TiDB 作为实时数仓方案的原因。最后还分享了他们在云上基于 Docker 运维 TiDB 的一套方案以及相关运维经验。Ping++ DBA 宋涛TiDB 在易果生鲜数据中台的应用 易果生鲜大数据架构师罗瑞星介绍了易果生鲜的实时数仓的业务特点,分享了使用 SQLServer 和存储过程遇到的痛点(替换成 TiDB + TiSpark 的方案后,实时性和可运维性得到了大幅提升)。易果生鲜 大数据架构师 罗瑞星沪江数据库转型之路 沪江数据库负责人胡钉钉介绍了之前从 SQL server 转型 MySQL 的原因,以及过去 MySQL 和分库分表的方案的一些痛点(包括扩展性、DDL、主从同步延迟等问题),重点分享了 TiDB 的核心特点以及沪江在一些核心系统用 TiDB 替换 MySQL 的一些经验。沪江 数据库负责人 胡钉钉上海电信微信营业厅 TiDB 实践 上海电信微信营业厅项目技术负责人闫志学介绍了上海电信微信营业厅的业务,以及从 MyCAT 迁移到 TiDB 的一些经验和上线后的效果。上海电信微信营业厅项目技术负责人 闫志学这次 Infra Meetup 让我们感受到了上海的朋友们“爆棚”的热情,下次可能要定一个更大的场地啦哈哈~~偷偷滴说,下期 Infra Meetup 将回归北京,北京的老朋友们咱们下期见! ~ PingCAP Infra Meetup作为一个基础架构领域的前沿技术公司,PingCAP 希望能为国内真正关注技术本身的 Hackers 打造一个自由分享的平台。自 2016 年 3 月 5 日开始,我们定期在周六的上午举办 Infra Meetup,邀请业内大牛与大家深度探讨基础架构领域的前瞻性技术思考与经验。在这里,我们希望提供一个高水准的前沿技术讨论空间,让大家真正感受到自由的开源精神魅力。 "}, {"url": "https://pingcap.com/weekly/2018-05-28-tidb-weekly/", "title": "Weekly update (May 21 ~ May 27, 2018)", "content": " Weekly update in TiDB Last week, we landed 44 PRs in the TiDB repositories.Added Make tidb_max_chunk_size a global variable Add a timeout for writing binlogs Support high_priority for DELETE/UPDATE/REPLACE INTO statements Support changing the log level online Support ComChangeUser Support JOIN hint for UPDATE/DELETE statements Fixed Fix the compatibility problem of ON UPDATE CURRENT_TIMESTAMP Fix a bug of ON DUPLICATE KEY UPDATE Fix the decimal fraction of DIV Fix count estimation of betweenRowCount Fix the wrong result of CEIL(DECIMAL) Fix the wrong result of CEIL(INT) integer Fix the cost estimation of Index Scan and Table Scan Fix a bug of deleting an index in YEAR type Fix the wrong result of FLOOR Fix the false alarm of ADMIN CHECK TABLE Fix a panic of MAX/MIN Fix a bug in rebuildRange when the plan cache for the PREPARE statement is enabled Improved Create a new backoff for each Region Do not log the Write error during handshake Refine the log level of stats Set the rollback log to the debug level Refine the comparison between the timestamp column and the string constant Push CEIL down to TiKV Weekly update in TiSpark Last week, we landed 2 PRs in the TiSpark repositories.Fixed Fix incorrect histogram totalRowCount Improved Improve the tidbMapTable logic Weekly update in TiKV and PD Last week, we landed 20 PRs in the TiKV and PD repositories.Added Encode and decode for arrow chunk Fixed Implement GC on the stale learner automatically Allow Snapshot to remove only the temporary files created by itself Fix the panic issue when collecting hot-cache metrics Improved Remove the Read trait from the decoding function of bytes Remove the Read trait from the decoding function of decimals Remove the Read trait from the decoding function of JSON New contributors (Thanks!) PD: goerzh shilicqupt "}, {"url": "https://pingcap.com/blog/implement-raft-in-rust/", "title": "Implement Raft in Rust", "content": " Consensus is one of the most important challenges in designing and building distributed systems–how to make sure multiple nodes (or agents, processes, threads, tasks, participants, etc.) in a group agree on a specific value proposed by at least one of the nodes. As an open-source distributed scalable HTAP database, TiDB uses the Raft Consensus Algorithm in its distributed transactional key-value storage engine, TiKV, to ensure data consistency, auto-failover, and fault tolerance. TiDB has thus far been used by more than 200 companies in their production environments in a wide range of industries, from e-commerce and food delivery, to fintech, media, gaming, and travel.Ever since the Raft Consensus Algorithm was created by Diego Ongaro and John Ousterhout, it has gained wide popularity in many organizations, who are using it to develop consistent distributed services with high availability. For example, CoreOS uses it to build etcd, a popular key-value store which helps users save critical data. HashiCorp uses it to build Consul, which helps make service discovery and configuration easy.When we began to build TiKV, we researched and investigated many Raft implementations. We eventually decided to go with etcd’s Raft implementation and built our own Raft using Rust, a systems programming language that runs blazing fast, prevents segfaults, and guarantees thread safety. Although etcd’s Raft implementation is written in Go, it has a simple API with no specific Go feature, thus can be easily ported to Rust.Since TiKV was open sourced on April 1, 2016, its Raft module has been running stably in many companies’ production environment. So we decided to abstract the Raft module away as an independent library and released it as a crate, raft-rs, to help the Rust community create their own consistent services using this easy to understand consensus algorithm. In the following sections, I will introduce what is raft-rs and how to use it.Design In this post, I won’t cover the ins-and-outs of the Raft algorithm in detail, since there are many good resources that already cover that topic. Before we dive into raft-rs, let’s walk through its design first.As you probably already know, Raft replicates the state machine through logs. If we can ensure all the machines have the same sequence of logs, after applying all logs in order, the state machine will reach a consistent state.A complete Raft model contains 4 essential parts: Consensus Module, the core consensus algorithm module; Log, the place to keep the Raft logs; State Machine, the place to save the user data; Transport, the network layer for communication. Our raft-rs implementation includes the core Consensus Module only, not the other parts. The core Consensus Module in raft-rs is customizable, flexible, and resilient. You can directly use raft-rs, but you will need to build your own Log, State Machine and Transport components.How to use raft-rs In this section, I will show you how to use raft-rs. Please note that we will only cover the Raft Log as it pertains to the Consensus Module, not how to apply the Log to the State Machine or Transport the messages from one node to another.Step 1: Create the Raft node You can use RawNode::new() to create the Raft node. To create the Raft node, you need to build a Log component, which is called Raft Storage in raft-rs, and then configure the Raft node.1. Build Raft StorageRaft Storage saves all the information about the current Raft implementation, including Raft Log, commit index, the leader to vote for, etc.Storage is a trait defined in storage.rs. Here is the trait interface in detail: initial_state is called when Raft is initialized. This interface will return a RaftState which contains HardState and ConfState; HardState contains the last meta information including commit index, the vote leader, and the vote term; ConfState records the current node IDs like [1, 2, 3] in the cluster. Every Raft node must have a unique ID in the cluster; entries returns the Log entries in an interval [low, high); term returns the term of the entry at Log index; first_index and last_index return the first and last index of the Log; These interfaces are straightforward to understand and implement, but you should pay attention to what is returned when there is no Log but needs to get the term at index first_index() - 1. To solve this, we usually use a dummy Log entry to keep the last truncated Log entry. The last interface is snapshot, which returns a Snapshot of the current state machine. We will send this Snapshot data to another node. 2. Configure the Raft nodeAfter we create the Raft Storage, the next step is to use RawNode::new() to create the Raft node. The new function needs a Raft Storage and a configuration. There are some important fields for this configuration: id: the unique ID of the node in the cluster, which must be unique; election_tick: how many ticks the follower re-campaigns if it doesn’t receive any message from the leader; heartbeat_tick: how many ticks the leader sends the heartbeat to the followers to keep alive; applied: the last applied index for the state machine. Raft will resume applying Log entries to the state machine from this index; max_size_per_msg: Raft can send many Log entries at the same time, so we need to limit the maximum size of the sending message. This is an optimization for Transport in batch; max_inflight_msgs: how many messages the leader can send to the followers without acknowledgement. This is an optimization for the Transport in pipeline. election_tick must be larger than heartbeat_tick. If our tick interval is 100 ms, we can use 10 for election_tick and 3 for heartbeat_tick, which means the leader will send heartbeat to the followers every 300 ms and the follower will re-campaign without receiving any messages after 1 second. The read_only_option enables you to choose the linearizability mode or the lease mode to read data. If you don’t care about the read consistency and want a higher read performance, you can use the lease mode. Other important fields like check_quorum and pre_vote are used to avoid the disturbance and make the cluster more stable. I will explain them in detail in another article later.Step 2: Drive and Run the Raft node Now that you have created a Raft node, the next step is to drive and run the Raft node. There three steps to this process: You need a timer to run the Raft node regularly. See the following example for using Rust channel recv_timeout:let mut t = Instant::now(); let mut timeout = Duration::from_millis(100); loop { match receiver.recv_timeout(timeout) { Ok(...) => (), Err(RecvTimeoutError::Timeout) => (), Err(RecvTimeoutError::Disconnected) => return, } let d = t.elaspsed(); if d >= timeout { t = Instant::now(); timeout = Duration::from_millis(100); // We drive Raft every 100ms. r.tick(); } else { timeout -= d; } } As is shown in the above example, the Raft node is driven to run every 100 ms set by the tick function. Use the propose function to drive the Raft node when the client sends a request to the Raft server. You can call propose to add the request to the Raft log explicitly.In most cases, the client needs to wait for a response for the request. For example, if the client writes a value to a key and wants to know whether the write succeeds or not, but the write flow is asynchronous in Raft, so the write log entry must be replicated to other followers, then committed and at last applied to the state machine, so here we need a way to notify the client after the write is finished.One simple way is to use a unique ID for the client request, and save the associated callback function in a hash map. When the log entry is applied, we can get the ID from the decoded entry, call the corresponding callback, and notify the client. You can call the step function when you receive the Raft messages from other nodes.Here is a simple example to use propose and step:let mut cbs = …"}, {"url": "https://pingcap.com/weekly/2018-05-21-tidb-weekly/", "title": "Weekly update (May 14 ~ May 20, 2018)", "content": " Weekly update in TiDB Last week, we landed 40 PRs in the TiDB repositories.Added Support TIME and TIMESTAMP binary types for the PREPARE/EXECUTE statements Make tidb_build_stats_concurrency a global variable Support USE INDEX in the DELETE FROM statement Fixed Fix the compatibility problem of the UNION statement Fix range calculation of Index Scan when Prepared Plan Cache is enabled Check the AUTO_INCREMENT column for the SHARD_ROW_ID_BITS statement Set PB code for builtinArithmeticDivideDecimalSig Improved Refine the error message about Invalid default value Make the error log for WriteConflict more friendly Add the schema version to the log Support warnings when using Coprocessor streaming Add the DDL Callback log Do not log handshake error Log slow processing and waiting Coprocessor tasks separately with different labels Do not bind graceful shutdown to SIGTERM Weekly update in TiSpark Last week, we landed 4 PRs in the TiSpark repositories.Fixed Fix the DateTime parse error when DateTime is in DST gap Fix the count(1) function used with the limit clause Improved Make the tidbMapTable method return the corresponding DataFrame Improve the query plan test Weekly update in TiKV and PD Last week, we landed 35 PRs in the TiKV and PD repositories.Added Use slog via the slog_stdlog crate Support compression in the gRPC layer Fixed Fix the issue that split might cause dirty read in extreme conditions Correct the default value of the read thread pool configuration Fix load Region failure due to too large packet size Fix the issue that Learner cannot be successfully elected in special conditions Improved Speed up decoding datum and table Speed up Deleting Range Update the gRPC version Make Label scheduler take care of unhealthy Regions Adjust timeout time for the operator which only contains TransferLeader Filter disconnected stores for leader transfer "}, {"url": "https://pingcap.com/weekly/2018-05-14-tidb-weekly/", "title": "Weekly update (May 07 ~ May 13, 2018)", "content": " Weekly update in TiDB Last week, we landed 55 PRs in the TiDB repositories.Added Support renaming a table as its original name Allow correlated columns to be pushed down to TiKV Support local latches for the transactions in TiDB Add an option to stop writing Binlog when TiDB meets some Binlog errors Add an HTTP API to enable or disable the general log of TiDB Update the logrus package to a new version Fixed Set lastInsertID in the duplicated update statement Fix several bugs of statistics feedback Fix a bug occurred when values are inserted into a time column Fix a bug when creating a table and renaming a table run concurrently Rollback all keys when Prewrite fails Fix a bug when adding index meets handle = MaxInt64 Fix a bug when the limit offset is a multiple of MaxChunkSize Fix a bug when a complex subquery exists in the Update statement Improved Refine the error message about Out of range value for column Set gc_worker and loadDeleteRangeSQL to a much higher priority Make tidb_opt_insubquery_unfold a global variable Uniform the calculation method of pseudo statistics Improve the CPU usage when opentracing is not enabled Weekly update in TiKV and PD Last week, we landed 24 PRs in the TiKV and PD repositories.Added Support reverse_scan Fixed Check learner regardless of whether learner is enabled or not Use AtomicU64 instead of RwLock to track the snapshot size Improved Migrate CircleCI 1.0 to 2.0 Ignore Lock when lock’s type is Lock Decode the number by accessing slice directly "}, {"url": "https://pingcap.com/meetup/meetup-20180509-no67/", "title": "【Infra Meetup No.67】杭州站", "content": " 上周日 Infra Meetup 首次走进杭州,感谢热情的杭州社区小伙伴们冒雨参加活动~这次活动由我司数据库专家马晓宇老师和资深数据库架构师房晓乐老师为大家带来精彩的分享,还有来自二维火、挖财、蘑菇街的社区小伙伴带来了三个闪电 Talk,分享了他们的 TiDB 实践经验。马晓宇:TiDB 架构及 2.0 详解 首先,我司数据库专家马晓宇老师带来《TiDB 架构及 2.0 详解》精彩分享,介绍了 TiDB 的方方面面,包括存储模块 TiKV,调度模块 PD,计算模块 TiDB, OLAP 组件 TiSpark,数据流转 Syncer 和 Binlog 以及 Cloud 集成等等众多组件和独立产品。马晓宇老师更与现场的同学深入探讨了 TiDB 背后的技术细节以及一些重大选择的原因。例如,从单体 KV 演进到分布式,就不得不思考如何多副本容错,且还需要在多个副本之间达到一致性,这是选择 Raft 协议的根本动机。然而,仅仅是 Raft 并不能满足扩展性的需求,因此又引入了 Raft Group / Region 的分片机制,再加上 PD 模块的调度,让数据和负载均衡得以实现。在 TiDB 部分,马晓宇老师重点介绍了数据库计算引擎的详细架构,包含模块及其不同作用,详细讲解了用户的 SQL 输入如何被分解分析之后产生执行计划并执行,以及数据在 TiDB 中如何将行数据以及索引编码成 TiKV 所需的键值对等等。另外,4 月底 TiDB 2.0 GA 和 TiSpark 1.0 正式发布,马晓宇老师在分享中也提到了 TiDB 和 TiSpark 版本的重大提升:相对 1.0 版本,TiDB 加强了稳定性和性能,针对 TPC-H 等分析型场景,TiDB 有了本质的飞跃。而 TiSpark 1.0 相对于之前发布的 beta 测试版则添加了统计信息用以索引选择,由此让 TiSpark 完整的支持了次级索引。延展阅读 【详解】TiDB 2.0 GA is here! TiDB 2.0 GA Release Notes 房晓乐:TiDB 最佳实践 短暂休息过后,我司资深解决方案架构师房晓乐分享了《TiDB 的最佳实践》。详细介绍 TiDB 安装部署、性能调优、最新周边工具等最佳实践,重点介绍了 TiDB 的典型应用场景及多个 TiDB 实践案例。场景一:海量数据超大数据量、高并发的 OLTP 系统。在今日头条案例中,TiDB 主要应用在今日头条核心 OLTP 系统 - 对象存储系统中,存储其中一部分元数据,支持头条图片和视频相关业务,比如抖音等。如今,TiDB 支撑着今日头条 OLTP 系统里 QPS 比较高的场景:集群容量约几十 T,日常 QPS 峰值会达到几十万。场景二:海量数据-高性能实时分析(HTAP)在同程旅游火车票/飞机票分析系统中,用 TiDB 实时同步火车票/飞机票业务的 MySQL,数千个分片,在 TiDB 中进行关联查询。使用 TiDB 以后,火车票/飞机票的分析不影响主库,集群吞吐/计算能力强悍,春节等节日期间运行稳定。而企业成长带来的基础设施压力,只需要简单增加 x86 机器就可以解决。社区分享 随后,来自 TiDB 社区的三位小伙伴——二维火运维负责人火烧、挖财数据库工程师长扬、蘑菇街运维负责人迈克,分享了他们的 TiDB 实践经验。!二维火运维负责人火烧:“TiDB 上线前的测试要像‘五年高考三年模拟’,不仅要测试不同的业务情况,还要测试不同 TiDB/TiKV 版本、数量的组合。”挖财数据库工程师长扬:“选用 TiDB 有我的私心,我是 Rust 死忠粉,在 Rust 社区了解到明星开源项目——TiKV 之后,进而了解到 TiDB。”蘑菇街运维负责人迈克:“如果 TiDB 是在 2013 年横空出世,我们就只需要在 TiDB 中做业务的纵向拆分 -> 加机器、加机器、加机器 ,就不会有分库分表中间件/MHA/自研监控告警/DDL 工具开发……也就没-有-通-宵。”社区圆桌讨论 社区圆桌讨论环节,来自阿里、网易、二维火、挖财、蘑菇街的技术小伙伴与我们共同畅聊了未来 3 年数据库的发展、数据库技术在云计算领域的发展趋势、开源数据库项目的成功路径等话题,让我们感受到了杭州超棒的技术氛围。最后,再次感谢杭州小伙伴们的热情参与和吉利集团提供的场地支持。杭州,我们还会再回来的~ PingCAP Infra Meetup作为一个基础架构领域的前沿技术公司,PingCAP 希望能为国内真正关注技术本身的 Hackers 打造一个自由分享的平台。自 2016 年 3 月 5 日开始,我们定期在周六的上午举办 Infra Meetup,邀请业内大牛与大家深度探讨基础架构领域的前瞻性技术思考与经验。在这里,我们希望提供一个高水准的前沿技术讨论空间,让大家真正感受到自由的开源精神魅力。 "}, {"url": "https://pingcap.com/weekly/2018-05-07-tidb-weekly/", "title": "Weekly update (April 30 ~ May 06, 2018)", "content": " Weekly update in TiDB Last week, we landed 24 PRs in the TiDB repositories.Added Add DB_NAME and TABLE_NAME in the result of ADMIN SHOW DDL JOBS Add an HTTP API to scatter Regions of a table Add the tidb_retry_limit session variable to control the transaction retry limit Add the auto_analyze_ratio session variable to control the automatic analysis ratio Support the ALTER TABLE FORCE syntax Fixed Restrict the column type in range partition Check the privilege for SHOW CREATE TABLE and information_schema.tables Check nil for Coprocessor stream response Set the index name of ADMIN CHECK INDEX to be case insensitive Improved Reduce the memory usage for duplicated key update Add the reorganization log to make trouble shooting easier Add failure metrics for checkLeader and prepare Weekly update in TiSpark Last week, we landed 1 PR in the TiSpark repositories.Fixed Fix the TopN validation issue Weekly update in TiKV and PD Last week, we landed 15 PRs in the TiKV and PD repositories.Added Support compacting the whole cluster Scatter the leader distribution in a specified range Fixed Resign the PD leader when it is not the same as the etcd leader Fix the parse error of config.toml Fix the bug of deleting the valid scheduler when starting the coordinator Improved Attach an interval to Region heartbeats Open the nightly feature gate for crossbeam-channel Upgrade etcd to v3.3.4 "}, {"url": "https://pingcap.com/blog-cn/tidb-source-code-reading-8/", "title": "TiDB 源码阅读系列文章(八)基于代价的优化", "content": " 概述 本文是 TiDB 源码阅读系列文章的第八篇。内文会先简单介绍制定查询计划以及优化的过程,然后用较大篇幅详述在得到逻辑计划后,如何基于统计信息和不同的属性选择等生成各种不同代价的物理计划,通过比较物理计划的代价,最后选择一个代价最小的物理计划,即 Cost-Based Optimization(CBO)的过程。优化器框架 一般优化器分两个阶段进行优化,即基于规则的优化(Rule-Based-Optimization,简称 RBO)和基于代价的优化(CBO)。TiDB 主要分为两个模块对计划进行优化: 逻辑优化,主要依据关系代数的等价交换规则做一些逻辑变换。 物理优化,主要通过对查询的数据读取、表连接方式、表连接顺序、排序等技术进行优化。 相比 RBO,CBO 依赖于统计信息的准确性与及时性,执行计划会及时的根据数据变换做对应的调整。优化器流程 TiDB 一个查询语句的简单流程:一个语句经过 parser 后会得到一个抽象语法树(AST),首先用经过合法性检查后的 AST 生成一个逻辑计划,接着会进行去关联化、谓词下推、聚合下推等规则化优化,然后通过统计数据计算代价选择最优的物理计划,最后执行。流程如下图 1。 图 1 物理算子简介 通过之前介绍物理层优化的方式,我们可以知道同一个逻辑算子可能因为它的数据读取、计算方式等不同会生成多个不同的物理算子,例如逻辑上的 Join 算子转换成物理算子可以选择 HashJoin、SortMergeJoin、IndexLookupJoin。这里会简单介绍一些逻辑算子可选择的物理算子。例如语句:select sum(*) from t join s on t.c = s.c group by a。此语句中逻辑算子有 DataSource、Aggregation、Join 和 Projection,接下来会对其中几个典型的逻辑算子对应的物理算子进行一个简单介绍,如下表:CBO 流程 基于代价优化的的主要思路是计算所有可能的执行计划的代价,并挑选代价最小的执行计划的路径。那么可以倒推出,首先得到需要采集对应表的统计信息,那么就可以用来计算出每个算子的执行代价,最后将得到每条路径上算子的代价按路径各自累加获取代价最小的路径。具体的代码实现在 plan/optimizer.go 中 dagPhysicalOptimize 函数,本文介绍的流程基本上也都由此函数完成,代码如下: func dagPhysicalOptimize(logic LogicalPlan) (PhysicalPlan, error) { logic.preparePossibleProperties() logic.deriveStats() t, err := logic.convert2PhysicalPlan(&requiredProp{taskTp: rootTaskType, expectedCnt: math.MaxFloat64}) if err != nil { return nil, errors.Trace(err) } p := t.plan() p.ResolveIndices() return p, nil } 出于易读性的考虑,接下来不会按代码调用顺序介绍,下面的段落与上面代码的函数对应情况如下: prune prop 对应的函数 preparePossibleProperties。 统计信息对应的获取函数 deriveStats。 其余章节会介绍函数 convert2PhysicalPlan。 整体流程 这里会先描述整个 CBO 的流程。这部分逻辑的主体框架在文件 plan/physical_plan_builder.go ,具体处理的函数是 convert2PhysicalPlan。例子 为了便于理解 CBO 的整个流程,这里会由一个例子展开。在展开前,先引入 required property,这个概念很重要。required property 是对算子返回值数据的要求,比如希望有些算子是按某些列有序的方式返回数据,那么会传对应的列信息,有些算子是没有要求的那么可以传空的 property。那么,现在我们举个例子,SQL 如下:select sum(s.a),count(t.b) from s join t on s.a = t.a and s.c < 100 and t.c > 10 group bys.a (其中 a 是索引,b 也是索引)此语句就是基于此语句的 on 条件对表 s 和表 t 做 join,然后对 join 结果做聚合。将其用图表示如图 2(此处为了与图 3 对比,此处省略 Projection 算子)。 图 2 得到了逻辑算子之后,我们怎么选择最优的物理算子呢?TiDB 是用记忆化搜索来处理的。由下往上和由上往下搜索的区别不大,考虑到后者的理解性更好,且按 parent 要求的 prop 传给children,能减少一些可能性(这个后面会具体介绍)。我们选择了由上往下的方式。接下来我们来具体介绍一下这个例子中的算子生成及选取流程。一开始的 prop 是空的,不会对 Agg 这个算子有要求。接下来就根据当前逻辑算子所有可能的 prop 构建对应的物理算子,Agg 则可以生成 Stream Agg 和 Hash Agg(此逻辑在如下面代码段的 genPhysPlansByReqProp 实现)。前者要求按 group bykey 有序,即按 a 列有序,所以他孩子的 prop 里面会带有 a 列。后者没有要求,则 prop 为空。此逻辑代码段在 plan/physical_plan_builder.go 中的:for _, pp := range p.self.genPhysPlansByReqProp(prop) { t, err = p.getBestTask(t, pp) if err != nil { return nil, errors.Trace(err) } } 那么 Stream Agg 的 child 是 Join,Join 对应 3 种 物理算子,SortMerge Join(SMJ)、Hash Join(HJ)和 Index Join(IdxJ)。SMJ 算子要求按 join key 有序,所以构建 DS(DataSource)时,需要表 s 按 s.a 有序,表 t 按 t.a 有序。所以将 DS 构建成物理算子的时候虽然有 IdxScan(a),IdxScan(b)和 TableScan(TS),但是这些算子中满足 prop(s.a)只有 IdxScan(a)。这个例子中,只有 IdxScan(a)满足要求,返回给 SMJ,如果有另外的 算子满足的话,就会通过代价来选取,这部分内容会在“代价评估”具体介绍。使用记忆化搜索,将每个算子的 prop 计算 hash 值并存储到哈希表,所以在 HJ 算 DS(s)(带黄色箭头的路径)时会发现 SMJ 下面的 DS(s)计算过了,那么就会直接取值不做多余计算。篇幅有限这里只对左侧的路径做了描述。这个例子最后一层比较是 HA + HJ + idx(c) 和 SA + MJ + idx(a) 的比较,具体也是通过统计信息就算出代价,选取最优解。 图 3 (图中黑色字体算子为逻辑算子,蓝色字体为物理算子,黄色箭头为已经计算过代价的算子,会获取已经缓存在哈希表中的结果,红色虚线箭头为不符合 prop 的算子。)代价评估 代价评估的调用逻辑在 plan/physical_plan_builder.go 中,代码如下:func (p *baseLogicalPlan) getBestTask(bestTask task, pp PhysicalPlan) (task, error) { tasks := make([]task, 0, len(p.children)) for i, child := range p.children { childTask, err := child.convert2PhysicalPlan(pp.getChildReqProps(i)) if err != nil { return nil, errors.Trace(err) } tasks = append(tasks, childTask) } resultTask := pp.attach2Task(tasks...) if resultTask.cost() < bestTask.cost() { bestTask = resultTask } return bestTask, nil } 统计信息 这里会详细描述一下在 CBO 流程中统计信息的使用。具体采集统计信息的方法和过程,本文不具体展开,后续我们会有文章具体介绍。一个 statesInfo 的结构有两个字段: // statsInfo stores the basic information of statistics for the plan's output. It is used for cost estimation. type statsInfo struct { count float64 cardinality []float64 } 其中 count 字段表示这个表的数据行数,每个表有一个值。cardinality 字段是用于表示每一列 distinct 数据行数,每个 column 一个。cardinality 一般通过统计数据得到,也就是统计信息中对应表上对应列的 DNV(the number of distinct value)的值。此数据具体的获取方式有两种: 方式一,使用真实的统计数据,具体公式如下: statsTable.count/ histogram.count * hist.NDV (statsTable.count 会根据 stats lease 定期更新,histogram.count 只有用户手动 analyze 才更新) 方式二,使用一个估计值,由于统计数据在某些情况下还没有收集完成,此时没有统计数据,具体公式如下: statsTable.count * distinctFactor 那么接下来我们举两个例子介绍通过统计数据获取算子的 statsInfo。 DataSource,首先通过前面介绍的两种公式获取 count 和 cardinality,接着用可下推的表达式计算 selectivity 的值,selectivity = row count after filter / row count before filter,最后用计算的 selectivity 来调整原来的 count 和 cardinality 的值。 LogicalJoin(inner join),此算子的 count 获取的公式: N(join(s,t)) = N(s) * N(t) / (V(s.key) * V(t.key)) *Min(V(s.key), V(t.key)) (其中 N 为表的行数,V 为 key 的 cardinality 值)可以理解为表 s 与表 t 中不重复值的平均行数的乘积乘上小表的不重复值行数。这里介绍的逻辑在 stats.go 文件里面的 plan/deriveStats 函数。expected count expected count 表示整个 SQL 结束前此算子期望读取的行数。例如 SQL:select* from swhere s.c1 < 5 order by id limit 3 (其中 c1 是索引列,id 是主键列)。我们可以简单认为得到两类可能的计划路径图,如图 4。 前者在 PhysicalLimit 时选择 id 有序,那么它的 expected count 为 3。因为有 c1 < 5 的过滤条件,所以在 TableScan 时 expected count 的值为 min(n(s),3 / f (σ(c1<5) )) 。 后者在 TopN 的时候虽然知道它需要读取 3 行,但是它是按 id 列有序,所以它的 expected count 为 Max,在 IndexScan 的时候 expected count 是 count * f (σ(c1<5)。 图 4 Task 在代价评估时将物理算子关联到 task 这个对象结构。task 分为三种类型,分别是 cop single, cop double 和 root。前两种类型都可以下推到 coprocessor 执行。将其区分类型有两个原因:一个是它可以区分对应的算子是在 TiDB 处理还是被下推到 TiKV 的 coprocessor 处理;另外一个比较重要的原因是为了评估代价时更加准确。这里我们举个例子,SQL 如下:select *from t where c < 1 and b < 1 and a = 1 (其中 (a,b) 是索引, (b,a,c) 是索引,表 t 有 a、b 和 c 三列)那么可以得到如下两种路径: doubleread(即IndexLookUpReader ):IndexScan( a = 1 and b < 1 ) -> TableScan-> Selection(c < 1) singleread(即IndexReader):IndexScan( b < 1 ) -> Selection( a = 1 and c < 1 ) 不区分 cop single 和 cop double 的时候,去搜索最底层,这会导致情况二被提前舍弃。但是实际上这两种路径,在第一种路径考虑向 TiKV 读两次数据的情况后,其代价很有可能超过第二种路径。所以我们会区分 copsingle 和 cop double,不在 IndexScan 的时候比较,而是在 Selection 结束的时候再比较开销,那么就很可能选第二种计划路径。这样就比较符合实际情况。我们通用的计算代价的公式:Cost(p) = N(p)*FN+M(p)*FM+C(p)*FC (其中 N 表示网络开销,M 表示内存开销,C 表示 CPU 开销,F 表示因子)将 plan 与 task 关联,并加上此 plan 的 cost。task 处理的代码主要在文件 plan/task.go 中。prune properties 引入预处理 property 函数的原因是为了减少一些没有必要考虑的 properties,从而尽可能早的裁减掉成物理计划搜索路径上的分支,例如:select *from t join s on t.A = s.A and t.B = s.B 它的 property 可以是 {A, B}, {B, A}。如果我们有 n 个等式条件,那么我们会有 n! 种可能的 property。如果有了此操作,我们只能使用 t 表和 s 表本身拥有的 properties。properties 是在 DataSource 这个 logical 算子中获取的,因为此算子中可以得到对应的主键和索引信息。此处逻辑由文件 plan/property_cols_prune.go 里的 preparePossibleProperties 函数处理。"}, {"url": "https://pingcap.com/weekly/2018-05-02-tidb-weekly/", "title": "Weekly update (April 23 ~ April 29, 2018)", "content": " Weekly update in TiDB Last week, we landed 49 PRs in the TiDB repositories.Added Add the CHANGELOG.md file to the TiDB repository Support more ODBC syntaxes Support PARTITION BY RANGE COLUMNS in SHOW CREATE TABLE Support the ALTER CONVERT TO syntax Support the ALTER TABLE AUTO_INCREMENT syntax Support the SET NAMES COLLATE DEFAULT syntax Fixed Fix Dump/Load statistics information Fix data race on the LockKeys() function Fix range calculating in the TableHandlesToKVRanges() function Fix the compatibility problem of the UNION statement Fix the wrong behavior of the tryToGetMemTask() function Refine the optimization rule of “TopN Push Down” Improved Add more log information about slow queries Log the slow Coprocessor task in detail Enhance the validation of column names when creating a table Weekly update in TiSpark Last week, we released TiSpark 1.0 GA and landed 18 PRs in the TiSpark repositories.Fixed Fix the leaky session Fix the unsigned index Fix the logic of handling the stale epoch error Fix the logic of handling zero store ID Fix the map single table method Improved Allow forcing the metadata to refresh Adjust the retry policy factor and cache invalidation Weekly update in TiKV and PD Last week, we landed 21 PRs in the TiKV and PD repositories.Added Add the change log for TiKV Add the change log for 2.0 GA Add metrics for hotspot cache Do fuzz test Fixed Improve the Key Scan feature and fix a bug for MVCC Improved Refine the installation instructions Collect Raft’s log Adjust clean_stale_peer_delay Merge (RAW)KV_COMMAND_COUNTER into COMMAND_COUNTER Release the log cache eagerly using GC "}, {"url": "https://pingcap.com/blog/tidb-2-0-announcement/", "title": "TiDB 2.0 is Ready - Faster, Smarter, and Battle-Tested", "content": " TiDB 2.0 is Ready! TiDB is an open-source distributed scalable Hybrid Transactional and Analytical Processing (HTAP) database. It is designed to provide infinite horizontal scalability, strong consistency, and high availability. TiDB is MySQL compatible and serves as a one-stop data warehouse for both OLTP (Online Transactional Processing) and OLAP (Online Analytical Processing) workload.When we launched TiDB 1.0 last October, we were excited but also a bit nervous. After working on TiDB heads-down, non-stop for more than two years, even with the support of a large (and growing) open-source community, we weren’t sure how the world would receive what we’ve built. What we saw during the following six months was nothing short of overwhelming. More than 200 companies have deployed TiDB in their production environments. These companies come from a wide range of industries from e-commerce and food delivery, to fintech, media, gaming, and travel. (You can see an always-incomplete and constantly-updated list of adopters here.)Many of these companies may be unfamiliar to a North American or European audience, but their scale is huge and so is the data they generate. Innovative startups like Mobike (dockless bike-sharing platform with 200 million users) and Yiguo (fresh produce delivery with 5 million customers) use TiDB as a hybrid real-time analytics data warehouse, entrusting us with more than a dozen TBs of data. Fast-growing companies like Toutiao.com (news and short videos app with 120 million DAUs) use TiDB as a solution for their massive amounts of metadata. Platforms like Ele.me (food delivery service recently acquired by Alibaba for 9.5 billion USD) deploys TiKV, the distributed transactional key-value store within the TiDB ecosystem, as its unifying storage layer to hold more than 10 TBs of data.Despite this initial traction, we know TiDB has much room for improvement. To figure out what we should work on in TiDB 2.0, we absorbed insights and feedbacks from our customers, listened to requests and issues from our community, and reflected internally on our ultimate vision of building a distributed hybrid transactional and analytical processing database that scales itself, heals itself, and lives in the cloud. We decided to focus on three areas: Improving stability and correctness; Boosting OLAP performance; Making TiDB easier to use and operate. After six months of hard work, we’ve made significant progress in these three areas–some of which are visible (see TPC-H benchmarks below), some of which are invisible and running in the background, but all of which are implemented to make TiDB 2.0 its best version yet. Here’s what we’ve done.Stability and Correctness The stability and correctness of a database is its most fundamental purpose. As (literally) the beating heart of every business, any volatility, jitter or error inside a database could pose great challenges to the business’s health and operation. Thus, we spent a lot of energy researching, analyzing, and engineering solutions to ensure that TiDB can operate more stably and intelligently.After 1.0, we built an in-house automated testing platform, called Schrodinger, and said good-bye to manual cluster testing in order to scale our testing practices. We added more cases into Schrodinger to comprehensively test every single layer of our product, from RocksDB at the very bottom, to the Raft layer, to the transaction layer, and all the way to the SQL layer.We implemented Chaos testing and introduced more auto-fault injections, such as using Systemtap to delay I/O, to make TiDB more resilient. We also injected faults into specific business logics in our code to ensure that TiDB could function even under the most abnormal circumstances. To ensure correctness in our design and implementation, we use TLA+ to formally prove our work. TLA+, a formal specification language developed by Leslie Lamport and used to verify concurrent systems, is something we’ve been studying and experimenting with since we first started building TiDB.To improve the stability and performance of our storage engine, we optimized our Raft process by adding new functions such as Region Merge for Multi-Raft and Raft Learner; fine-tuned our hotspot scheduling mechanism by collecting more statistics to achieve accurate and precise scheduling; and improved RocksDB’s performance by using the DeleteFilesInRanges feature to achieve higher disk space collection efficiency, lower workload on the disk, and balance usage of disk resources.OLAP Performance Boost Many of our customers have anywhere from hundreds of GBs to more than a dozen TBs of data in their TiDB clusters. These companies’ datasets grow on a daily basis and so are their needs and requirements for real-time data analytics to make the most out of their data. Thus, improving OLAP query performances on huge datasets became an obvious top priority.In TiDB 1.0, we made the switch from Rule-Based Optimizer to Cost-Based Optimizer, and in TiDB 2.0, we refactored our optimizer and execution engine to achieve quicker selection of the optimal query plan and the most efficient execution plan. In short, we made TiDB smarter. Our optimizations resulted in the following improvements: Higher accuracy and timely updates of the statistics; More precise estimation of query cost; More in-depth analysis of complex criteria and filters; Graceful processing of correlated subqueries; More flexible and accurate selection of the physical operator. We also introduced Chunk, a new internal data encoding method where a chunk of data is stored in a data structure instead of in rows. The data within the same column of data is stored sequentially in memory by chunks so that: Memory consumption is significantly reduced; GC overhead is reduced by allocating memory in chunks; Calling overhead is reduced by transferring the data between operators in chunks; Vector computing is made possible in certain circumstances and cache miss rate of CPU is reduced. Ease of Use and Operation While the entire TiDB project can appear rather complex, it doesn’t have to be. Thus, we spent a lot of time improving its usability and operationality, so users can easily deploy, upgrade, scale, monitor, management, and diagnose the entire system, no matter how many TiDB clusters you have running.To improve monitoring, we added more than 100 metrics to help monitor the HTTP interface and SQL statements, in order to expose the system’s runtime information for tuning and diagnosis.To make operating TiDB clusters easier, we optimized our operation tools and simplified certain processes to reduce their complexity and impact on business operations. We also included useful new tools, like auto-deployment of binlog components and TLS enablement.Some Benchmarks, No Benchmark-eting We’ve mentioned significant OLAP performance boost in TiDB 2.0 compared to 1.0. Here’s a set of TPC-H benchmarks to back that up. (Blue is 2.0, orange is 1.0)As you can see, all queries run much faster in 2.0 than in 1.0, many of them several times if not orders of magnitude faster. What’s more, queries that could not be processed at all in 1.0 (i.e. Q2, 5, 7, 17, 18, 19, 21) all returned results with good performance in 2.0. Only one query, Q15, returned NaN in 2.0 because this version currently does not support VIEW. (Don’t worry, VIEW support is on our roadmap.) You can find details of TiDB 2.0’s TPC-H 50G Performance Test Report here and reproduce the results yourself.We always strive to be transparent, fair, and reproducible with every set of benchmarks we release and avoid “benchmark-eting.” There are too many misleading benchmarks out there that look shiny on the surface but don’t stand up to scrutiny. Abusing benchmarks may yield an easy win, but is ultimately detrimental to the product, the community, and the users who rely on them. That’s something we are committed to never do.Looking Ahead TiDB 2.0 is faster, smarter, and …"}, {"url": "https://pingcap.com/blog-cn/tidb-2.0-ga-release/", "title": "TiDB 2.0 GA Release", "content": " 2018 年 4 月 27 日,TiDB 发布 2.0 GA 版。相比 1.0 版本,对 MySQL 兼容性、系统稳定性、优化器和执行器做了很多改进。TiDB SQL 优化器 精简统计信息数据结构,减小内存占用 加快进程启动时加载统计信息速度 支持统计信息动态更新 [experimental] 优化代价模型,对代价估算更精准 使用 Count-Min Sketch 更精确地估算点查的代价 支持分析更复杂的条件,尽可能充分的使用索引 支持通过 STRAIGHT_JOIN 语法手动指定 Join 顺序 GROUP BY子句为空时使用 Stream Aggregation 算子,提升性能 支持使用索引计算 Max/Min 函数 优化关联子查询处理算法,支持将更多类型的关联子查询解关联并转化成 Left Outer Join 扩大 IndexLookupJoin 的使用范围,索引前缀匹配的场景也可以使用该算法 SQL 执行引擎 使用 Chunk 结构重构所有执行器算子,提升分析型语句执行性能,减少内存占用,显著提升 TPC-H 结果 支持 Streaming Aggregation 算子下推 优化 Insert Into Ignore 语句性能,提升 10 倍以上 优化 Insert On Duplicate Key Update 语句性能,提升 10 倍以上 下推更多的数据类型和函数到 TiKV 计算 优化 Load Data 性能,提升 10 倍以上 支持对物理算子内存使用进行统计,通过配置文件以及系统变量指定超过阈值后的处理行为 支持限制单条 SQL 语句使用内存的大小,减少程序 OOM 风险 支持在 CRUD 操作中使用隐式的行 ID 提升点查性能 Server 支持 Proxy Protocol 添加大量监控项, 优化日志 支持配置文件的合法性检测 支持 HTTP API 获取 TiDB 参数信息 使用 Batch 方式 Resolve Lock,提升垃圾回收速度 支持多线程垃圾回收 支持 TLS 兼容性 支持更多 MySQL 语法 支持配置文件修改 lower_case_table_names 系统变量,用于支持 OGG 数据同步工具 提升对 Navicat 的兼容性 在 Information_Schema 中支持显示建表时间 修复部分函数/表达式返回类型和 MySQL 不同的问题 提升对 JDBC 兼容性 支持更多的 SQL_MODE DDL 优化 Add Index 的执行速度,部分场景下速度大幅度提升 Add Index 操作变更为低优先级,降低对线上业务影响 Admin Show DDL Jobs 输出更详细的 DDL 任务状态信息 支持 Admin Show DDL Job Queries JobID 查询当前正在运行的 DDL 任务的原始语句 支持 Admin Recover Index 命令,用于灾难恢复情况下修复索引数据 支持通过 Alter 语句修改 Table Options PD 增加 Region Merge 支持,合并数据删除后产生的空 Region [experimental] 增加 Raft Learner 支持 [experimental] 调度器优化 调度器适应不同的 Region size 提升 TiKV 宕机时数据恢复的优先级和恢复速度 提升下线 TiKV 节点搬迁数据的速度 优化 TiKV 节点空间不足时的调度策略,尽可能防止空间不足时磁盘被写满 提升 balance-leader scheduler 的调度效率 减少 balance-region scheduler 调度开销 优化 hot-region scheduler 的执行效率 运维接口及配置 增加 TLS 支持 支持设置 PD leader 优先级 支持基于 label 配置属性 支持配置特定 label 的节点不调度 Region leader 支持手动 Split Region,可用于处理单 Region 热点的问题 支持打散指定 Region,用于某些情况下手动调整热点 Region 分布 增加配置参数检查规则,完善配置项的合法性较验 调试接口 增加 Drop Region 调试接口 增加枚举各个 PD health 状态的接口 统计相关 添加异常 Region 的统计 添加 Region 隔离级别的统计 添加调度相关 metrics 性能优化 PD leader 尽量与 etcd leader 保持同步,提升写入性能 优化 Region heartbeat 性能,现可支持超过 100 万 Region TiKV 功能 保护关键配置,防止错误修改 支持 Region Merge [experimental] 添加 Raw DeleteRange API 添加 GetMetric API 添加 Raw Batch Put,Raw Batch Get,Raw Batch Delete 和 Raw Batch Scan 给 Raw KV API 增加 Column Family 参数,能对特定 Column Family 进行操作 Coprocessor 支持 streaming 模式,支持 streaming 聚合 支持配置 Coprocessor 请求的超时时间 心跳包携带时间戳 支持在线修改 RocksDB 的一些参数,包括 block-cache-size 大小等 支持配置 Coprocessor 遇到某些错误时的行为 支持以导数据模式启动,减少导数据过程中的写放大 支持手动对 region 进行对半 split 完善数据修复工具 tikv-ctl Coprocessor 返回更多的统计信息,以便指导 TiDB 的行为 支持 ImportSST API,可以用于 SST 文件导入 [experimental] 新增 TiKV Importer 二进制,与 TiDB Lightning 集成用于快速导入数据 [experimental] 性能 使用 ReadPool 优化读性能,raw_get/get/batch_get 提升 30% 提升 metrics 的性能 Raft snapshot 处理完之后立即通知 PD,加快调度速度 解决 RocksDB 刷盘导致性能抖动问题 提升在数据删除之后的空间回收 加速启动过程中的垃圾清理过程 使用 DeleteFilesInRanges 减少副本迁移时 I/O 开销 稳定性 解决在 PD leader 发送切换的情况下 gRPC call 不返回问题 解决由于 snapshot 导致下线节点慢的问题 限制搬移副本临时占用的空间大小 如果有 Region 长时间没有 Leader,进行上报 根据 compaction 事件及时更新统计的 Region size 限制单次 scan lock 请求的扫描的数据量,防止超时 限制接收 snapshot 过程中的内存占用,防止 OOM 提升 CI test 的速度 解决由于 snapshot 太多导致的 OOM 问题 配置 gRPC 的 keepalive 参数 修复 Region 增多容易 OOM 的问题 TiSpark TiSpark 使用独立的版本号,现为 1.0 GA。TiSpark 1.0 版本组件提供了针对 TiDB 上的数据使用 Apache Spark 进行分布式计算的能力。 提供了针对 TiKV 读取的 gRPC 通信框架 提供了对 TiKV 组件数据的和通信协议部分的编码解码 提供了计算下推功能,包含 聚合下推 谓词下推 TopN 下推 Limit 下推 提供了索引相关支持 谓词转化聚簇索引范围 谓词转化次级索引 Index Only 查询优化 运行时索引退化扫表优化 提供了基于代价优化 统计信息支持 索引选择 广播表代价估算 多种 Spark Interface 的支持 Spark Shell 支持 ThriftServer/JDBC 支持 Spark-SQL 交互支持 PySpark Shell 支持 SparkR 支持 如今,在社区和 PingCAP 技术团队的共同努力下,TiDB 2.0 GA 版已发布,在此感谢社区小伙伴们长久以来的参与和贡献。 作为世界级开源的分布式关系型数据库,TiDB 灵感来自于 Google Spanner/F1,具备『分布式强一致性事务、在线弹性水平扩展、故障自恢复的高可用、跨数据中心多活』等核心特性。TiDB 于 2015 年 5 月在 GitHub 创建,同年 12 月发布 Alpha 版本,而后于 2016 年 6 月发布 Beta 版,12 月发布 RC1 版, 2017 年 3 月发布 RC2 版,6 月发布 RC3 版,8 月发布 RC4 版,10 月发版 TiDB 1.0,并在 2018 年 3 月发版 2.0 RC1。 "}, {"url": "https://pingcap.com/blog-cn/tidb-2.0-ga-release-detail/", "title": "详解 | TiDB 2.0 GA is here!", "content": " 去年十月份的时候,我们发布了 TiDB 1.0 版本,为此我们日夜兼程奋斗了两年半时间,我们认为 1.0 版本达到了可在生产环境中使用的程度。在接下来的六个月中,我们一方面维护 1.0 版本的稳定性并且增加必要的新特性,另一方面马不停蹄的开发 2.0 版本。经过半年时间,6 个 RC 版本,今天 TiDB 2.0 GA 版本正式发布。2.0 版本规划 在 2.0 版本的规划阶段,我们对“这个版本需要做什么”进行了深入思考,我们根据现有用户的情况、技术发展趋势以及社区的声音,认为 2.0 版本需要聚焦在以下几点: 保证 TiDB 的稳定性以及正确性。这两点是一个数据库软件的基础功能,作为业务的基石,任何一点抖动或者错误都可能对业务造成巨大的影响。目前已经有大量的用户在线上使用 TiDB,这些用户的数据量在不断增加、业务也在不断演进。我们非常关注 TiDB 集群如何保持长期稳定运行、如何减小系统的抖动、如何进行智能的调度,为此做了大量的调研和分析。 提升 TiDB 在大数据量下的查询性能。从我们接触下来的用户来看,很多客户都有少则上百 GB,多则上百 TB 的数据,一方面数据会持续增加,另一方面也希望能对这些数据做实时的查询。所以如果能提升大数据量下的查询性能,对用户会很有帮助。 优化 TiDB 的易用性和可维护性。TiDB 整套系统的复杂性比较高,运维及使用的难度要大于单机数据库,所以我们希望能提供尽可能方便的方案帮助用户使用 TiDB。比如尽可能简化部署、升级、扩容方式,尽可能容易的定位系统中出现的异常状态。 围绕上面三点原则,我们做了大量的改进,一些是对外可见(如 OLAP 性能的显著提升、监控项的大量增加以及运维工具的各项优化),还有更多的改进是隐藏在数据库背后,默默的提升整个数据库的稳定性以及正确性。正确性和稳定性 在 1.0 版本发布之后,我们开始构建和完善自动化测试平台 Schrodinger,彻底告别了之前靠手工部署集群测试的方式。同时我们也新增了非常多的测试用例,做到测试从最底层 RocksDB,到 Raft,再到 Transaction,然后是 SQL 都能覆盖。在 Chaos 测试上面,我们引入了更多的错误注入工具,例如使用 systemtap 对 I/O 进行 delay 等,也在代码特定的业务的逻辑进行错误注入测试,充分保证 TiDB 在异常条件下面也能稳定运行。之前我们做了很多 TLA+ 的论证工作,也有一些简单的测试,1.0 之后我们开始使用 TLA+ 系统进行论证,保证我们的实现在设计上面都是正确的。在存储引擎方面,为了提升大规模集群的稳定性和性能,我们优化了 Raft 的流程,引入 Region Merge、Raft Learner 等新特性;优化热点调度机制,统计更多的信息,并根据这些信息做更合理的调度;优化 RocksDB 的性能,使用 DeleteFilesInRanges 等特性,提升空间回收效率,降低磁盘负载,以及更加平滑地使用磁盘资源等等。OLAP 性能优化 在 2.0 版本中,我们重构了 SQL 优化器和执行引擎,希望能尽可能快的选择最优查询计划并且尽可能高效地执行查询计划。1.0 版本已经从基于规则的查询优化器转向基于代价的查询优化器,但是还不够完善,在 2.0 版本中,我们一方面优化统计信息的精确度以及更新及时程度,另一方面提升 SQL 优化器的能力,对查询代价的估算更加精准、对复杂过滤条件的分析更加细致、对关联子查询的处理更加优雅、对物理算子的选择更加灵活准确。在这一版本中,SQL 执行引擎引入新的内部数据表示方式 — Chunk,一个结构中保存一批数据而不仅是一行数据,同一列的数据在内存中连续存放,使得内存使用更紧凑,这样带来了几点好处:1. 显著减小了内存消耗; 2. 批量分配内存,减小了 GC 开销;3. 算子之间可以对数据进行批量传递,减小调用开销;4. 在某些场景下,可以进行向量计算以及减小 CPU 的 Cache Miss 的情况。完成上述两项改动之后,TiDB 在 OLAP 场景下的性能有了大幅的质的提升,从 TPC-H 的对比结果https://github.com/pingcap/docs-cn/blob/master/benchmark/tpch.md 来看,所有的 Query 在 2.0 中都运行得更快,一些 Query 大多数都有几倍甚至数量级的提升,特别是一些 1.0 中跑不出结果的 Query 在 2.0 中都能顺利执行。易用性和可运维性 为了让 TiDB 更容易被安装和使用,监控、运维、工具方面我们也做了诸多优化。在监控方面,增加了过百个监控项,同时通过 HTTP 接口、SQL 语句等方式暴露出一些运行时信息,用于系统调优或者是定位系统中存在的问题。在运维方面,我们运维工具做了优化,简化操作流程,降低操作复杂度及操作过程对于线上的影响。同时功能也更加丰富,支持自动部署 Binlog 组件、支持启用 TLS。版本升级 从 TiDB 1.0 到 2.0 可以进行滚动升级,具体步骤可以参考 这篇文档。One more thing 我们也同时发布了 TiSpark 1.0 GA 版本,了解一下? 点击查看 TiDB 2.0 GA Release Notes "}, {"url": "https://pingcap.com/weekly/2018-04-23-tidb-weekly/", "title": "Weekly update (April 16 ~ April 22, 2018)", "content": " Weekly update in TiDB Last week, we landed 36 PRs in the TiDB repositories.Added Add TiDB HTTP API to query the DDL history information Add the session variable tidb_optimizer_selectivity_level to control the selectivity estimation level Add table partition information in SHOW CREATE TABLE Analyze the table automatically when the modified row count of a table is too large Fixed Check if the column name already exists before renaming a column Fix a problem when parallel executing CREATE TABLE IF NOT EXISTS Fix pseudo selectivity estimation for the primary key Eliminate Projection when the schema length is 0 Set the hash join concurrency in NewSessionVars Improved Refactor scalarFuncToPBExpr Improve the cost estimation for physical aggregate operators Improve the execution performance of the UnionScanExec operator Cache global variables Weekly update in TiSpark Last week, we landed 8 PRs in the TiSpark repositories.Fixed Fix the binary test and delete redundant issue tests Fix Protobuf definition according to TiKV changes Weekly update in TiKV and PD Last week, we landed 29 PRs in the TiKV and PD repositories.Added Support specifying ColumnFamily in the rawkv APIs Add a new Region score function for balance that considers the free space of TiKV Support ScatterRegion Fixed Fix the issue of reloading without persisted schedulers Fix wrongly collected Coprocessor statistics Bump the recursion limit to 200 Improved Upgrade the Rust and Clippy versions Add metrics to FuturePool Reduce the lock contention in WORKER "}, {"url": "https://pingcap.com/meetup/meetup-20180417-no66/", "title": "【Infra Meetup No.66】Application of TLA+ at PingCAP", "content": " 上周六的 Meetup 上,我司董麒麟同学为大家讲解了 TLA+ 在 TiDB 中的应用。现奉上现场视频 & 干货节选,Enjoy~ 视频回顾 视频 | Infra Meetup No.66:Application of TLA+ at PingCAP可下载 完整 PPT 配合观看干货节选 TLA+ 是一个用来设计、描述和验证并发系统的一套形式化语言,易学易用。在 TiDB 中,我们非常关心一些关键系统的设计正确性,所以使用 TLA+ 来保证这一点。PingCAP 在 2017 年底开始尝试使用 TLA+,到目前为止,已经用 TLA+ 验证了我们优化过的 Percolator 协议以及 Multi-raft region merge 的正确性。这些代码可以在 pingcap/tla-plus 上找到。TLA+ 可以在一个比代码更高的层面上描述系统。在编写代码之前,将系统完整地表述一遍是很重要的。这能强迫我们去思考这个系统的细节,避免早期设计时出现失误并保证正确性。TLA+ 的基本原理是将系统描述成为一个状态机。系统可以用 TLA+ 来抽象出若干变量表达它的当前状态,并用形式化的语言去描述这个状态机的初始结束状态与状态转移。我们对这个系统的一些 Safety 性质比较感兴趣,这些 Safety 的性质也可以在 TLA+ 中用谓词来刻画。另外一个工具 TLC 可以用来验证被 TLA+ 抽象出来的系统模型。TLC 的原理是枚举状态机的所有可以遍历到的状态集。验证系统的正确性就是确保所有状态都满足对应的谓词。TLA+ 在 TiDB 的第一个应用是 Percolator 事务协议。这个协议是一个二阶段提交算法,用来在只支持单行事物的存储上实现多行事务。这个协议的具体介绍可以在 这里 找到。和原始协议的不同,TiDB 做了一个很重要的优化,在 prewrite 阶段,我们并不是采取了先 prewrite 主锁,再并发副锁的策略,而是主锁和副锁一起并发。但是如果直接这样设计是存在问题的。在视频中可以看到我们是如何用 TLA+ 定位这个问题,然后提出了一个解决方案来克服这个问题。我们用 TLA+ 验证了优化的正确性。TLA+ 在 TiDB 的第二个应用是 Multi-raft region merge。这个是因为在很多情况下,不同的 region 可能分片并不均匀。我们用 TLA+ 来保证这个系统的正确性是一方面。另外一个方面是在设计这个文档时,我们发现用自然语言来描述这个系统会存在歧义模糊的问题,而用 TLA+ 这种形式化的语言就能很好地克服这个问题。这里想表达的是,写 TLA+ 代码也是一种投资的行为,如果想让这个系统一直健壮地跑下去,而且能被后面加入公司的员工以及 contributors 理解,那么用 TLA+ 去描述这个系统是一个非常划算的事情。 PingCAP Infra Meetup作为一个基础架构领域的前沿技术公司,PingCAP 希望能为国内真正关注技术本身的 Hackers 打造一个自由分享的平台。自 2016 年 3 月 5 日开始,我们定期在周六的上午举办 Infra Meetup,邀请业内大牛与大家深度探讨基础架构领域的前瞻性技术思考与经验。在这里,我们希望提供一个高水准的前沿技术讨论空间,让大家真正感受到自由的开源精神魅力。 "}, {"url": "https://pingcap.com/weekly/2018-04-16-tidb-weekly/", "title": "Weekly update (April 09 ~ April 15, 2018)", "content": " Weekly update in TiDB Last week, we landed 32 PRs in the TiDB repositories.Added Update the average column size dynamically Update statistics using query feedback Use tidb_index_lookup_join_currency to control the number of IndexLookupJoin inner workers Add a TiDB system variable tidb_hash_join_concurrency Make pseudo estimate ratio configurable Show memory usage in show processlist Fixed Make inferring of decimal for unix_timestamp more consistent with MySQL Fix the bug of writing null value into not null column in write-only state Fix the IndexLookUpJoin hang problem Update the column’s offset when modifying the column Support insert ignore on duplicate update Improved Set explicit_defaults_for_timestamp = on for compatibility with MySQL Increase the default lease Improve the performance of Clone Use a cloned Expression when setting it to plan Weekly update in TiSpark Last week, we landed 3 PRs in the TiSpark repositories.Added Add wrapper for Exception handling Build a new RPC error handling framework Weekly update in TiKV and PD Last week, we landed 25 PRs in the TiKV and PD repositories.Added Support Raft learner in raftstore Support adding the learner node Modify RocksDB cache size dynamically Build tikv-importer as a standalone binary Fixed Remove a misused RocksDB ticker Disable DeleteRange by default Avoid the panic caused by extreme conditions when generating snapshots Fix the issue of allocating IDs frequently Improved Shrink queues into smaller ones to save memory when they are not used anymore Simplify the process of ImportSST::Upload API Process the overflow_as_warning flag Collect the number of rows scanned for each range Do not clear taintCache in balanceRegionScheduler Adjust the balance configuration Add keepalive Fix the compatibility issue when adding a new scheduler New contributors (Thanks!) TiKV: Zhang Yuning Docs: John Liu Docs-cn: yanchaozhong "}, {"url": "https://pingcap.com/blog/chaos-practice-in-tidb/", "title": "From Chaos to Order -- Tools and Techniques for Testing TiDB, A Distributed NewSQL Database", "content": " What is Chaos? In the world of distributed computing, you can never predict what will happen to your cluster. Anything is possible. A butterfly fluttering in Rio de Janeiro could change the weather in Chicago, or destroy an entire data center in Cairo. Network Time Protocol (NTP) might be out of sync, CPUs might mysteriously max out, or worse yet, your diligent DBA might accidentally remove data in the middle of the night.As an open source distributed NewSQL Hybrid Transactional/Analytical Processing (HTAP) database, TiDB contains the most important asset of our customers–their data. One of the fundamental and foremost requirements of our system is to be fault-tolerant. But how do you ensure fault tolerance in a distributed database? In this article, I will cover the top fault injection tools and techniques in Chaos Engineering, as well as how we execute Chaos practices in TiDB.Why Do We Need Chaos Ever since Netflix invented Chaos Monkey in 2011, this Monkey has become more and more popular. If you want to build a distributed system, letting the Chaos Monkey go a little crazy on your cluster can help build a more fault-tolerant, resilient, and reliable system.Typically, we write as many unit tests as we can to ensure all of our logics are covered, build sufficient integration tests to guarantee that our system can work well with other components, and do performance tests to improve the handling of millions of requests.Unfortunately, that’s not enough for a distributed system. No matter how many unit, integration, or performance tests we do, we still can’t guarantee that our system can withstand the unpredictability of in-production environment. We may meet disk failures, machine power lost, network isolation, and that’s just the tip of the iceberg. To make distributed systems like TiDB more robust, we need a method to simulate unpredictable failures and test our responses to these failures. That’s why we need Chaos Monkey.How to get “Chaotic” Not only did Netflix invent Chaos, it also introduced the concept of “Chaos Engineering,” which is a methodical way to uncover system-level weaknesses. There are some core principles of the Chaos Engineering, as well as a whole book on Chaos Engineering.In TiDB, we apply Chaos Engineering to observe the state of our system, make hypothesis, conduct experiments, and verify those hypothesis with real results. We adhere to the principles, but also add our own flavors. Here’s our 5-step Chaos methodology: Use Prometheus as the monitoring tool to observe the status and behaviors of a TiDB cluster and collect the metrics of a stable cluster to establish a proxy for what a stable system looks like; Make a list of hypothesis of certain failure scenarios and what we expect to happen. One example in TiDB’s case: If we isolate one TiKV (the distributed key-value storage layer of TiDB) node from the cluster, the QPS (Queries Per Second) should drop, but will soon recover to another stable state. Pick a hypothesis from our list; Conduct an experiment on the chosen hypothesis by injecting faults and analyzing the result. If the result is different from our hypothesis, there may (or must) be something wrong or missing; Rinse and repeat on another hypothesis from our list and automate the process. One of the advanced principles in Chaos Engineering is to run experiments in a production environment. Before deploying TiDB for our users, we have to ensure it’s battle-tested. However, we can’t perform these experiments in our customers’ production environment, because they entrust TiDB with their most mission-critical data. What we can do is create our own “battlefield,”–an internal production environment.Currently, we are using TiDB to power Jira for our internal issues tracking and project management work, “eating our own dog food,” so to speak. With this setup, we can run Chaos experiments on Jira. Without any warning, we would inject faults to jeopardize all aspects of the Jira system while our own employees are using it for their daily tasks, in order to simulate a series of cascading “accidents” to identify possible system loopholes. We call this practice “military drill,” and it occurs frequently during our daily operations. In the following sections, I will walk through how we do fault injection and automate the process.How TiDB does Fault Injection Fault injection is a technique for improving the coverage of a test by introducing faults to test code paths, in particular error handling code paths. It is widely considered as an important part of developing robust software. There are many ways to do fault injection to assess the system. In TiDB, faults are injected in the following ways: Use kill -9 to kill the process by force or use kill to kill the process gracefully and then restart it. Send SIGSTOP to hang or SIGCONT to resume the process. Use renice to adjust the process priority or use setpriority for the threads of the process. Max out the CPU. Use iptables or tc to drop or reject the network packages or delay the network packages. Use tc to reorder the network packages and use a proxy to reorder the gRPC requests. Use iperf to take all network throughput. Use libfuse to mount a file system and do the I/O fault injection. Link libfiu to do the I/O fault injection. Use rm -rf forcbily to remove all data. Use echo 0 > file to damage a file. Copy a huge file to create the NoSpace problem. Top Fault Injection Tools Kernel Fault Injection A popular fault injection tool is the Fault Injection Framework that’s included in the Linux kernel, which developers can use to implement simple fault injection to test device drivers. For more accurate fault injections, e.g. returning error when a user reads a file, or allocating failure in malloc, we use the following fault injection process: Rebuild the kernel with the framework enabled Use the kernel fault injection as follow:echo 1 > /sys/block/vdb/vdb1/make-it-failmount debugfs /debug -t debugfscd /debug/fail_make_requestecho 10 > interval # intervalecho 100 > probability # 100% probabilityecho -1 > times # how many times: -1 means no limit When we access the file, we may get following errors: Buffer I/O error on device vdb1, logical block 32538624lost page write due to I/O error on vdb1 We can inject fault to the allocation as follow:echo 1 > cache-filterecho 1 > /sys/kernel/slab/ext4_inode_cache/failslabecho N > ignore-gfp-waitecho -1 > timesecho 100 > probability cp linux-3.10.1.tar.xz linux-3.10.1.tar.xz.6cp: cannot create regular file ‘linux-3.10.1.tar.xz.6’: Cannot allocate memory Although the Linux kernel’s Fault Injection Framework is powerful, we have to rebuild the kernel because some users won’t enable it in their production environment.SystemTap Another way to inject fault is [SystemTap](https://sourceware.org/systemtap/), a scripting language and tool which can assist diagnosis of a performance or functional problem. We use SystemTap to probe the kernel function and do accurate fault injection. For example, we can delay the I/O operation in the read/write return by doing the following:probe vfs.read.return { if (target() != pid()) next udelay(300) } probe vfs.write.return { if (target() != pid()) next udelay(300) } We can also change the I/O return value. Below we inject an EINTR for read and ENOSPC for write:probe vfs.read.return { if (target() != pid()) next // Interrupted by a signal $return = -4 } probe vfs.write.return { if (target() != pid()) next // No space $return = -28 } Fail Sometimes, we want to do fault injection in specific places like:fn save_snapshot() { save_data(); save_meta(); } We do this because, for example, we want to see the system panic after the snapshot data is saved, but meta is not yet. How can we do this? We can use a mechanism called …"}, {"url": "https://pingcap.com/blog-cn/tidb-source-code-reading-7/", "title": "TiDB 源码阅读系列文章(七)基于规则的优化", "content": " 在 TiDB 里面,SQL 优化的过程可以分为逻辑优化和物理优化两个部分。逻辑优化主要是基于规则的优化,简称 RBO(rule based optimization)。物理优化会为逻辑查询计划中的算子选择某个具体的实现,需要用到一些统计信息,决定哪一种方式代价最低,所以是基于代价的优化 CBO(cost based optimization)。本篇将主要关注逻辑优化。先介绍 TiDB 中的逻辑算子,然后介绍 TiDB 的逻辑优化规则,包括列裁剪、最大最小消除、投影消除、谓词下推等等。逻辑算子介绍 在写具体的优化规则之前,先简单介绍查询计划里面的一些逻辑算子。 DataSource 这个就是数据源,也就是表,select * from t 里面的 t Selection 选择,例如 select xxx from t where xx = 5 里面的 where 过滤条件 Projection 投影, select c from t 里面的取 c 列是投影操作 Join 连接, select xx from t1, t2 where t1.c = t2.c 就是把 t1 t2 两个表做 Join 选择,投影,连接(简称 SPJ) 是最基本的算子。其中 Join 有内连接,左外右外连接等多种连接方式。select b from t1, t2 where t1.c = t2.c and t1.a > 5 变成逻辑查询计划之后,t1 t2 对应的 DataSource,负责将数据捞上来。上面接个 Join 算子,将两个表的结果按 t1.c = t2.c连接,再按 t1.a > 5 做一个 Selection 过滤,最后将 b 列投影。下图是未经优化的表示: Sort 就是 select xx from xx order by 里面的 order by Aggregation,在 select sum(xx) from xx group by yy 中的 group by 操作,按某些列分组。分组之后,可能带一些聚合函数,比如 Max/Min/Sum/Count/Average 等,这个例子里面是一个 sum Apply 这个是用来做子查询的 列裁剪 列裁剪的思想是这样的:对于用不上的列,没有必要读取它们的数据,无谓的浪费 IO 资源。比如说表 t 里面有 a b c d 四列。select a from t where b > 5 这个查询里面明显只有 a b 两列被用到了,所以 c d 的数据是不需要读取的。在查询计划里面,Selection 算子用到 b 列,下面接一个 DataSource 用到了 a b 两列,剩下 c 和 d 都可以裁剪掉,DataSource 读数据时不需要将它们读进来。列裁剪的算法实现是自顶向下地把算子过一遍。某个节点需要用到的列,等于它自己需要用到的列,加上它的父节点需要用到的列。可以发现,由上往下的节点,需要用到的列将越来越多。代码是在 plan/column_pruning.go 文件里面。列裁剪主要影响的算子是 Projection,DataSource,Aggregation,因为它们跟列直接相关。Projection 里面会裁掉用不上的列,DataSource 里面也会裁剪掉不需要使用的列。Aggregation 算子会涉及哪些列?group by 用到的列,以及聚合函数里面引用到的列。比如 select avg(a), sum(b) from t group by c d,这里面 group by 用到的 c 和 d 列,聚合函数用到的 a 和 b 列。所以这个 Aggregation 使用到的就是 a b c d 四列。Selection 做列裁剪时,要看它父节点要哪些列,然后它自己的条件里面要用到哪些列。Sort 就看 order by 里面用到了哪些列。Join 则要把连接条件中用到的各种列都算进去。具体的代码里面,各个算子都是实现 PruneColumns 接口:func (p *LogicalPlan) PruneColumns(parentUsedCols []*expression.Column) 通过列裁剪这一步操作之后,查询计划里面各个算子,只会记录下它实际需要用到的那些列。最大最小消除 最大最小消除,会对 Min/Max 语句进行改写。select min(id) from t 我们用另一种写法,可以做到类似的效果:select id from t order by id desc limit 1 这个写法有什么好处呢?前一个语句,生成的执行计划,是一个 TableScan 上面接一个 Aggregation,也就是说这是一个全表扫描的操作。后一个语句,生成执行计划是 TableScan + Sort + Limit。在某些情况,比如 id 是主键或者是存在索引,数据本身有序, Sort 就可以消除,最终变成 TableScan 或者 IndexLookUp 接一个 Limit,这样子就不需要全表扫了,只需要读到第一条数据就得到结果!全表扫操作跟只查一条数据,性能上可是天壤之别。最大最小消除,做的事情就是由 SQL 优化器“自动”地做这个变换。select max(id) from t 生成的查询树会被转换成下面这种:select max(id) from (select id from t order by id desc limit 1 where id is not null) t 这个变换复杂一些是要处理 NULL 的情况。经过这步变换之后,还会执行其它变换。所以中间生成的额外的算子,可能在其它变换里面被继续修改掉。min 也是类似的语句替换。相应的代码是在 max_min_eliminate.go 文件里面。实现是一个纯粹的 AST 结构的修改。投影消除 投影消除可以把不必要的 Projection 算子消除掉。那么,什么情况下,投影算子是可消除的呢?首先,如果 Projection 算子要投影的列,跟它的子节点的输出列,是一模一样的,那么投影步骤就是一个无用操作,可以消除。比如 select a,b from t 在表 t 里面就正好就是 a b 两列,那就没必要 TableScan 上面再做一次 Projection。然后,投影算子下面的子节点,又是另一个投影算子,那么子节点的投影操作就没有意义,可以消除。比如 Projection(A) -> Projection(A,B,C) 只需要保留 Projection(A) 就够了。类似的,在投影消除规则里面,Aggregation 跟 Projection 操作很类似。因为从 Aggregation 节点出来的都是具体的列,所以 Aggregation(A) -> Projection(A,B,C) 中,这个 Projection 也可以消除。代码是在 eliminate_projection.go 里面。func eliminate(p Plan, canEliminate bool) { 对 p 的每个子节点,递归地调用 eliminate 如果 p 是 Project 如果 canEliminate 为真 消除 p 如果 p 的子节点的输出列,跟 p 的输出列相同,消除 p } 注意 canEliminate 参数,它是代表是否处于一个可被消除的“上下文”里面。比如 Projection(A) -> Projection(A, B, C) 或者 Aggregation -> Projection 递归调用到子节点 Projection 时,该 Projection 就处于一个 canEliminate 的上下文。简单解释就是,一个 Projection 节点是否可消除: 一方面由它父节点告诉它,它是否是一个冗余的 Projection 操作 另一方面由它自己和子节点的输入列做比较,输出相同则可消除 谓词下推 谓词下推是非常重要的一个优化。比如select * from t1, t2 where t1.a > 3 and t2.b > 5 假设 t1 和 t2 都是 100 条数据。如果把 t1 和 t2 两个表做笛卡尔积了再过滤,我们要处理 10000 条数据,而如果能先做过滤条件,那么数据量就会大量减少。谓词下推会尽量把过滤条件,推到靠近叶子节点,从而减少数据访问,节省计算开销。这就是谓词下推的作用。谓词下推的接口函数类似是这样子的:func (p *baseLogicalPlan) PredicatePushDown(predicates []expression.Expression) ([]expression.Expression, LogicalPlan) PredicatePushDown 函数处理当前的查询计划 p,参数 predicates 表示要添加的过滤条件。函数返回值是无法下推的条件,以及生成的新 plan。这个函数会把能推的条件尽量往下推,推不下去的条件,做到一个 Selection 算子里面,然后连接在节点 p 上面,形成新的 plan。比如说现在有条件 a > 3 AND b = 5 AND c < d,其中 a > 3 和 b = 5 都推下去了,那剩下就接一个 c < d 的 Selection。我们看一下 Join 算子是如何做谓词下推的。代码是在 plan/predicate_push_down.go 文件。首先会做一个简化,将左外连接和右外连接转化为内连接。什么情况下外连接可以转内连接?左向外连接的结果集包括左表的所有行,而不仅仅是连接列所匹配的行。如果左表的某行在右表中没有匹配的行,则在结果集右边补 NULL。做谓词下推时,如果我们知道接下来的的谓词条件一定会把包含 NULL 的行全部都过滤掉,那么做外连接就没意义了,可以直接改写成内连接。什么情况会过滤掉 NULL 呢?比如,某个谓词的表达式用 NULL 计算后会得到 false;或者多个谓词用 AND 条件连接,其中一个会过滤 NULL;又或者用 OR 条件连接,其中每个都是过滤 NULL 的。术语里面 OR 条件连接叫做析取范式 DNF (disjunctive normal form)。对应的还有合取范式 CNF (conjunctive normal form)。TiDB 的代码里面用到这种缩写。能转成 inner join 的例子:select * from t1 left outer join t2 on t1.id = t2.id where t2.id != null; select * from t1 left outer join t2 on t1.id = t2.id where t2.id != null and t2.value > 3; 不能转成 inner join 的例子:select * from t1 left outer join t2 on t1.id = t2.id where t2.id != null or t2.value > 3; 接下来,把所有条件全收集起来,然后区分哪些是 Join 的等值条件,哪些是 Join 需要用到的条件,哪些全部来自于左子节点,哪些全部来自于右子节点。区分之后,对于内连接,可以把左条件,和右条件,分别向左右子节点下推。等值条件和其它条件保留在当前的 Join 算子中,剩下的返回。谓词下推不能推过 MaxOneRow 和 Limit 节点。因为先 Limit N 行,然后再做 Selection 操作,跟先做 Selection 操作,再 Limit N 行得到的结果是不一样的。比如数据是 1 到 100,先 Limit 10 再 Select 大于 5,得到的是 5 到 10,而先做 Selection 再做 Limit 得到的是 5 到 15。MaxOneRow 也是同理,跟 Limit 1 效果一样。DataSource 算子很简单,会直接把过滤条件加入到 CopTask 里面。最后会通过 coprocessor 推给 TiKV 去做。构建节点属性 在 build_key_info.go 文件里面,会构建 unique key 和 MaxOneRow 属性。这一步不是在做优化,但它是在构建优化过程需要用到的一些信息。build_key_info 是在收集关于唯一索引的信息。我们知道某些列是主键或者唯一索引列,这种情况该列不会存在多个相同的值。只有叶子节点记录这个信息。build_key_info 就是要将这个信息,从叶子节点,传递到 LogicalPlan 树上的所有节点,让每个节点都知道这些属性。 对于 DataSource,对于主键列,和唯一索引列,都是 unique key。注意处理 NULL,需要列是带有 NotNull 标记的。 对于 Projection,它的子节点中的唯一索引列信息,跟它的投影表达式的列取交集。比如 a b c 列都是唯一索引,投影其中的 b 列,输出的 b 列仍然具有值唯一的属性。如果一个节点输出肯定只有一行,这个节点会设置一个 MaxOneRow 属性。哪些情况节点输出只有一行呢? 如果一个算子的子节点是 MaxOneRow 算子 如果是 Limit 1,可以设置 MaxOneRow 如果是 Selection,并且过滤条件是一个唯一索引列等于某常量 Join 算子,如果它的左右子节点都是 MaxOneRow 属性 总结 这是基于规则优化(RBO)的上篇。介绍了逻辑查询计划里面基本的算子,以及一部分的优化规则。后续我们还将介绍更多的优化规则,以及基于代价的优化(CBO)。"}, {"url": "https://pingcap.com/weekly/2018-04-09-tidb-weekly/", "title": "Weekly update (April 02 ~ April 08, 2018)", "content": " Weekly update in TiDB Last week, we landed 28 PRs in the TiDB repositories.Added Support AdminCleanupIndex to clean up the dangling index Support AlterTableComment Add RawDeleteRange API Make session transaction isolation level take effect only once Fixed Fix row estimation for the pseudo unique key Fix row count estimation for the column with null values Fix the result of cast (0x10 as binary(2)) Fix zero value issue for binary type Merge BatchGet results to fix InsertIgnore in a transaction block Improved Track memory usage for NestedLoopApply Delete ranges when rolling back add index Optimize the insert executor on duplicate key update Upgrade mysql.db user column length to 32 Weekly update in TiSpark Last week, we landed 1 PR in the TiSpark repositories.Added Fix single read for count(1) case Weekly update in TiKV and PD Last week, we landed 9 PRs in the TiKV and PD repositories.Added Support compact_region by tikv-ctl Add ImportKVService Add raw batch put/get/delete/scan Fixed Fix OOM when receiving too many snapshots Improved Update MVCC debug structure New contributors (Thanks!) TiKV: Xiaoguang Sun Matt Friedman Docs: Valerian Pereira "}, {"url": "https://pingcap.com/meetup/meetup-20180404-no65/", "title": "【Infra Meetup No.65】「四美具,二难并」之成都行", "content": " 上周 Infra Meetup 走进了成都,来自 G7 汇通天下的廖强老师和来自 PingCAP 的申砾、孙浩老师,为大家带来了三个干货满满的 Talk 。 这是第二场走出帝都的 Meetup,场面依然火爆~「四美具,二难并」 成都,唯有美食与同道者不可辜负! 下午两点大家陆续进场,不得不说成都的同学们太热情了,场地差点坐不下,各式各样的椅子都被搬来了~等同学们坐定之后,PingCAP Engineering VP 申砾老师首先上台,深入讲解了 TiDB 的各项核心性能,让同学们对 TiDB 的架构和性能有了充分的认知。申砾:《Deep Dive into TiDB》 视频回顾 | Infra Meetup No.65 成都站:Deep Dive into TiDB(申砾) PingCAP Engineering VP 申砾 申砾老师从系统整体到技术细节,从核心项目到周边工具,介绍了 TiDB 的方方面面。 TiDB 的设计目标、核心特性以及整体架构。 系统分层介绍,包括分布式 Key-Value 存储引擎 TiKV 的核心技术及实现细节,分布式 SQL 引擎的设计思路以及优化器、执行引擎等核心组件的介绍。 Cloud TiDB、TiSpark 等核心项目以及 TiDB 集群的周边工具。 Q&A 环节:TiDB 在实践中的使用经验,TiDB 2.0 版本的最新进展以及如何实现性能上的巨大提升。 短暂休息之后,G7 汇通天下技术合伙人廖强老师讲述了他为什么选择了 TiDB ,以及 G7 的实践方案。廖强:《拥抱开源社区 - G7 TiDB 实践之路》  视频回顾 | Infra Meetup No.65 成都站:拥抱开源社区 - G7 TiDB 实践之路(廖强) G7 汇通天下技术合伙人 廖强 廖强老师主要从自己的工作经验出发,介绍了 TiDB 在 G7 业务实践中的细节。 介绍之前工作中在 MySQL Sharding 方案遇到的一些“坑”,以及早期使用开源技术碰到的问题和解决方案。 分享 G7 进行数据库选型的原则:业务层改动少,平滑迁移,掌控力强,稳定改进——TiDB 非常符合这个标准。G7 已经使用了 TiDB 很长时间,有非常丰富的迁移经验。因此,廖强老师进一步讲解了把 TiDB 从 MySQL 读库推进到完全使用 TiDB 作为业务库的流程,以及在此过程中需要注意的问题。 重点介绍 TiDB 的应用场景之一——金融风控,以及在场景中使用 TiDB 和 TiSpark 的情况。 分享参与开源的基本方法和步骤。 最后,由 PingCAP 资深解决方案架构师孙浩老师给大家分享了具有代表性的 TiDB 最佳实践,同学们对 TiDB 的开发和部署有了更加深入的感受,在 Talk 结束之后,也踊跃提问和讨论,气氛非常活跃~孙浩:《TiDB Best Practice》 视频回顾 | Infra Meetup No.65 成都站:TiDB Best Practice(孙浩) PingCAP 资深解决方案架构师 孙浩 孙浩老师从 TiDB 的基础知识出发,深入介绍了 TiDB 的部署最佳实践和开发最佳实践。 TiDB 适用场景、架构与部署以及其他基础概念。 以三个部署场景为例,解析大型 OLTP 和 OLTP / OLAP 混合型场景的需求、硬件配置等部署细节。 TiDB 的开发最佳实践,TiDB 外围接口与表设计,数据导入与写入实践,TiDB 生态工具的使用。 PingCAP Infra Meetup作为一个基础架构领域的前沿技术公司,PingCAP 希望能为国内真正关注技术本身的 Hackers 打造一个自由分享的平台。自 2016 年 3 月 5 日开始,我们定期在周六的上午举办 Infra Meetup,邀请业内大牛与大家深度探讨基础架构领域的前瞻性技术思考与经验。在这里,我们希望提供一个高水准的前沿技术讨论空间,让大家真正感受到自由的开源精神魅力。 "}, {"url": "https://pingcap.com/success-stories/tidb-in-mobike/", "title": "Blitzscaling the Largest Dockless Bikesharing Platform with TiDB’s Help", "content": " Industry: RidesharingData Growth Rate: ~30TB per dayAuthors: Chengjie Ding and Ming Hu (Infrastructure Platform Engineers at Mobike)Mobike is the world’s first and largest dockless bike-sharing provider, serving over 200 million users in 200 cities across the world, operating over 9 million smart bikes. It’s an affordable and convenient way of transportation for short urban trips, with a patented bike design with a smart lock system and a mobile app. We handle more than 30 million rides for our users every single day.The system behind the Mobike app collects over 30 TB of data daily from bikes equipped with GPS and IoT connected devices. The unprecedented growth in data volume and concurrency pose immense challenges on our backend system, especially our database. Thanks to TiDB, a distributed hybrid transactional and analytical processing (HTAP) database built by the PingCAP team, not only are we equipped with a solution that can elastically scale out horizontally, but we are also empowered to obtain insights from “fresh” data to support real-time decision-making. The vibrant TiDB open-source community also allows us to deploy and operate around the world without vendor lock-in. Now, we can easily support the rapid growth in our business and data without worrying about infrastructure.We have been using TiDB in our production environment since early 2017. Now we have deployed TiDB in multiple clusters with close to 100 nodes, handling dozens of TBs of data for different application scenarios. This post will provide a deep dive on why we chose TiDB over MySQL and its sharding solutions by illustrating how TiDB solves our pain points.Why TiDB? Before we chose TiDB, we carefully evaluated MySQL and its sharding solutions. As a fast-growing startup looking to scale quickly, we found MySQL sharding solutions undesirable for the following reasons: Standalone MySQL required us to archive data frequently. When the data size outgrew the capacity of a standalone MySQL, we had to shard the database and tables using middleware solutions, which was difficult to manage; Based on our previous experience with sharding, huge volumes of data often lead to a hung database, because it required frequent table structure updates to perform Data Definition Language (DDL) operations. This situation would negatively affect our application’s usability and even cause data inconsistency. In addition, we want the application logic to be upgraded more conveniently, despite of the service volume outburst and the changing service requirement, which cannot be done with sharding; If we went with the sharding solution, when it’s time to shard the database, we had to stop the on-going business, refactored the application code, and then migrated the data. What made things worse, we must carefully and manually specify the sharding key because it controls how the data should be distributed across the shards and changing an existing sharding key could cause serious problems. Not to mention that sharding does not support cross-shard distributed transactions, or no guarantee of the strong consistency of transactions. A new solution must be found to meet the following requirements: Online DDL: New services keep emerging, which brings constant DDL changes. We need to be able to add new columns and indices without database downtime. Elastic scalability: We need to cope with the rapid data growth and the temporary traffic surge brought by on-demand marketing campaigns by increasing the capacity at the peak time and decrease it when the campaigns are over. Support frequent correlated query and temporary query demands from the operational teams. Thankfully, TiDB more than fits the bill.Brief Overview of TiDB TiDB has the following core features: Compatibility with the MySQL protocol; Horizontal scalability; Distributed ACID transactions across multiple data centers; Strong consistency guarantees; Automatic failover and high availability. Inside the TiDB project, there are several components: TiDB cluster consists of stateless TiDB instances and serves as a stateless SQL layer that processes users’ SQL queries, accesses data in the storage layer, and returns corresponding results. TiKV cluster, composed of TiKV instances, is the distributed transactional Key-Value storage where the data resides. Regardless of whether the data comes, it is stored in TiKV eventually. It uses the Raft protocol for replication to ensure data consistency and disaster recovery. TiSpark sits right on top of TiKV to support both our data scientists for real-time analysis or for offline daily analysis in the existing Hadoop system. The TiDB ecosystem also has a wealth of other enterprise-level tools, such as the Ansible scripts for quick deployment, Syncer for seamless migration from MySQL, Wormhole for migrating heterogeneous data, and TiDB-Binlog, which is a tool to collect binlog files.Four In-Production Applications Case 1: Success rate of locking and unlocking The success rate of locking and unlocking a smart bike is one of the key metrics for Mobike, because failure to lock/unlock will cause bad user experience and even user attrition. To deliver a smooth experience, we need constant insights on the lock/unlock success rate based on regions, application versions, terminals, users, and bikes to locate the bikes with issues. Each time users lock or unlock bikes, usually during rush hours, massive log information of the bike is being generated. This data volume is estimated to be tens of billions of rows per year.We deploy TiDB to directly help support the system behind the success rate of locking and unlocking, which fulfills all the above requirements. See the following diagram for how TiDB is integrated in our system:With TiDB, alert is sent to the administrators when the system detects a success rate drop of locking and unlocking within minutes. We can quickly find a single failed ride and the associated user and bike from the database, which allow us to locate the faulty bike quickly.Case 2: Real-Time Data Analysis As our data volume continues to grow exponentially, we need accessible and accurate real-time data analysis to keep our competitive edge vis-a-vis other bikesharing platforms. Before we implemented TiDB, we had several dozens MySQL clusters, some of which are sharded databases, while others are standalone instances. But MySQL was not designed for processing complicated queries against massive datasets, which made real-time data analysis all the more challenging.To meet this challenge, our initial plan was to synchronize data to Hive. We came up with two methods, but each had significant drawbacks: Full volume synchronization on a daily basis. This method would result in high pressure for the online databases and consume huge amounts of Hive resource as time goes on. Incremental synchronization on a daily basis. This approach was complex, given that the daily differences should be merged with the preceding day’s data, because HDFS does not support an update operation. The advantage of this method was that if the data size is large, incremental synchronization is faster and saves more space than full synchronization. The disadvantage is that incremental synchronization occupies a lot of Hadoop’s computing resources, which affects the system’s stability. Instead with TiDB, real-time data synchronization can be performed from multiple MySQL instances with tools designed specifically for the MySQL ecosystem. Syncer, which we mentioned before, enabled us to synchronize our TiDB cluster with various MySQL instances and the sharded MySQL clusters. TiDB supports the update operation, so it does not have the same issues Hive has. With TiSpark in the mix, which is a thin layer built for running Apache Spark on top of TiDB/TiKV, we can leverage Spark to quickly run complex OLAP queries immediately after data is imported to TiDB.The following diagram depicts our implementation of a real-time data …"}, {"url": "https://pingcap.com/weekly/2018-04-02-tidb-weekly/", "title": "Weekly update (March 26 ~ April 01, 2018)", "content": " Weekly update in TiDB Last week, we landed 49 PRs in the TiDB repositories.Added Support show grants for current_user(); Add manual GC back for some KV API users Support using decimal in INTERNAL Fixed Fix an unsigned decimal Fix a potential goroutine leak problem in copIterator Fix the AdminCheckTable bug when the column is nil and has a default value Fix type infer for the binary literal Fix a bug that lexer.Reset() cannot be reset to the initial state Handle the truncate error in BinaryLiteral.ToInt Fix a bug when applying the top-n push down rule Improved Recover a panic in adding index workers Improve performance of DecodeBytes in DecodeOneToChunk Use scientific notation to format float value Check the gRPC error message before returning a critical error Weekly update in TiSpark Last week, we landed 6 PRs in the TiSpark repositories.Fixed Fix excessive dag columns Fix estimatedRowCount when the pushdown predicate is not present Weekly update in TiKV and PD Last week, we landed 21 PRs in the TiKV and PD repositories.Added Add import-mode arguments to tune configurations for importing data Add RegionOption for picking Region randomly Add the diagnose API Set eval_warnings in SelectResponse.warnings or StreamResponse.warnings Clean up obsoleted SST files periodically Initiate the half split Region Support admin splitting Region Fixed Remove redundant configuration Fix the bug of ThreadSafeCache Get method lock Fix metrics of the replica checker Fix a bug of config show all Improved Relax the abnormal leader missing check Make sending snapshots asynchronous in a CpuPool Avoid passing CpuPool into OnResponse New contributors (Thanks!) TiDB: chenyangyang 何晨 康晓宁 TiKV: ShalokShalom "}, {"url": "https://pingcap.com/blog-cn/tidb-source-code-reading-6/", "title": "TiDB 源码阅读系列文章(六)Select 语句概览", "content": " 在先前的 TiDB 源码阅读系列文章(四) 中,我们介绍了 Insert 语句,想必大家已经了解了 TiDB 是如何写入数据,本篇文章介绍一下 Select 语句是如何执行。相比 Insert,Select 语句的执行流程会更复杂,本篇文章会第一次进入优化器、Coprocessor 模块进行介绍。表结构和语句 表结构沿用上篇文章的:CREATE TABLE t { id VARCHAR(31), name VARCHAR(50), age int, key id_idx (id) }; Select 语句只会讲解最简单的情况:全表扫描+过滤,暂时不考虑索引等复杂情况,更复杂的情况会在后续章节中介绍。语句为:SELECT name FROM t WHERE age > 10; 语句处理流程 相比 Insert 的处理流程,Select 的处理流程中有 3 个明显的不同: 需要经过 OptimizeInsert 是比较简单语句,在查询计划这块并不能做什么事情(对于 Insert into Select 语句这种,实际上只对 Select 进行优化),而 Select 语句可能会无比复杂,不同的查询计划之间性能天差地别,需要非常仔细的进行优化。 需要和存储引擎中的计算模块交互Insert 语句只涉及对 Key-Value 的 Set 操作,Select 语句可能要查询大量的数据,如果通过 KV 接口操作存储引擎,会过于低效,必须要通过计算下推的方式,将计算逻辑发送到存储节点,就近进行处理。 需要对客户端返回结果集数据Insert 语句只需要返回是否成功以及插入了多少行即可,而 Select 语句需要返回结果集。 本篇文章会重点说明这些不同的地方,而相同的步骤会尽量化简。Parsing Select 语句的语法解析规则在 这里。相比 Insert 语句,要复杂很多,大家可以对着 MySQL 文档 看一下具体的解析实现。需要特别注意的是 From 字段,这里可能会非常复杂,其语法定义是递归的。最终语句被解析成 ast.SelectStmt 结构:type SelectStmt struct { dmlNode resultSetNode // SelectStmtOpts wraps around select hints and switches. *SelectStmtOpts // Distinct represents whether the select has distinct option. Distinct bool // From is the from clause of the query. From *TableRefsClause // Where is the where clause in select statement. Where ExprNode // Fields is the select expression list. Fields *FieldList // GroupBy is the group by expression list. GroupBy *GroupByClause // Having is the having condition. Having *HavingClause // OrderBy is the ordering expression list. OrderBy *OrderByClause // Limit is the limit clause. Limit *Limit // LockTp is the lock type LockTp SelectLockType // TableHints represents the level Optimizer Hint TableHints [](#)*TableOptimizerHint } 对于本文所提到的语句 SELECT name FROM t WHERE age > 10;  name 会被解析为 Fields,WHERE age > 10 被解析为 Where 字段,FROM t 被解析为 From 字段。Planning 在 planBuilder.buildSelect() 方法中,我们可以看到 ast.SelectStmt 是如何转换成一个 plan 树,最终的结果是一个 LogicalPlan,每一个语法元素都被转换成一个逻辑查询计划单元,例如 WHERE c > 10 会被处理为一个 plan.LogicalSelection 的结构:if sel.Where != nil { p = b.buildSelection(p, sel.Where, nil) if b.err != nil { return nil } }  具体的结构如下:// LogicalSelection represents a where or having predicate. type LogicalSelection struct { baseLogicalPlan // Originally the WHERE or ON condition is parsed into a single expression, // but after we converted to CNF(Conjunctive normal form), it can be // split into a list of AND conditions. Conditions []expression.Expression } 其中最重要的就是这个 Conditions 字段,代表了 Where 语句需要计算的表达式,这个表达式求值结果为 True 的时候,表明这一行符合条件。其他字段的 AST 转 LogicalPlan 读者可以自行研究一下,经过这个 buildSelect() 函数后,AST 变成一个 Plan 的树状结构树,下一步会在这个结构上进行优化。Optimizing 让我们回到 plan.Optimize() 函数,Select 语句得到的 Plan 是一个 LogicalPlan,所以 这里 可以进入 doOptimize 这个函数,这个函数比较短,其内容如下:func doOptimize(flag uint64, logic LogicalPlan) (PhysicalPlan, error) { logic, err := logicalOptimize(flag, logic) if err != nil { return nil, errors.Trace(err) } if !AllowCartesianProduct && existsCartesianProduct(logic) { return nil, errors.Trace(ErrCartesianProductUnsupported) } physical, err := dagPhysicalOptimize(logic) if err != nil { return nil, errors.Trace(err) } finalPlan := eliminatePhysicalProjection(physical) return finalPlan, nil } 大家可以关注两个步骤:logicalOptimize 和 dagPhysicalOptimize,分别代表逻辑优化和物理优化,这两种优化的基本概念和区别本文不会描述,请大家自行研究(这个是数据库的基础知识)。下面分别介绍一下这两个函数做了什么事情。逻辑优化 逻辑优化由一系列优化规则组成,对于这些规则会按顺序不断应用到传入的 LogicalPlan Tree 中,见 logicalOptimize() 函数:func logicalOptimize(flag uint64, logic LogicalPlan) (LogicalPlan, error) { var err error for i, rule := range optRuleList { // The order of flags is same as the order of optRule in the list. // We use a bitmask to record which opt rules should be used. If the i-th bit is 1, it means we should // apply i-th optimizing rule. if flag&(1<<uint(i)) == 0 { continue } logic, err = rule.optimize(logic) if err != nil { return nil, errors.Trace(err) } } return logic, errors.Trace(err) } 目前 TiDB 已经支持下列优化规则:var optRuleList = []logicalOptRule{ &columnPruner{}, &maxMinEliminator{}, &projectionEliminater{}, &buildKeySolver{}, &decorrelateSolver{}, &ppdSolver{}, &aggregationOptimizer{}, &pushDownTopNOptimizer{}, } 这些规则并不会考虑数据的分布,直接无脑的操作 Plan 树,因为大多数规则应用之后,一定会得到更好的 Plan(不过上面有一个规则并不一定会更好,读者可以想一下是哪个)。这里选一个规则介绍一下,其他优化规则请读者自行研究或者是等待后续文章。columnPruner(列裁剪) 规则,会将不需要的列裁剪掉,考虑这个 SQL: select c from t; 对于 from t 这个全表扫描算子(也可能是索引扫描)来说,只需要对外返回 c 这一列的数据即可,这里就是通过列裁剪这个规则实现,整个 Plan 树从树根到叶子节点递归调用这个规则,每层节点只保留上面节点所需要的列即可。经过逻辑优化,我们可以得到这样一个查询计划:其中 FROM t 变成了 DataSource 算子,WHERE age > 10 变成了 Selection 算子,这里留一个思考题,SELECT name 中的列选择去哪里了?物理优化 在物理优化阶段,会考虑数据的分布,决定如何选择物理算子,比如对于 FROM t WHERE age > 10 这个语句,假设在 age 字段上有索引,需要考虑是通过 TableScan + Filter 的方式快还是通过 IndexScan 的方式比较快,这个选择取决于统计信息,也就是 age > 10 这个条件究竟能过滤掉多少数据。我们看一下 dagPhysicalOptimize 这个函数:func dagPhysicalOptimize(logic LogicalPlan) (PhysicalPlan, error) { logic.preparePossibleProperties() logic.deriveStats() t, err := logic.convert2PhysicalPlan(&requiredProp{taskTp: rootTaskType, expectedCnt: math.MaxFloat64}) if err != nil { return nil, errors.Trace(err) } p := t.plan() p.ResolveIndices() return p, nil } 这里的 convert2PhysicalPlan 会递归调用下层节点的 convert2PhysicalPlan 方法,生成物理算子并且估算其代价,然后从中选择代价最小的方案,这两个函数比较重要:// convert2PhysicalPlan implements LogicalPlan interface. func (p *baseLogicalPlan) convert2PhysicalPlan(prop *requiredProp) (t task, err error) { // Look up the task with this prop in the task map. // It's used to reduce double counting. t = p.getTask(prop) if t != nil { return t, nil } t = invalidTask if prop.taskTp != rootTaskType { // Currently all plan cannot totally push down. p.storeTask(prop, t) return t, nil } for _, pp := range p.self.genPhysPlansByReqProp(prop) { t, err = p.getBestTask(t, pp) if err != nil { return nil, errors.Trace(err) } } p.storeTask(prop, t) return t, nil } func (p *baseLogicalPlan) getBestTask(bestTask task, pp PhysicalPlan) (task, error) { tasks := make([]task, 0, len(p.children)) for i, child := range p.children { childTask, err := child.convert2PhysicalPlan(pp.getChildReqProps(i)) if err != nil { return nil, errors.Trace(err) } tasks = append(tasks, childTask) } resultTask := pp.attach2Task(tasks...) if resultTask.cost() < bestTask.cost() { bestTask = resultTask } return bestTask, nil } 上面两个方法的返回值都是一个叫 task 的结构,而不是物理计划,这里引入一个概念,叫 Task,TiDB 的优化器会将 PhysicalPlan 打包成为 Task。Task 的定义在 task.go 中,我们看一下注释:// task is a new version of `PhysicalPlanInfo`. It stores cost information for a task. // A task may be CopTask, RootTask, MPPTask or a ParallelTask. type task interface { count() float64 addCost(cost float64) cost() float64 copy() task plan() PhysicalPlan invalid() bool } 在 TiDB 中,Task 的定义是能在单个节点上不依赖于和其他节点进行数据交换即可进行的一系列操作,目前只实现了两种 Task: CopTask 是需要下推到存储引擎(TiKV)上进行计算的物理计划,每个收到请求的 TiKV 节点都会做相同的操作 RootTask 是保留在 TiDB 中进行计算的那部分物理计划 如果了解过 TiDB 的 Explain 结果,那么可以看到每个 Operator 都会标明属于哪种 Task,比如下面这个例子:整个流程是一个树形动态规划的算法,大家有兴趣可以跟一下相关的代码自行研究或者等待后续的文章。经过整个优化过程,我们已经得到一个物理查询计划,这个 SELECT name FROM t WHERE age > 10; 语句能够指定出来的查询计划大概是这样子的:读者可能会比较奇怪,为什么只剩下这样一个物理算子?WHERR age > 10 哪里去了?实际上 age > 10 这个过滤条件被合并进了 PhysicalTableScan,因为 age > 10 这个表达式可以下推到 TiKV 上进行计算,所以会把 TableScan 和 Filter 这样两个操作合在一起。哪些表达式会被下推到 TiKV 上的 Coprocessor 模块进行计算呢?对于这个 Query 是在下面 这个地方 进行识别:// PredicatePushDown implements LogicalPlan PredicatePushDown interface. func (ds *DataSource) PredicatePushDown(predicates []expression.Expression) ([]expression.Expression, LogicalPlan) { _, ds.pushedDownConds, predicates = expression.ExpressionsToPB(ds.ctx.GetSessionVars().StmtCtx, predicates, ds.ctx.GetClient()) return predicates, ds } 在 expression.ExpressionsToPB 这个方法中,会把能下推 TiKV 上的表达式识别出来(TiKV 还没有实现所有的表达式,特别是内建函数只实现了一部分),放到 DataSource.pushedDownConds 字段中。接下来我们看一下 DataSource 是如何转成 PhysicalTableScan,见 DataSource.convertToTableScan() 方法。这个方法会构建出 PhysicalTableScan,并且调用 addPushDownSelection() 方法,将一个 PhysicalSelection 加到 PhysicalTableScan 之上,一起放进 copTask 中。这个查询计划是一个非常简单的计划,不过我们可以用这个计划来说明 TiDB 是如何执行查询操作。Executing 一个查询计划如何变成一个可执行的结构以及如何驱动这个结构执行查询已经在前面的两篇文章中做了描述,这里不再敷述,这一节我会重点介绍具体的执行过程以及 TiDB 的分布式执行框架。Coprocessor 框架 Coprocessor 这个概念是从 HBase 中借 …"}, {"url": "https://pingcap.com/blog-cn/tidb-tools-ecosystems/", "title": "刘寅:TiDB 工具链和生态", "content": " 本文为今年年初 PingCAP 商业产品团队负责人刘寅在 TiDB DevCon2018 上分享的 《 TiDB 工具链和生态》实录内容,文内详细介绍了 TiDB 的周边工具以及生态系统。enjoy~ 大家下午好,我叫刘寅。在 PingCAP 主要负责 TiDB 商业工具产品开发,也在做公司 SRE 方面的事情。今天下午我分享的主题是介绍下 TiDB 的周边工具以及生态系统。今天要讲的内容主要包含这几方面,首先是关于 TiDB 的部署,这是很多使用 TiDB 的用户首先关心的事情。接下来会介绍 TiDB 的数据导入工具和数据迁移同步工具,以及管理配置,数据可视化相关的工具。TiDB 的架构可能大家都比较清楚了。TiDB 是一个由若干模块组成的分布式系统。这些模块相互依赖协调工作组成一个集群,整体构成了 TiDB 数据库。这样一个架构,对于用户进行部署和运维,其复杂程度相对单机数据库比如 MySQL 来说不那么容易的事情。那让我们来看看如何快速部署一套 TiDB 集群实例。最近我们公开了一个项目 pingcap/tidb-docker-compose,这令我们在一个本地的开发和测试环境上跑一套 TiDB 变得非常简单。只需要用一个命令 docker-compose up 就能快速启动起来。docker-compose 是 Docker 生态中的一个非常便利的工具,它可以在本机方便的把 TiDB 的各个组件,包括它的监控,可视化工具,全部整合在一个 yaml 文件来描述,非常的方便。不仅可以通过我们官方 docker image 镜像启动,也可以支持从本地的 binary 启动。比如当我本机编译了一个特殊版本的 binary,我就可以直接构建本地镜像来启动,甚至还可以支持现场编译源码来启动。所以这对于我们自己开发和测试也是非常方便的。另外我们也做了一个很简化的配置文件,比如我不希望默认跑 3 个 TiKV,我想启 5 个或者更多,简单的改下配置就可以搞定。对于生产环境的部署和运维,往往面对的是一个成规模的集群,docker-compose 的部署方式就不够了。我们建议采用提供的 Ansible 部署方式。用户首先在一个 Inventory 文件中描述和编排所需的 TiDB 集群拓扑,然后执行我们提供的 ansible-playbook 脚本,就可以快速部署和运维一个生产环境下的 TiDB 集群。我们现在很多的线上用户,也是用了这样的部署方式。TiDB Ansible 不仅实现在裸机上部署集群,同时也支持 Cloud 的部署方式。比如说用 Ansible 提供的组件,我们可以基于 AWS / Azure / GCP 上一键创建 TiDB 的集群,而将来也会支持国内的公有云平台。其次可以根据用户需求,定制集群的拓扑。这个比较细,也会包含 TiDB 的一些周边工具的部署,比如说 TiDB Binlog 组件。第三,它提供一个配置管理的功能,包括 TiDB、TiKV 很多的参数配置。我们也集成进去,可以在一个地方统一管理整个集群的配置。除此之外,我们对运维操作的执行脚本做了一系列的优化。这样对于在部署一个规模庞大的集群会变得及其方便。另外这里顺便还要提一下,我们在 Ansible 部署过程中,我们会对硬件和系统环境做一个严格的检查。可能有些用户出于测试的目的,使用较低速的机械硬盘,而达不到跑 TiDB 的最低要求。所以这里,我们会有限定要求,会在安装过程中交互提示出来。TiDB 作为一个可以弹性水平扩展的分布式数据库,天生为云而设计,从初期我们就和容器走的非常近。容器的优势,相信大家都非常了解。首先,它提供了一致化的环境,用户不需要去适应各种不同的系统环境,而分别构建运行时 Binary。另外容器的启动运行非常方便,可以很快速的在开发环境运行或者生产环境部署。另外容器提供了资源隔离的特性,通过 Namespace 和 CGroups 这些现代操作系统提供的能力,来实现容器内部和外部的资源隔离和限制。说到容器就不得不提容器编排,TiDB 在与 K8s 的整合方面我们做了非常多的事情。比如在 K8s 之上实现对 TiDB 集群的自动化管理,快速部署、扩缩容、以及故障的自动愈合。同时更好的支持云平台下的多租户管理,通过限制单个租户的资源的使用,利用容器完成隔离。来保证租户之间不会相互影响。不至于说一个用户执行高负载的查询或者写入,对同一台宿主机上的其他用户实例造成影响。然而 TiDB 存储本身是有状态的,在 K8s 上部署的时候,如何管理好有状态的服务,并且保证存储的 iops 和延迟方面苛刻的要求,同时还要保证服务的高可用性就成为一个难题。如果采用 K8s 提供的 native 存储解决方案,外挂 PV,也就是挂网络存储。但是这样对于数据库系统来说,尤其是大量的随机读和顺序写的场景下,网络盘的性能是达不到要求的。所以说从最开始我们设计 TiDB 上云解决方案,其实主要就是探索 K8s 的本地 PV 解决方案。当然现在 K8s 1.9 已经开始对 Local PV 有一定支持,而我们在 1.7 的时候就实现了一个 Local Storage Manager。我们现在做的一些工作,也逐渐在和社区 K8s 主版本进行整合。另外 TiDB 本身是一个复杂集群,除了存储还有网络,以及周边工具的管理都需要考虑。为了实现将专业领域的运维管理变的更加自动化,我们造了 TiDB Operator。Operator 这个 pattern 其实是最初借鉴 CoreOS 的 Etcd Operator。TiDB Operator 就是降低 TiDB 部署和运维的复杂度,实现自动化的扩缩容和故障转移。同时 Operator 在 K8s 上同时管理多套 TiDB 集群,像在腾讯云和 UCloud 两个公有云上,就是用这种方式来实现多租户统一化管理。我们实现的 Local PV 管理机制,实质上是对集群中所有本地磁盘的统一管理,并赋予他们生命周期,从而作为 K8s 中的一类资源参与调度。同时新版本 K8s 的趋势上,在往云上的操作系统方向上发展,自身的资源以及 API 变的更加开放。我们不需要去改动 K8s 本身的代码,而是去做更好的扩展,来实现满足自己的调度功能。比如说我们利用 K8s 亲和性的特点,让同种类型的服务运行在同一台物理机上,更充分的利用硬件资源。再比如说 PD 和 TiKV 这两种服务,你不能在一起混部使用同一块 SSD,否则 IO 会相互影响。所以我们利用反亲和的特性,让 PD 和 TiKV 调度的时候尽量分开。另外再举一个调度的例子,TiDB 集群本身是支持区分节点的地域属性的,PD 根据地域属性来实现数据层面的调度,并且尽量保证同一份数据的多个副本尽可能按地域分散开。那么 K8s 部署 TiDB 节点的时候,也需要考虑地域特征来进行调度。比如按照跨 Region、跨可用区将一个集群的节点分散部署,并且把地域的信息传递给 TiKV 和 PD,使数据副本尽量分散。而这个知识本身 K8s 是不具备的,我们需要扩展 K8s 的调度器把经验和原则传递进去。Operator 包含一些 TiDB 扩展的 Controller 和 Scheduler,但还不够,我们需要在上面包装一层,以暴露出来统一的运维和管理接口,这就是 Cloud Manager。Cloud Manager 对外暴露标准化的接口,用于和云平台的前端控制台对接,这样就通过前台可以完成 K8s 以及 TiDB 集群的相关资源的综合管理。DBaaS 结构图可以看到 Cloud TiDB 的分层架构。最下层是容器云,中间一层是 K8s 自身的服务管理和 API Server。我们在此基础上进行扩展,实现各种 Controller 和调度器,自己本地存储管理 Volume Manager,最终通过 Cloud Manager 提供的 RESTful API 进行暴露。可以很容易接一个前端的 Dashboard,或者直接使用 CLI 命令行工具,完成 TiDB 集群实例的统一化管理。这个图就是前面讲的一些细节。这里面可以看到,左半边是 Kube 本身的组件,右侧是我们的扩展出来组件,另外,我们也自己定义了一些 TiDB 的资源类型放在 CDR 里面。比如说 TiDB Cluster,在这个资源对象上可以描述要启动多少个 TiKV,多少个 TiDB。另外还有 TiDB Set / TiKV Set / PD Set 等一系列对象,来分别描述某个服务的配置。这是在腾讯云上面的一个截图,现在这两个产品都在公测,这是UCloud的截图有兴趣的同学可以关注一下。此外,我们提供了 Operator Chart 的安装方式,使用 Helm 工具可以一键通过 Operator 拉起来一套 TiDB 实例。这种方式在 K8s 上就更像是一个 RPM 包的方式部署服务,并且管理服务之间依赖。只需要一行命令,就可以获得到官方的 Cloud TiDB 的核心组件。如果你有一个 K8s 集群,或者你在使用一个公有云提供的 K8s 集群,用上面的命令,就可以快速运行 TiDB Operator 和 TiDB 集群。这是一个配置的例子,打开 charts 压缩包可以找到对应的配置 yaml 文件。我们对每一行的配置做了详细的注释。比如可以设定一些参数:像副本数、CPU 内存使用限制、TiDB 起多少个、TiKV 起多少个,等等。部署工具就先介绍这么多。下一部分,我们开始介绍一下 TiDB 周边的工具,其实这里面有一些大家已经接触和使用过了。首先是 Syncer,这个小工具在很多生产环境上已经用起来了。它是一个 MySQL 到 TiDB 间的实时同步工具。原理很简单,就是把自己伪装成一个 MySQL 的 Slave 库,从上游 MySQL 里面把 binlog 实时 dump 出来,并且还原成 SQL 到下游(TiDB)回放。这里我们支持简单的规则过滤,也支持分库分表的合并。我们也可以同时跑多个 Syncer 把多个上游 MySQL,按库同步到一个大的 TiDB 集群。Syncer 的主要一些特性,首先是要支持按 GTID 同步。GTID 是什么?它是 MySQL 自身的 replication 机制提供的一种特性。MySQL 主从同步最早是以 binlog pos(文件名+offset)来描述同步位置,但这个设计有明显的缺陷,比如说这样一个场景,最初是 1 个 Master 带 2 个 Slaves,当 Master 挂了这时需要把一个 Slave 升级为 Master,另一个 Slave 从新 Master 继续同步。但这样就要保证,新的 Master 和旧 Master 的 binlog pos 能接续上,但是 MySQL 不同实例的 binlog 记录方式是不同的,因此必须有一个全局唯一 ID 来和 binlog 对应上,这就是 GTID。在 MySQL 5.6 之后 GTID 支持的就比较好了,生产环境大多是开启了这种方式。Syncer 除了支持按 pos 同步,也支持 GTID。Syncer 从公有云的 RDS 同步支持的都比较好,比如像阿里云、腾讯云我们测的也比较多,因为云平台后端机器故障或者维护,主从切换比较频繁,而且 Virtual IP 还保持不变对用户无感知,所以假如 Syncer 不能很好支持 GTID 的话那切一次主从数据就会不一致了。第二是分库分表合并。不管上游库是按库拆,按表拆,甚至混合拆分,Syncer 都能很好支持,通过配置文件描述出来。另外还有同步性能的问题,因为 binlog 是一个单向数据流,我们同步的时候如果是单线程来做虽然比较简单,但性能可能很差。使用多线程,就必须区分对同一行数据操作的因果顺序,没有关联关系的行可以并行执行,有关联的行只能顺序执行。对于 MySQL 每一个 binlog event 都是一个事务,他里面会包含对不同表,不同行的多次操作。所以 Syncer 会对事务进行拆分,然后并行执行。这样的代价是 Syncer 不保证按上游的事务原子性来同步,但最终一致性没有问题。Syncer 也支持一些简单的过滤规则,可以选择指定库或者表同步,也可以做排除。另外也支持一些简单的表名映射变换。在一个公司初期,可能业务铺的比较快,每块业务用一个 MySQL 库,不同的业务之间数据是隔离的。后来业务复杂了,可能 MySQL 要挂从库了。从库专门用于一些数据分析的场景,而不能影响主库支撑线上的读写。随着进一步的发展,数据分析可能要跨业务线,那么跨库进行统计查询,比如 Join 和 Sub Query 这样的操作基本上很难。这个场景下我们可以把一个 TiDB 集群作为所有线上 MySQL 的 Slave,而使用 Syncer 完成同步。数据分析团队可以在 TiDB 中完成复杂的关联查询和分析,这跟使用 MySQL 没有什么区别。而且 Syncer 同步的实时性很高,使后端的分析可以做到非常的实时。接下来我们介绍一下 TiDB Binlog。TiDB Binlog 本质上不同于 MySQL,这个要声明一下,我们的 binlog 跟 MySQL 的 binlog 格式不同,TiDB 采用一种自描述的 protobuf 格式的 binlog。而每个 TiDB Server,都会写自己的 binlog,一个事务就是一个 binlog event。然后通过一个叫作 Pump 的小程序,汇总写入到 Kafka 集群。Pump 直接写本地就好了,为什么还要用 Kafka?这是考虑到 log 落本地盘会有单点故障的风险。所以采用 Kafka 或者一个分布式文件系统来解决这个问题。在下游有一个叫 Drainer 的组件来消费 Kafka 的数据。Drainer 的职责是将 binlog 按照事务的顺序还原成 SQL,同步到下游数据库,比如 MySQL,也可能是另外一个 TiDB 集群,还可以写到文件流实现增量数据备份。其实 Drainer 做的事情是有一些难度的,因为 TiDB 不像 MySQL,他是一个分布式系统,大家可以思考一下。首先,怎么保证事务的完整性,什么意思呢,因为 TiDB 的事务大家都知道是两阶段事务。那么有可能事务提交成功,但是 binlog 没有写成功;也有可能事务没有写成功但是 binlog 发出去了,这两种情况都可能导致不一致。第二点,如何来还原分布式事务之间的因果顺序。TiDB 事务是提交到 TiKV 上来执行,每个事务又是两阶段,事务的顺序号是由 PD 产生,在同一个 TiDB 节点上可能会并发执行多个事务,所以产生的 binlog 的事务 seq 不能保证单调递增,那如何还原顺序并实时输出。第三点,网络本身可能也是不可靠的,你可能写到 TiDB 是前一个事务在前,一个在后。而在网络传输的过程中,顺序可能变化。在多机都在产生 binlog 的情况下,最终落到 Drainer 的顺序是错乱的,那么如何进行顺序还原。这个似乎跟 TCP 有点像,但又不太一样。在 TiDB 里面事务的全局顺序编号并不是连续递增,所以说当 Drainer 收到了一个 binlog 的时候,永远不知道下一个 binlog 的事务编号是多少。至于实现,我们设计了一个比较复杂的动态窗口算法。时间关系我就不展开讲,大家有兴趣可以思考一下,欢迎线下讨论。在场景方面,我们用 TiDB Binlog 可以做很多事儿。比如在 TiDB 集群上再挂一个从集群。也可以同步到 MySQL 做从库。像一些客户在线上初期开始使用 TiDB 可能会比较谨慎,开始把 TiDB 通过 Syncer 挂到 MySQL 的后面做一个从库,跑一段时间验证觉得没有问题,就可以把它调换一下。TiDB 成为主库,用 binlog 去反向同步到 MySQL。再跑一段时间觉得 OK 了很安全,就可以把 MySQL 从库摘下来,这样就完成了一个灰度上线的过程。此外我们还可以用 binlog 去同步其他异构数据库,或者一些数据仓库、或者分布式存储产品。包括我们也在研发自己的 OLAP 的存储引擎。将来都是通过 binlog 来完成数据实时同步。只需要给 Drainer 写不同的 Adapter 插件即可。TiDB Binlog 还可以用于数据增量备份,可以找到最近的一个全量备份点,然后回放这段时间的 Binlog,就可以还原到任意时间点的数据状态。另外还有一些场景,比如说有的公司业务希望在 binlog 基础上实现事件订阅。我们可以通过监听 binlog,当监测到某个业务数据发生变化的时候往 Kafka 里面触发一条消息,类似实现 trigger 的功能。binlog 本身是描述成一种通用的 protobuf 格式,也可以用来驱动流式计算引擎,来实现一些异步/流式分析需求。Binlog 的使用场景非常广泛,可以在实际业务中灵活发挥。另外介绍一个工具就是 Lightning, Lightning可能大家都没有用到过,因为我们还在最后的测试和优化阶段,这是一个快速的 TiDB 导入工具,之前我们提供的工具是 MyDumper,MyDumper 是 MySQL 通用的一个数据导出的工具。它同时还有一个 MyLoader,我们在这个基础上又做了一个 TiDB Loader,但这个东西本质上还是去执行 SQL。就是说 MyDumper 输出的数据文件是很多的 SQL 文本。那么用 Loader 导入到 TiDB 这个过程中大家可能会觉得导数据比较慢。这是因为这种方式的数据导入,TiKV 底层存储的 region 要不断的分裂和搬移,而且一般顺序写数据,表的主键往往是递增的,这样会导致写入热点,不能同时把所有 TiKV 节点都调动起来,失去了分布式的优势。那么 Lightning 是怎么做的呢?首先我们会直接把输入的数据格式绕过 SQL 解析器和优化器直接转换成有序的 KV 键值对,并分批进行处理,根据 PD 预先计算好新插入数据的 Region 分布,然后直接生成 SST 文件 Ingest 到 TiKV 中,非常接近物理数据导入。我们在内部测试比之前的 Loader 方式要快 7 到 10 倍,1T 的数据将近在 5 个小时之内完成导入,预计很快会跟大家见面。MyDumper 格式的文件作为输入,首先完成 SQL 到 KV 的转换,它是由若干分布式 worker 来完成,多机并行执行。同时绕过了优化器,生成连续的 KV 流,再通过一个专门的 Ingest Server 对 KV 进行全局排序。同时可以预计算 region,通过 PD 提前安排调度到哪个节点,所以整个的流程是非常高效的。接下来介绍一个我们商业化工具,叫作 Wormhole。这个可以理解为是一个带控制面板的 Syncer,但比 Syncer 强大。它支持多源多目的地的数据同步。而且本身也是分布式结构,具有高可用、并行执行的特点。另外它对于分库分表支持的更好,配置可视化。在同步前检查也更为严格,比如说同步 MySQL,会提前检查表结构和 TiDB 的兼容性,是否开启 row 模式的 binlog 等等,避免在运行过程中发现了再报异常。另外 Wormhole …"}, {"url": "https://pingcap.com/weekly/2018-03-26-tidb-weekly/", "title": "Weekly update (March 19 ~ March 25, 2018)", "content": " Weekly update in TiDB Last week, we landed 35 PRs in the TiDB repositories.Added Add the average column size for histogram Support STRAIGHT_JOIN to disable join reordering Add the AdminChecksumTable command Show Region key’s record ID or index values Fixed Support converting json to float64 Fix incompatible behavior when modifying value from Navicat GUI Fix panic by cloning the predicates of UnionScan Fix the syntax error on set transaction isolation level serializable Fix a data race on the concurrent access of Tracker.children Fix a data race for the SelectForUpdate executor Improved Speed up adding index for discrete tables Refactor MergeJoin Fill the TABLE_ROWS field of information_schema.TABLES with the information from statistics Weekly update in TiSpark Last week, we landed 4 PRs in the TiSpark repositories.Fixed Fix the range of the prefix index Fix the bucket loading issue Weekly update in TiKV and PD Last week, we landed 26 PRs in the TiKV and PD repositories.Added Dump the snapshot meta file Modify the TiKV configuration dynamically Implement the checksum push down request Support Region merging Add the checker for Region merging Support TiKV recovering services from the unsafe state of the majority failure of replicas Fixed Replace %I with %H Transfer the leader to the new peer when scattering Regions Improved Improve the balance-region scheduler Improve the balance-leader scheduler Simplify the shuffle-leader scheduler Inform PD ASAP after new peers are not pending any more Use delete range by default Pick the hot Region from the store randomly Refactor the worker with crossbeam-channel New contributors (Thanks!) TiDB: lwh TiKV: csmoe wspsxing Docs: Ryan Brewster "}, {"url": "https://pingcap.com/blog-cn/tidb-source-code-reading-5/", "title": "TiDB 源码阅读系列文章(五)TiDB SQL Parser 的实现", "content": " 本文为 TiDB 源码阅读系列文章的第五篇,主要对 SQL Parser 功能的实现进行了讲解,内容来自社区小伙伴——马震(GitHub ID:mz1999 )的投稿。TiDB 源码阅读系列文章的撰写初衷,就是希望能与数据库研究者、爱好者进行深入交流,我们欣喜于如此短的时间内就收到了来自社区的反馈。后续,也希望有更多小伙伴加入到与 TiDB 『坦诚相见』的阵列中来。 PingCAP 发布了 TiDB 的源码阅读系列文章,让我们可以比较系统的去学习了解TiDB的内部实现。最近的一篇《SQL 的一生》,从整体上讲解了一条 SQL 语句的处理流程,从网络上接收数据,MySQL 协议解析和转换,SQL 语法解析,查询计划的制定和优化,查询计划执行,到最后返回结果。其中,SQL Parser 的功能是把 SQL 语句按照 SQL 语法规则进行解析,将文本转换成抽象语法树(AST),这部分功能需要些背景知识才能比较容易理解,我尝试做下相关知识的介绍,希望能对读懂这部分代码有点帮助。TiDB 是使用 goyacc 根据预定义的 SQL 语法规则文件 parser.y 生成 SQL 语法解析器。我们可以在 TiDB 的 Makefile 文件中看到这个过程,先 build goyacc 工具,然后使用 goyacc 根据 parser.y 生成解析器 parser.go:goyacc: $(GOBUILD) -o bin/goyacc parser/goyacc/main.go parser: goyacc bin/goyacc -o /dev/null parser/parser.y bin/goyacc -o parser/parser.go parser/parser.y 2>&1 ... goyacc 是 yacc 的 Golang 版,所以要想看懂语法规则定义文件 parser.y,了解解析器是如何工作的,先要对 Lex & Yacc 有些了解。Lex & Yacc 介绍 Lex & Yacc 是用来生成词法分析器和语法分析器的工具,它们的出现简化了编译器的编写。Lex & Yacc 分别是由贝尔实验室的 Mike Lesk 和 Stephen C. Johnson 在 1975 年发布。对于 Java 程序员来说,更熟悉的是 ANTLR,ANTLR 4 提供了 Listener+Visitor 组合接口, 不需要在语法定义中嵌入actions,使应用代码和语法定义解耦。Spark 的 SQL 解析就是使用了 ANTLR。Lex & Yacc 相对显得有些古老,实现的不是那么优雅,不过我们也不需要非常深入的学习,只要能看懂语法定义文件,了解生成的解析器是如何工作的就够了。我们可以从一个简单的例子开始:上图描述了使用 Lex & Yacc 构建编译器的流程。Lex 根据用户定义的 patterns 生成词法分析器。词法分析器读取源代码,根据 patterns 将源代码转换成 tokens 输出。Yacc 根据用户定义的语法规则生成语法分析器。语法分析器以词法分析器输出的 tokens 作为输入,根据语法规则创建出语法树。最后对语法树遍历生成输出结果,结果可以是产生机器代码,或者是边遍历 AST 边解释执行。从上面的流程可以看出,用户需要分别为 Lex 提供 patterns 的定义,为 Yacc 提供语法规则文件,Lex & Yacc 根据用户提供的输入文件,生成符合他们需求的词法分析器和语法分析器。这两种配置都是文本文件,并且结构相同:... definitions ... %% ... rules ... %% ... subroutines ... 文件内容由 %% 分割成三部分,我们重点关注中间规则定义部分。对于上面的例子,Lex 的输入文件如下:... %% /* 变量 */ [a-z] { yylval = *yytext - 'a'; return VARIABLE; } /* 整数 */ [0-9]+ { yylval = atoi(yytext); return INTEGER; } /* 操作符 */ [-+()=/*n] { return *yytext; } /* 跳过空格 */ [ t] ; /* 其他格式报错 */ . yyerror("invalid character"); %% ... 上面只列出了规则定义部分,可以看出该规则使用正则表达式定义了变量、整数和操作符等几种 token。例如整数 token 的定义如下:[0-9]+ { yylval = atoi(yytext); return INTEGER; } 当输入字符串匹配这个正则表达式,大括号内的动作会被执行:将整数值存储在变量 yylval 中,并返回 token 类型 INTEGER 给 Yacc。再来看看 Yacc 语法规则定义文件:%token INTEGER VARIABLE %left '+' '-' %left '*' '/' ... %% program: program statement 'n' | ; statement: expr { printf("%dn", $1); } | VARIABLE '=' expr { sym[$1] = $3; } ; expr: INTEGER | VARIABLE { $$ = sym[$1]; } | expr '+' expr { $$ = $1 + $3; } | expr '-' expr { $$ = $1 - $3; } | expr '*' expr { $$ = $1 * $3; } | expr '/' expr { $$ = $1 / $3; } | '(' expr ')' { $$ = $2; } ; %% ... 第一部分定义了 token 类型和运算符的结合性。四种运算符都是左结合,同一行的运算符优先级相同,不同行的运算符,后定义的行具有更高的优先级。语法规则使用了 BNF 定义。BNF 可以用来表达上下文无关(*context-free*)语言,大部分的现代编程语言都可以使用 BNF 表示。上面的规则定义了三个产生式。产生式冒号左边的项(例如 statement)被称为非终结符, INTEGER 和 VARIABLE 被称为终结符,它们是由 Lex 返回的 token 。终结符只能出现在产生式的右侧。可以使用产生式定义的语法生成表达式:expr -> expr * expr -> expr * INTEGER -> expr + expr * INTEGER -> expr + INTEGER * INTEGER -> INTEGER + INTEGER * INTEGER 解析表达式是生成表达式的逆向操作,我们需要归约表达式到一个非终结符。Yacc 生成的语法分析器使用自底向上的归约(*shift-reduce*)方式进行语法解析,同时使用堆栈保存中间状态。还是看例子,表达式 x + y * z 的解析过程:1 . x + y * z 2 x . + y * z 3 expr . + y * z 4 expr + . y * z 5 expr + y . * z 6 expr + expr . * z 7 expr + expr * . z 8 expr + expr * z . 9 expr + expr * expr . 10 expr + expr . 11 expr . 12 statement . 13 program . 点(.)表示当前的读取位置,随着 . 从左向右移动,我们将读取的 token 压入堆栈,当发现堆栈中的内容匹配了某个产生式的右侧,则将匹配的项从堆栈中弹出,将该产生式左侧的非终结符压入堆栈。这个过程持续进行,直到读取完所有的 tokens,并且只有启始非终结符(本例为 program)保留在堆栈中。产生式右侧的大括号中定义了该规则关联的动作,例如:expr: expr '*' expr { $$ = $1 * $3; } 我们将堆栈中匹配该产生式右侧的项替换为产生式左侧的非终结符,本例中我们弹出 expr '*' expr,然后把 expr 压回堆栈。 我们可以使用 $position 的形式访问堆栈中的项,$1 引用的是第一项,$2 引用的是第二项,以此类推。$$ 代表的是归约操作执行后的堆栈顶。本例的动作是将三项从堆栈中弹出,两个表达式相加,结果再压回堆栈顶。上面例子中语法规则关联的动作,在完成语法解析的同时,也完成了表达式求值。一般我们希望语法解析的结果是一棵抽象语法树(AST),可以这么定义语法规则关联的动作:... %% ... expr: INTEGER { $$ = con($1); } | VARIABLE { $$ = id($1); } | expr '+' expr { $$ = opr('+', 2, $1, $3); } | expr '-' expr { $$ = opr('-', 2, $1, $3); } | expr '*' expr { $$ = opr('*', 2, $1, $3); } | expr '/' expr { $$ = opr('/', 2, $1, $3); } | '(' expr ')' { $$ = $2; } ; %% nodeType *con(int value) { ... } nodeType *id(int i) { ... } nodeType *opr(int oper, int nops, ...) { ... } 上面是一个语法规则定义的片段,我们可以看到,每个规则关联的动作不再是求值,而是调用相应的函数,该函数会返回抽象语法树的节点类型 nodeType,然后将这个节点压回堆栈,解析完成时,我们就得到了一颗由 nodeType 构成的抽象语法树。对这个语法树进行遍历访问,可以生成机器代码,也可以解释执行。至此,我们大致了解了 Lex & Yacc的原理。其实还有非常多的细节,例如如何消除语法的歧义,但我们的目的是读懂 TiDB 的代码,掌握这些概念已经够用了。goyacc 简介 goyacc 是 golang 版的 Yacc。和 Yacc 的功能一样,goyacc 根据输入的语法规则文件,生成该语法规则的 go 语言版解析器。goyacc 生成的解析器 yyParse 要求词法分析器符合下面的接口:type yyLexer interface { Lex(lval *yySymType) int Error(e string) } 或者type yyLexerEx interface { yyLexer // Hook for recording a reduction. Reduced(rule, state int, lval *yySymType) (stop bool) // Client should copy *lval. } TiDB 没有使用类似 Lex 的工具生成词法分析器,而是纯手工打造,词法分析器对应的代码是 parser/lexer.go, 它实现了 goyacc 要求的接口:... // Scanner implements the yyLexer interface. type Scanner struct { r reader buf bytes.Buffer errs []error stmtStartPos int // For scanning such kind of comment: /*! MySQL-specific code */ or /*+ optimizer hint */ specialComment specialCommentScanner sqlMode mysql.SQLMode } // Lex returns a token and store the token value in v. // Scanner satisfies yyLexer interface. // 0 and invalid are special token id this function would return: // return 0 tells parser that scanner meets EOF, // return invalid tells parser that scanner meets illegal character. func (s *Scanner) Lex(v *yySymType) int { tok, pos, lit := s.scan() v.offset = pos.Offset v.ident = lit ... } // Errors returns the errors during a scan. func (s *Scanner) Errors() []error { return s.errs } 另外 lexer 使用了 字典树 技术进行 token 识别,具体的实现代码在 parser/misc.goTiDB SQL Parser 的实现 终于到了正题。有了上面的背景知识,对 TiDB 的 SQL Parser 模块会相对容易理解一些。TiDB 的词法解析使用的 手写的解析器(这是出于性能考虑),语法解析采用 goyacc。先看 SQL 语法规则文件 parser.y,goyacc 就是根据这个文件生成SQL语法解析器的。parser.y 有 6500 多行,第一次打开可能会被吓到,其实这个文件仍然符合我们上面介绍过的结构:... definitions ... %% ... rules ... %% ... subroutines ... parser.y 第三部分 subroutines 是空白没有内容的, 所以我们只需要关注第一部分 definitions 和第二部分 rules。第一部分主要是定义 token 的类型、优先级、结合性等。注意 union 这个联合体结构体:%union { offset int // offset item interface{} ident string expr ast.ExprNode statement ast.StmtNode } 该联合体结构体定义了在语法解析过程中被压入堆栈的项的属性和类型。压入堆栈的项可能是 终结符,也就是 token,它的类型可以是item 或 ident;这个项也可能是 非终结符,即产生式的左侧,它的类型可以是 expr 、 statement 、 item 或 ident。goyacc 根据这个 union 在解析器里生成对应的 struct 是:type yySymType struct { yys int offset int // offset item interface{} ident string expr ast.ExprNode statement ast.StmtNode } 在语法解析过程中,非终结符 会被构造成抽象语法树(AST)的节点 ast.ExprNode 或 ast.StmtNode。抽象语法树相关的数据结构都定义在 ast 包中,它们大都实现了 ast.Node 接口:// Node is the basic element of the AST. // Interfaces embed Node should have 'Node' name suffix. type Node interface { Accept(v Visitor) (node Node, ok bool) Text() string SetText(text string) } 这个接口有一个 Accept 方法,接受 Visitor 参数,后续对 AST 的处理,主要依赖这个 Accept 方法,以 Visitor 模式遍历所有的节点以及对 AST 做结构转换。// Visitor visits a Node. type Visitor interface { Enter(n Node) (node Node, skipChildren bool) Leave(n Node) (node Node, ok bool) } 例如 plan.preprocess 是对 AST 做预处理,包括合法性检查以及名字绑定。union 后面是对 token 和 非终结符 按照类型分别定义:/* 这部分的 token 是 ident 类型 */ %token <ident> ... add "ADD" all "ALL" alter "ALTER" analyze "ANALYZE" and "AND" as "AS" asc "ASC" between "BETWEEN" bigIntType "BIGINT" ... /* 这部分的 token 是 item 类型 */ %token <item> /*yy:token "1.%d" */ floatLit "floating-point literal" /*yy:token "1.%d" */ decLit "decimal literal" /*yy:token "%d" */ intLit "integer literal" /*yy:token "%x" */ hexLit "hexadecimal literal" /*yy:token "%b" */ bitLit "bit literal" andnot "&^" assignmentEq ":=" eq "=" ge ">=" ... /* 非终结符按照类型分别定义 */ %type <expr> Expression "expression" BoolPri "boolean primary expression" …"}, {"url": "https://pingcap.com/weekly/2018-03-19-tidb-weekly/", "title": "Weekly update (March 12 ~ March 18, 2018)", "content": " Weekly update in TiDB Last week, we landed 60 PRs in the TiDB repositories.Added Collect query feedbacks Support admin recover index Support retry and timeout for Coprocessor streaming API Export implicit rowid and use it in CRUD Fixed Fix the column length when converting the column information for tinyint Add the deprecation warning for builtin function PASSWORD Add missing columns in collations_information_applicability Fix the comparison between uint and int Fix the index iterator for unique index with a null value Fix insert into t1 (select * from t) Fix a bug when performing column substitution for join Change makeJoinRowToChunk to account for virtual rows Rollback the transaction when Compile returns error Improved Add a unit test for distsql.go Add the isolation test Show more information on DDL history Weekly update in TiSpark Last week, we landed 14 PRs in the TiSpark repositories and released 1.0-RC1.Fixed Fix the downgrade index scan logic to make it easier to downgrade Fix the prefix index logic for covering index Fix 0000-00-00 related test cases Rename the configuration item from allow_index_double_read to allow_index_read Map non-binary encoding blob to String type Make histogram loading compatible with TiDB of the earlier version Suppress JSON mapping exception Fix error handling for OtherError cases Fix the problem that the decimal precision is too large Improved Add statistics count in the plan for easier debugging RC1 released RC1 is released Weekly update in TiKV and PD Last week, we landed 29 PRs in the TiKV and PD repositories.Added Add raw_delete_range interface Support dump metrics Add metrics for PD member health Support merge Upgrade the indexmap Dump statistics of rocksdb and malloc Add the consistency-check subcommand to tikv-ctl Implement IngestSST API Fixed Fix Region size calculation Apply a hotfix in murmur3 Make the PD mock server ignore the sending failure Fix a bug that the help information always shows after help is used once Notify snapshot failure when resolving the remote address Fix the pd-ctl post bug when tls is enabled Fix a bug that too many pending Regions exist when checker adds peers to TiKV Improved Poll significant message Make the balance scheduler do not depend on the average score Set the default value for wal_bytes_per_sync and bytes_per_sync Make it possible to call the apply process recursively Separate read pool configuration from name_prefix Add assertion for error cases Change the isolation level of PD Region label from Histogram to Gauge Reclaim the disk space aggressively after data is deleted Add Coprocessor streaming support New contributors (Thanks!) TiKV: Hugo Wang Docs-cn: 康晓宁 "}, {"url": "https://pingcap.com/blog/performance_tuning_on_a_distributed_newsql_database/", "title": "How to do Performance Tuning on TiDB, A Distributed NewSQL Database", "content": " Author: Jinpeng Zhang, Database Engineer, Storage Team at PingCAPDoing performance tuning on distributed systems is no joking matter. It’s much more complicated than on a single node server, and bottlenecks can pop up anywhere, from system resources in a single node or subcomponent, to cooperation between nodes, to even network bandwidth. Performance tuning is a practice that aims to find these bottlenecks and address them, in order to reveal more bottlenecks and address them as well, until the system reaches an optimal performance level. In this article, I will share some best practices on how to tune “write” operations in TiDB to achieve maximum performance.TiDB is an open source hybrid transactional/analytical processing (HTAP) NewSQL database. One TiDB cluster has several TiDB servers, several TiKV servers , and a group of Placement Drivers (PD) (usually 3 or 5 nodes). The TiDB server is a stateless SQL layer, the TiKV server is the Key-Value storage layer, and PD is a manager component with god view that is responsible for storing metadata and conduct load balancing. Below is the architecture of a TiDB cluster, and you can find more details on each component in the official TiDB documentation.TiDB ArchitectureGathering Metrics We gather a lot of metrics inside each component and they are periodically sent to Prometheus, an open source system monitoring solution. You can easily observe the behaviors of these metrics in Grafana, an open source platform for time series analytics. If you deploy the TiDB cluster using Ansible, Prometheus and Grafana will be installed by default. By observing various metrics, we can see how each component is working, pinpoint where are the bottlenecks, and address them via tuning. Let’s see an example.Writeflow of an Insert SQL Statement Assuming we use the following SQL statement to insert a record to table t.mysql >> INSERT INTO t(id, name, address) values(1, “Jack”, “Sunnyvale”);Above is a simplified, animated overview of how this statement is processed in TiDB. After the TiDB server receives this SQL statement, it will transform the statement into one or more Key-Value (KV) pairs, depending on the number of indexes. These KV pairs will then be sent to an associated TiKV-server, where they will be replicated to several other TiKV-servers in the form of Raft log. Finally, when the Raft log has been committed, these KV pairs will be written to the engine for storage.There are three key processes at play in processing this statement: transforming SQL to KV pairs, replica by Region, and two-phase commit. Let’s dive into each in more details.From SQL to KV pairs Unlike other database systems, TiDB only stores KV pairs in order to provide infinite horizontal scalability with strong consistency. So how do we implement high-level concepts, such as database, table, and index? In TiDB, each table has an associated global unique number called “table-id.” The keys of all the data in a particular table, including records and indexes, all begin with the 8 bytes table-id. Each index has a table scope unique number called “index-id.” The following two lines show the encoding rules of record keys and index keys.Encoding rules of record keys and index keysThe Concept of Region In TiDB, a Region represents a continuous, left-close-right-open key range [start_key, end_key). Each Region has several replicas, and each replica is called a peer. Every Region also belongs to an individual Raft group, in order to guarantee strong data consistency among all peers. (For more information on how the Raft consensus algorithm is implemented in TiKV, see a related blog post by Distinguished Engineer at PingCAP, Liu Tang.) Nearby records of the same table are most likely in the same Region, because of the encoding rules that I mentioned above.When the cluster is first initialized, there is only one Region. A Region will dynamically split into two nearby Regions when the Region reaches a certain size (currently the default is 96MB), automatically distributing data across the system to provide horizontal scaling.Two-Phase Commit Our transaction model is inspired by Percolator, but with some additional optimizations.Briefly speaking, it is a two-phase commit protocol with prewrite and commit.There’s a lot more under the hood in each of these components, but a macro-level understanding is enough to set the scene for performance tuning. Now, let’s dig into four specific tuning techniques.Tuning Technique #1: Scheduler All write commands are dispatched to the scheduler model before replicating. The scheduler model is comprised of one scheduler thread and several worker threads. Why do we need a scheduler model? Before writing to the database, we need to check whether this write command is allowed and whether it satisfies the constraints of a transaction. All this checking workload, which might need reading from the underlying storage engine, is handled by scheduler workers.When you see in your metric that the total CPU usage of the scheduler workers exceeds scheduler-worker-pool-size * 80%, the way to tune your system is to increase the number of the scheduler workers to improve performance.You can change the scheduler workers count by modifying the ‘scheduler-worker-pool-size’ item in the ‘storage’ section of the configuration file. There are 4 scheduler workers by default on machines whose CPU core count is less than 16, otherwise the default is 8 scheduler workers. See relevant code section: scheduler-worker-pool-size = 4Monitoring CPU usage per scheduler workTuning Technique #2: ‘raftstore’ thread and ‘apply’ thread As I mentioned above, we use Raft to implement strong consistency between multiple peers. Before we actually write one KV pair into the database, this operation must first be replicated by Raft in the form of Raft log, which also needs to be written to disk in each peer to maintain durability. Only when the Raft log has been committed can the associated KV pair of the write command be written to the database.Thus, there are two types of write: writing Raft log and writing KV pair to the database. To process each type separately inside TiKV, there is one thread named “raftstore”, whose obligations are handling all Raft messages and writing Raft logs to the disk, and another thread named “apply worker,” whose responsibility is writing KV pairs to storage. These two threads, located in the ‘Thread CPU’ sub-panel of the TiKV panel in Grafana (see graphics below), both play significant roles in the write workload. We can easily trace how busy these threads are through Grafana.What’s worth paying attention to about these two threads is that if only some TiKV servers’ “apply” or “raftstore” threads are very busy, while other servers’ are not, that means the writing load is extremely unbalanced. These few busy TiKV servers thus become bottlenecks of the whole cluster. One way to accidentally create this hotspot situation is by choosing a column whose value monotonically increases. For example, using AUTOINCREMENT primary key or creating index on the column whose value keeps increasing, e.g. last access timestamp.To tune this scenario and remove the bottleneck, you must avoid designing primary keys and indexes on columns whose values increase monotonically.In traditional single node database systems, using the AUTOINCREMENT keyword can offer a lot of benefit for sequential writing. But when it comes to a distributed database system, the most important thing is balancing load well on all components.TiKV Thead CPU sub-panel Tuning Technique #3: RocksDB RocksDB is a persistent KV store with high performance and many useful features. TiKV uses RocksDB as its underlying storage engine, as well as many of its features like column family, delete range, prefix seek, memtable prefix bloom filter, sst user defined properties and so on. RocksDB provides its own detailed performance tuning …"}, {"url": "https://pingcap.com/blog-cn/tidb-source-code-reading-4/", "title": "TiDB 源码阅读系列文章(四)Insert 语句概览", "content": " 本文为 TiDB 源码阅读系列文章的第四篇。上一篇文章简单介绍了整体流程,无论什么语句,大体上是在这个框架下运行,DDL 语句也不例外。本篇文章会以 Insert 语句为例进行讲解,帮助读者理解前一篇文章,下一篇文章会介绍 Select 语句的执行流程。这两条是最常用的读、写语句,其他的语句相信读者能触类旁通,可以自行研究或者是等待后续的文章。对于这两类语句,目前也只会针对核心流程进行说明,更复杂的 Join、Insert-Into-OnDuplicate-Update 等会等到后面的文章进行讲解。另外本文会重点介绍每个语句在执行框架下面的具体执行逻辑,请读者阅读前先了解 Insert 语句的行为。表结构 这里先给一个表结构,下面介绍的 SQL 语句都是在这个表上的操作。CREATE TABLE t { id VARCHAR(31), name VARCHAR(50), age int, key id_idx (id) }; Insert 语句 INSERT INTO t VALUES ("pingcap001", "pingcap", 3); 以这条语句为例,解释 Insert 是如何运行的。语句处理流程 首先大家回忆一下上一篇文章介绍的框架,一条 SQL 语句经过协议层、Parser、Plan、Executor 这样几个模块处理后,变成可执行的结构,再通过 Next() 来驱动语句的真正执行。对于框架,每类语句都差不多;对于每个核心步骤,每个语句会有自己的处理逻辑。语法解析 先看 Parser,对于 Insert 语句的解析逻辑在这里,可以看到这条语句会被解析成下面这个结构:// InsertStmt is a statement to insert new rows into an existing table. // See https://dev.mysql.com/doc/refman/5.7/en/insert.html type InsertStmt struct { dmlNode IsReplace bool IgnoreErr bool Table *TableRefsClause Columns [](#)*ColumnName Lists [](#)[](#)ExprNode Setlist [](#)*Assignment Priority mysql.PriorityEnum OnDuplicate [](#)*Assignment Select ResultSetNode } 这里提到的语句比较简单,只会涉及 Table 以及 Lists 这两个字段,也就是向哪个表插入哪些数据。其中 Lists 是一个二维数组,数组中的每一行对应于一行数据,这个语句只包含一行数据。有了 AST 之后,需要对其进行一系列处理,预处理、合法性验证、权限检查这些暂时跳过(每个语句的处理逻辑都差不多),我们看一下针对 Insert 语句的处理逻辑。查询计划 接下来是将 AST 转成 Plan 结构,这个操作是在 planBuilder.buildInsert() 中完成。对于这个简单的语句,主要涉及两个部分: 补全 Schema 信息包括 Database/Table/Column 信息,这个语句没有指定向哪些列插入数据,所以会使用所有的列。 处理 Lists 中的数据这里会处理一遍所有的 Value,将 ast.ExprNode 转换成 expression.Expression,也就是纳入了我们的表达式框架,后面会在这个框架下求值。大多数情况下,这里的 Value 都是常量,也就是 expression.Constant。 如果 Insert 语句比较复杂,比如要插入的数据来自于一个 Select,或者是 OnDuplicateUpdate 这种情况,还会做更多的处理,这里暂时不再深入描述,读者可以执行看 buildInsert() 中其他的代码。现在 ast.InsertStmt 已经被转换成为 plan.Insert 结构,对于 Insert 语句并没有什么可以优化的地方,plan.Insert 这个结构只实现了 Plan 这个接口,所以在下面这个判断中,不会走进 Optimize 流程:if logic, ok := p.(LogicalPlan); ok { return doOptimize(builder.optFlag, logic) } 其他比较简单的语句也不会进入 doOptimize,比如 Show 这种语句,下一篇文章会讲解 Select 语句,会涉及到 doOptimize 函数。执行 拿到 plan.Insert 这个结构后,查询计划就算制定完成。最后我们看一下 Insert 是如何执行的。首先 plan.Insert 在这里被转成 executor.InsertExec 结构,后续的执行都由这个结构进行。执行入口是 Next 方法,第一步是要对待插入数据的每行进行表达式求值,具体的可以看 getRows 这个函数,拿到数据后就进入最重要的逻辑— InsertExec.exec() 这个函数,这个函数有点长,不过只考虑我们文章中讲述的这条 SQL 的话,可以把代码简化成下面这段逻辑:for _, row := range rows { h, err := e.Table.AddRecord(e.ctx, row, false) } 接下来我们看一下 AddRecord 这个函数是如何将一行数据写入存储引擎中。要理解这段代码,需要了解一下 TiDB 是如何将 SQL 的数据映射为 Key-Value,可以先读一下我们之前写的一些文章,比如这一篇。这里假设读者已经了解了这一点背景知识,那么一定会知道这里需要将 Row 和 Index 的 Key-Value 构造出来的,写入存储引擎。构造 Index 数据的代码在 addIndices() 函数中,会调用 index.Create() 这个方法:构造 Index Key: func (c *index) GenIndexKey(sc *stmtctx.StatementContext, indexedValues [](#)types.Datum, h int64, buf [](#)byte) (key [](#)byte, distinct bool, err error) { ...... key = c.getIndexKeyBuf(buf, len(c.prefix)+len(indexedValues)*9+9) key = append(key, [](#)byte(c.prefix)...) key, err = codec.EncodeKey(sc, key, indexedValues...) if !distinct && err == nil { key, err = codec.EncodeKey(sc, key, types.NewDatum(h)) }构造 Index Value: func (c *index) Create(ctx context.Context, rm kv.RetrieverMutator, indexedValues [](#)types.Datum, h int64) (int64, error) { if !distinct { // non-unique index doesn't need store value, write a '0' to reduce space  err = rm.Set(key, [](#)byte'0') return 0, errors.Trace(err) } ...... if skipCheck { err = rm.Set(key, encodeHandle(h)) return 0, errors.Trace(err) } 构造 Row 数据的代码比较简单,就在 tables.AddRecord 函数中:构造 Row Key: key := t.RecordKey(recordID)构造 Row Value: writeBufs.RowValBuf, err = tablecodec.EncodeRow(ctx.GetSessionVars().StmtCtx, row, colIDs, writeBufs.RowValBuf, writeBufs.AddRowValues) 构造完成后,调用类似下面这段代码即可将 Key-Value 写到当前事务的缓存中:if err = txn.Set(key, value); err != nil { return 0, errors.Trace(err) } 在事务的提交过程中,即可将这些 Key-Value 提交到存储引擎中。小结 Insert 语句在诸多 DML 语句中算是最简单的语句,本文也没有涉及 Insert 语句中更复杂的情况,所以相对比较好理解。上面讲了这么多代码,让我们用一幅图来再回顾一下整个流程。最后给大家留一个思考题,本文描述了如何写入数据,那么 TiDB 是如何删除数据的呢?也就是 Delete 语句的执行流程是什么样子的,请大家追踪源码,调研一下这个流程,有兴趣的读者可以仿照本文写一篇源码解析文档,投稿给我们。下一篇文章会介绍一下 Select 语句的执行流程,不但会涉及到 SQL 层,也会介绍 Coprocessor 模块是如何工作的,敬请期待。"}, {"url": "https://pingcap.com/weekly/2018-03-12-tidb-weekly/", "title": "Weekly update (March 05 ~ March 11, 2018)", "content": " TiDB 2.0 RC1 release TiDB 2.0 RC1 is released. This release has great improvement in MySQL compatibility, SQL optimization and stability.Weekly update in TiDB Last week, we landed 38 PRs in the TiDB repositories.Added Support checking the consistency of an index Support decoding a column value by HTTP API Add validation for configuration Add HTTP API for settings Employ memory Tracker to track memory usage during query execution Fixed Fix inconsistent behavior for insert Correct the behavior of the bit aggregate function Fix a bug that index is not used in a special case Fix the field length of Boolean type Handle warnings returned from tikv/mocktikv Improved Set low priority for adding an index Support pseudo profiling table for compatibility Enhance decorrelation Check the password format for create user identified by password XXX Avoid the random error during Leader checking in GC Make CommitMaxBackoff configurable Weekly update in TiSpark Last week, we landed 8 PRs in the TiSpark repositories.Added Add statistics information module Add the SQL dump for the Meta-server database Fixed Fix the parse exception when a table name contains symbols Fix group by in DAGRequest Fix a document link Improved Reduce jar size Weekly update in TiKV and PD Last week, we landed 32 PRs in the TiKV and PD repositories.Added Configure the check SSD Check critical configurations when TiKV starts Initialize api for metrics Fixed Create a parent directory if it does not exist Exclude offline store in FilterSource Fix usage template Fix a bug in SSD test Cancel unused Region heartbeat RPC Delete the overlap from etcd Fix a panic caused by the merged Region Fix stale Region information with overlaps that should be removed Fix a segfault Fix a bug of the operator type Fix health status with TLS enabled Improved Count the number of offline Regions Tune the default snapshot I/O limitation Increase the operator timeout Record the elapsed time of operatorStep Move storage read operations into ReadPool New contributors (Thanks!) TiDB: shizy 杨 洋 "}, {"url": "https://pingcap.com/blog-cn/tidb-source-code-reading-3/", "title": "TiDB 源码阅读系列文章(三)SQL 的一生", "content": " 概述 上一篇文章讲解了 TiDB 项目的结构以及三个核心部分,本篇文章从 SQL 处理流程出发,介绍哪里是入口,对 SQL 需要做哪些操作,知道一个 SQL 是从哪里进来的,在哪里处理,并从哪里返回。SQL 有很多种,比如读、写、修改、删除以及管理类的 SQL,每种 SQL 有自己的执行逻辑,不过大体上的流程是类似的,都在一个统一的框架下运转。框架 我们先从整体上看一下,一条语句需要经过哪些方面的工作。如果大家还记得上一篇文章所说的三个核心部分,可以想到首先要经过协议解析和转换,拿到语句内容,然后经过 SQL 核心层逻辑处理,生成查询计划,最后去存储引擎中获取数据,进行计算,返回结果。这个就是一个粗略的处理框架,本篇文章会把这个框架不断细化。对于第一部分,协议解析和转换,所有的逻辑都在 server 这个包中,主要逻辑分为两块:一是连接的建立和管理,每个连接对应于一个 Session;二是在单个连接上的处理逻辑。第一点本文暂时不涉及,感兴趣的同学可以翻翻代码,看看连接如何建立、如何握手、如何销毁,后面也会有专门的文章讲解。对于 SQL 的执行过程,更重要的是第二点,也就是已经建立了连接,在这个连接上的操作,本文会详细讲解这一点。对于第二部分,SQL 层的处理是整个 TiDB 最复杂的部分。这部分为什么复杂?原因有三点: SQL 语言本身是一门复杂的语言,语句的种类多、数据类型多、操作符多、语法组合多,这些『多』经过排列组合会变成『很多』『非常多』,所以需要写大量的代码来处理。 SQL 是一门表意的语言,只是说『要什么数据』,而不说『如何拿数据』,所以需要一些复杂的逻辑选择『如何拿数据』,也就是选择一个好的查询计划。 底层是一个分布式存储引擎,会面临很多单机存储引擎不会遇到的问题,比如做查询计划的时候要考虑到下层的数据是分片的、网络不通了如何处理等情况,所以需要一些复杂的逻辑处理这些情况,并且需要一个很好的机制将这些处理逻辑封装起来。这些复杂性是看懂源码比较大的障碍,所以本篇文章会尽量排除这些干扰,给大家讲解核心的逻辑是什么。 这一层有几个核心概念,掌握了这几个也就掌握了这一层的框架,请大家关注下面这几个接口: Session RecordSet Plan LogicalPlan PhysicalPlan Executor 下面的详细内容中,会讲解这些接口,用这些接口理清楚整个逻辑。对于第三部分可以认为两块,第一块是 KV 接口层,主要作用是将请求路由到正确的的 KV Server,接收返回消息传给 SQL 层,并在此过程中处理各种异常逻辑;第二块是 KV Server 的具体实现,由于 TiKV 比较复杂,我们可以先看 Mock-TiKV 的实现,这里有所有的 SQL 分布式计算相关的逻辑。 接下来的几节,会对上面的三块详细展开描述。协议层入口 当和客户端的连接建立好之后,TiDB 中会有一个 Goroutine 监听端口,等待从客户端发来的包,并对发来的包做处理。这段逻辑在 server/conn.go 中,可以认为是 TiDB 的入口,本节介绍一下这段逻辑。 首先看 clientConn.Run(),这里会在一个循环中,不断的读取网络包:445: data, err := cc.readPacket() 然后调用 dispatch() 方法处理收到的请求:465: if err = cc.dispatch(data); err != nil { 接下来进入 clientConn.dispatch()方法:func (cc *clientConn) dispatch(data []byte) error { 这里要处理的包是原始 byte 数组,里面的内容读者可以参考 MySQL 协议,第一个 byte 即为 Command 的类型:580: cmd := data[0] 然后根据 Command 的类型,调用对应的处理函数,最常用的 Command 是 COM_QUERY,对于大多数 SQL 语句,只要不是用 Prepared 方式,都是 COM_QUERY,本文也只会介绍这个 Command,其他的 Command 请读者对照 MySQL 文档看代码。 对于 Command Query,从客户端发送来的主要是 SQL 文本,处理函数是 handleQuery():func (cc *clientConn) handleQuery(goCtx goctx.Context, sql string) (err error) { 这个函数会调用具体的执行逻辑:850: rs, err := cc.ctx.Execute(goCtx, sql) 这个 Execute 方法的实现在 server/driver_tidb.go 中,func (tc *TiDBContext) Execute(goCtx goctx.Context, sql string) (rs []ResultSet, err error) { rsList, err := tc.session.Execute(goCtx, sql) 最重要的就是调用 tc.session.Execute,这个 session.Execute 的实现在 session.go 中,自此会进入 SQL 核心层,详细的实现会在后面的章节中描述。经过一系列处理,拿到 SQL 语句的结果后会调用 writeResultset 方法把结果写回客户端:857: err = cc.writeResultset(goCtx, rs[0], false, false) 协议层出口 出口比较简单,就是上面提到的 writeResultset 方法,按照 MySQL 协议的要求,将结果(包括 Field 列表、每行数据)写回客户端。读者可以参考 MySQL 协议中的 COM_QUERY Response 理解这段代码。接下的几节我们进入核心流程,看看一条文本的 SQL 是如何处理的。我会先介绍所有的流程,然后用一个图把所有的流程串起来。Session Session 中最重要的函数是 Execute,这里会调用下面所述的各种模块,完成语句执行。注意这里在执行的过程中,会考虑 Session 环境变量,比如是否 AutoCommit,时区是什么。Lexer & Yacc 这两个组件共同构成了 Parser 模块,调用 Parser,可以将文本解析成结构化数据,也就是抽象语法树 (AST):session.go 699: return s.parser.Parse(sql, charset, collation) 在解析过程中,会先用 lexer 不断地将文本转换成 token,交付给 Parser,Parser 是根据 yacc 语法生成,根据语法不断的决定 Lexer 中发来的 token 序列可以匹配哪条语法规则,最终输出结构化的节点。 例如对于这样一条语句 SELECT * FROM t WHERE c > 1;,可以匹配 SelectStmt 的规则,被转换成下面这样一个数据结构:type SelectStmt struct { dmlNode resultSetNode // SelectStmtOpts wraps around select hints and switches. *SelectStmtOpts // Distinct represents whether the select has distinct option. Distinct bool // From is the from clause of the query. From *TableRefsClause // Where is the where clause in select statement. Where ExprNode // Fields is the select expression list. Fields *FieldList // GroupBy is the group by expression list. GroupBy *GroupByClause // Having is the having condition. Having *HavingClause // OrderBy is the ordering expression list. OrderBy *OrderByClause // Limit is the limit clause. Limit *Limit // LockTp is the lock type LockTp SelectLockType // TableHints represents the level Optimizer Hint TableHints []*TableOptimizerHint } 其中,FROM t 会被解析为 FROM 字段,WHERE c > 1 被解析为 Where 字段,* 被解析为 Fields 字段。所有的语句的结构够都被抽象为一个 ast.StmtNode,这个接口读者可以自行看注释,了解一下。这里只提一点,大部分 ast 包中的数据结构,都实现了 ast.Node 接口,这个接口有一个 Accept 方法,后续对 AST 的处理,主要依赖这个 Accept 方法,以 Visitor 模式遍历所有的节点以及对 AST 做结构转换。制定查询计划以及优化 拿到 AST 之后,就可以做各种验证、变化、优化,这一系列动作的入口在这里:session.go 805: stmt, err := compiler.Compile(goCtx, stmtNode) 我们进入 Compile 函数,可以看到三个重要步骤: plan.Preprocess: 做一些合法性检查以及名字绑定; plan.Optimize:制定查询计划,并优化,这个是最核心的步骤之一,后面的文章会重点介绍; 构造 executor.ExecStmt 结构:这个 ExecStmt 结构持有查询计划,是后续执行的基础,非常重要,特别是 Exec 这个方法。 生成执行器 在这个过程中,会将 plan 转换成 executor,执行引擎即可通过 executor 执行之前定下的查询计划,具体的代码见 ExecStmt.buildExecutor():executor/adpter.go 227: e, err := a.buildExecutor(ctx) 生成执行器之后,被封装在一个 recordSet 结构中:return &recordSet{ executor: e, stmt: a, processinfo: pi, txnStartTS: ctx.Txn().StartTS(), }, nil 这个结构实现了 ast.RecordSet 接口,从字面上大家可以看出,这个接口代表了查询结果集的抽象,我们看一下它的几个方法:// RecordSet is an abstract result set interface to help get data from Plan. type RecordSet interface { // Fields gets result fields. Fields() []*ResultField // Next returns the next row, nil row means there is no more to return. Next(ctx context.Context) (row types.Row, err error) // NextChunk reads records into chunk. NextChunk(ctx context.Context, chk *chunk.Chunk) error // NewChunk creates a new chunk with initial capacity. NewChunk() *chunk.Chunk // SupportChunk check if the RecordSet supports Chunk structure. SupportChunk() bool // Close closes the underlying iterator, call Next after Close will // restart the iteration. Close() error } 通过注释大家可以看到这个接口的作用,简单来说,可以调用 Fields() 方法获得结果集每一列的类型,调用 Next/NextChunk() 可以获取一行或者一批数据,调用 Close() 可以关闭结果集。运行执行器 TiDB 的执行引擎是以 Volcano 模型运行,所有的物理 Executor 构成一个树状结构,每一层通过调用下一层的 Next/NextChunk() 方法获取结果。 举个例子,假设语句是 SELECT c1 FROM t WHERE c2 > 1;,并且查询计划选择的是全表扫描+过滤,那么执行器树会是下面这样:大家可以从图中看到 Executor 之间的调用关系,以及数据的流动方式。那么最上层的 Next 是在哪里调用,也就是整个计算的起始点在哪里,谁来驱动这个流程? 有两个地方大家需要关注,这两个地方分别处理两类语句。 第一类语句是 Select 这种查询语句,需要对客户端返回结果,这类语句的执行器调用点在给客户端返回数据的地方:row, err = rs.Next(ctx) 这里的 rs 即为一个 RecordSet 接口,对其不断的调用 Next(),拿到更多结果,返回给 MySQL Client。 第二类语句是 Insert 这种不需要返回数据的语句,只需要把语句执行完成即可。这类语句也是通过 Next 驱动执行,驱动点在构造 recordSet 结构之前:// If the executor doesn't return any result to the client, we execute it without delay. if e.Schema().Len() == 0 { return a.handleNoDelayExecutor(goCtx, e, ctx, pi) } else if proj, ok := e.(*ProjectionExec); ok && proj.calculateNoDelay { // Currently this is only for the "DO" statement. Take "DO 1, @a=2;" as an example: // the Projection has two expressions and two columns in the schema, but we should // not return the result of the two expressions. return a.handleNoDelayExecutor(goCtx, e, ctx, pi) } 总结 上面描述了整个 SQL 层的执行框架,这里用一幅图来描述整个过程:通过这篇文章,相信大家已经了解了 TiDB 中语句的执行框架,整个逻辑还是比较简单,框架中具体的模块的详细解释会在后续章节中给出。下一篇文章会用具体的语句为例,帮助大家理解本篇文章。"}, {"url": "https://pingcap.com/weekly/2018-03-05-tidb-weekly/", "title": "Weekly update (February 26 ~ March 04, 2018)", "content": " Weekly update in TiDB Last week, we landed 27 PRs in the TiDB repositories.Added Support stream aggregation on TiKV Support long VARCHAR Set Range and OutputCounts in Coprocessor Response for streaming API Support COMMENT = string in partition definition Add restrict and cascade in DropTable Fixed Set have_profiling to NO Improved Remove invalid intervals in building Range Resolve locks in a batch Extract the same part from DNF’s leaves Simplify the logic of HashCode Improve the performance of decoding decimal Test coverage: Improve the test coverage in the executor package Improve the test coverage in the plan package Improve the test coverage in the distsql package Panic recover: Add the recover mechanism for index lookup reader workers Add the recover mechanism for union workers Add the recover panic in owner.CampaignLoop Weekly update in TiSpark Last week, we landed 4 PRs in the TiSpark repositories.Added Add the index covering optimization Add the broadcast join support Improved Add more tests Add DDL Dump for using TiDB as Spark MetaStore Weekly update in TiKV and PD Last week, we landed 12 PRs in the TiKV and PD repositories.Added Export some struct expressions for other tools Log panic stacks Update the TiKV version Add a Raft message flush metrics Fixed Update the Rust dockerfile Fix lowspace metrics Check Regions in the background goroutine Handle the problem that only one row returns in stream aggregation Improved Rename a confused constant variable Make end_point_request_max_handle_secs configurable Precreate some labal metrics New contributor (Thanks!) TiKV: Greg Weber "}, {"url": "https://pingcap.com/blog-cn/tidb-source-code-reading-2/", "title": "TiDB 源码阅读系列文章(二)初识 TiDB 源码", "content": " 本文为 TiDB 源码阅读系列文章的第二篇,第一篇文章介绍了 TiDB 整体的架构,知道 TiDB 有哪些模块,分别是做什么的,从哪里入手比较好,哪些可以忽略,哪些需要仔细阅读。这篇文章是一篇入门文档,难度系数比较低,其中部分内容可能大家在其他渠道已经看过,不过为了内容完整性,我们还是会放在这里。TiDB 架构 本次 TiDB 源码之旅从这幅简单的架构图开始,这幅图很多人都看过,我们可以用一句话来描述这个图:『TiDB 是一个支持 MySQL 协议,以某种支持事务的分布式 KV 存储引擎为底层存储的 SQL 引擎』。从这句话可以看出有三个重要的事情,第一是如何支持 MySQL 协议,与 Client 交互,第二是如何与底层的存储引擎打交道,存取数据,第三是如何实现 SQL 的功能。本篇文章会先介绍一些 TiDB 有哪些模块及其功能简要介绍,然后以这三点为线索,将这些模块串联起来。代码简介 TiDB 源码完全托管在 Github 上,从项目主页可以看到所有信息。整个项目使用 Go 语言开发,按照功能模块分了很多 Package,通过一些依赖分析工具,可以看到项目内部包之间的依赖关系。大部分包都以接口的形式对外提供服务,大部分功能也都集中在某个包中,不过有一些包提供了非常基础的功能,会被很多包依赖,这些包需要特别注意。项目的 main 文件在 tidb-server/main.go,这里面定义了服务如何启动。整个项目的 Build 方法可以在 Makefile 中找到。除了代码之外,还有很多测试用例,可以在 xx_test.go 中找到。另外 cmd 目录下面还有几个工具包,用来做性能测试或者是构造测试数据。模块介绍 TiDB 的模块非常多,这里做一个整体介绍,大家可以看到每个模块大致是做什么用的,想看相关功能的代码是,可以直接找到对应的模块。 Package Introduction ast 抽象语法树的数据结构定义,例如 SelectStmt 定义了一条 Select 语句被解析成什么样的数据结构 cmd/benchdb 简单的 benchmark 工具,用于性能优化 cmd/benchfilesort 简单的 benchmark 工具,用于性能优化 cmd/benchkv Transactional KV API benchmark 工具,也可以看做 KV 接口的使用样例 cmd/benchraw Raw KV API benchmark 工具,也可以看做不带事务的 KV 接口的使用样例 cmd/importer 根据表结构以及统计信息伪造数据的工具,用于构造测试数据 config 配置文件相关逻辑 context 主要包括 Context 接口,提供一些基本的功能抽象,很多包以及函数都会依赖于这个接口,把这些功能抽象为接口是为了解决包之间的依赖关系 ddl DDL 的执行逻辑 distsql 对分布式计算接口的抽象,通过这个包把 Executor 和 TiKV Client 之间的逻辑做隔离 domain domain 可以认为是一个存储空间的抽象,可以在其中创建数据库、创建表,不同的 domain 之间,可以存在相同名称的数据库,有点像 Name Space。一般来说单个 TiDB 实例只会创建一个 Domain 实例,其中会持有 information schema 信息、统计信息等。 executor 执行器相关逻辑,可以认为大部分语句的执行逻辑都在这里,比较杂,后面会专门介绍 expression 表达式相关逻辑,包括各种运算符、内建函数 expression/aggregation 聚合表达式相关的逻辑,比如 Sum、Count 等函数 infoschema SQL 元信息管理模块,另外对于 Information Schema 的操作,都会访问这里 kv KV 引擎接口以及一些公用方法,底层的存储引擎需要实现这个包中定义的接口 meta 利用 structure 包提供的功能,管理存储引擎中存储的 SQL 元信息,infoschema/DDL 利用这个模块访问或者修改 SQL 元信息 meta/autoid 用于生成全局唯一自增 ID 的模块,除了用于给每个表的自增 ID 之外,还用于生成全局唯一的 Database ID 和 Table ID metrics Metrics 相关信息,所有的模块的 Metrics 信息都在这里 model SQL 元信息数据结构,包括 DBInfo / TableInfo / ColumnInfo / IndexInfo 等 mysql MySQL 相关的常量定义 owner TiDB 集群中的一些任务只能由一个实例执行,比如异步 Schema 变更,这个模块用于多个 tidb-server 之间协调产生一个任务执行者。每种任务都会产生自己的执行者。 parser 语法解析模块,主要包括词法解析 (lexer.go) 和语法解析 (parser.y),这个包对外的主要接口是 Parse(),用于将 SQL 文本解析成 AST parser/goyacc 对 GoYacc 的包装 parser/opcode 关于操作符的一些常量定义 perfschema Performance Schema 相关的功能,默认不会启用 plan 查询优化相关的逻辑 privilege 用户权限管理接口 privilege/privileges 用户权限管理功能实现 server MySQL 协议以及 Session 管理相关逻辑 sessionctx/binloginfo 向 Binlog 模块输出 Binlog 信息 sessionctx/stmtctx Session 中的语句运行时所需要的信息,比较杂 sessionctx/variable System Variable 相关代码 statistics 统计信息模块 store 储存引擎相关逻辑,这里是存储引擎和 SQL 层之间的交互逻辑 store/mockoracle 模拟 TSO 组件 store/mockstore 实例化一个 Mock TiKV 的逻辑,主要方法是 NewMockTikvStore,把这部分逻辑从 mocktikv 中抽出来是避免循环依赖 store/mockstore/mocktikv 在单机存储引擎上模拟 TiKV 的一些行为,主要作用是本地调试、构造单元测试以及指导 TiKV 开发 Coprocessor 相关逻辑 store/tikv TiKV 的 Go 语言 Client store/tikv/gcworker TiKV GC 相关逻辑,tidb-server 会根据配置的策略向 TiKV 发送 GC 命令 store/tikv/oracle TSO 服务接口 store/tikv/oracle/oracles TSO 服务的 Client store/tikv/tikvrpc TiKV API 的一些常量定义 structure 在 Transactional KV API 上定义的一层结构化 API,提供 List/Queue/HashMap 等结构 table 对 SQL 的 Table 的抽象 table/tables 对 table 包中定义的接口的实现 tablecodec SQL 到 Key-Value 的编解码,每种数据类型的具体编解码方案见 codec 包 terror TiDB 的 error 封装 tidb-server 服务的 main 方法 types 所有和类型相关的逻辑,包括一些类型的定义、对类型的操作等 types/json json 类型相关的逻辑 util 一些实用工具,这个目录下面包很多,这里只会介绍几个重要的包 util/admin TiDB 的管理语句( Admin 语句)用到的一些方法 util/charset 字符集相关逻辑 util/chunk Chunk 是 TiDB 1.1 版本引入的一种数据表示结构。一个 Chunk 中存储了若干行数据,在进行 SQL 计算时,数据是以 Chunk 为单位在各个模块之间流动 util/codec 各种数据类型的编解码 x-server X-Protocol 实现 从哪里入手 粗看一下 TiDB 有 80 个包,让人觉得无从下手,不过并不是所有的包都很重要,另外一些功能只会涉及到少量包,从哪里入手去看源码取决于看源码的目的。如果是想了解某一个具体的功能的实现细节,那么可以参考上面的模块简介,找到对应的模块即可。如果想对源码有全面的了解,那么可以从 tidb-server/main.go 入手,看 tidb-server 是如何启动,如何等待并处理用户请求。再跟着代码一直走,看 SQL 的具体执行过程。另外一些重要的模块,需要看一下,知道是如何实现的。辅助性的模块,可以选择性的看一下,有大致的印象即可。重要模块 在全部 80 个模块中,下面几个模块是最重要的,希望大家能仔细阅读,针对这些模块,我们也会用专门的文章来讲解,等所有的文章都 Ready 后,我将下面的表格中的 TODO 换成对应的文章链接。 Package Related Articles plan TODO expression TODO executor TODO distsql TODO store/tikv TODO ddl TODO tablecodec TODO server TODO types TODO kv TODO tidb TODO 辅助模块 除了重要的模块之外,余下的是辅助模块,但并不是说这些模块不重要,只是说这些模块并不在 SQL 执行的关键路径上,我们也会用一定的篇幅描述其中的大部分包。SQL 层架构 这幅图比上一幅图详细很多,大体描述了 SQL 核心模块,大家可以从左边开始,顺着箭头的方向看。Protocol Layer 最左边是 TiDB 的 Protocol Layer,这里是与 Client 交互的接口,目前 TiDB 只支持 MySQL 协议,相关的代码都在 server 包中。这一层的主要功能是管理客户端 connection,解析 MySQL 命令并返回执行结果。具体的实现是按照 MySQL 协议实现,具体的协议可以参考 MySQL 协议文档。这个模块我们认为是当前实现最好的一个 MySQL 协议组件,如果大家的项目中需要用到 MySQL 协议解析、处理的功能,可以参考或引用这个模块。连接建立的逻辑在 server.go 的 Run() 方法中,主要是下面两行:236: conn, err := s.listener.Accept() 258: go s.onConn(conn) 单个 Session 处理命令的入口方法是调用 clientConn 类的 dispatch 方法,这里会解析协议并转给不同的处理函数。SQL Layer 大体上讲,一条 SQL 语句需要经过,语法解析–>合法性验证–>制定查询计划–>优化查询计划–>根据计划生成查询器–>执行并返回结果 等一系列流程。这个主干对应于 TiDB 的下列包: Package 作用 tidb Protocol 层和 SQL 层之间的接口 parser 语法解析 plan 合法性验证 + 制定查询计划 + 优化查询计划 executor 执行器生成以及执行 distsql 通过 TiKV Client 向 TiKV 发送以及汇总返回结果 store/tikv TiKV Client KV API Layer TiDB 依赖于底层的存储引擎提供数据的存取功能,但是并不是依赖于特定的存储引擎(比如 TiKV),而是对存储引擎提出一些要求,满足这些要求的引擎都能使用(其中 TiKV 是最合适的一款)。最基本的要求是『带事务的 Key-Value 引擎,且提供 Go 语言的 Driver』,再高级一点的要求是『支持分布式计算接口』,这样 TiDB 可以把一些计算请求下推到 存储引擎上进行。这些要求都可以在 kv 这个包的接口中找到,存储引擎需要提供实现了这些接口的 Go 语言 Driver,然后 TiDB 利用这些接口操作底层数据。对于最基本的要求,可以重点看这几个接口: Transaction:事务基本操作 Retriever :读取数据的接口 Mutator:修改数据的接口 Storage:Driver 提供的基本功能 Snapshot:在数据 Snapshot 上面的操作 Iterator:Seek 返回的结果,可以用于遍历数据 有了上面这些接口,可以对数据做各种所需要的操作,完成全部 SQL 功能,但是为了更高效的进行运算,我们还定义了一个高级计算接口,可以关注这三个 Interface/struct : Client:向下层发送请求以及获取下层存储引擎的计算能力 Request: 请求的内容 Response: 返回结果的抽象 小结 至此,读者已经了解了 TiDB 的源码结构以及三个主要部分的架构,更详细的内容会在后面的章节中详细描述。"}, {"url": "https://pingcap.com/blog-cn/tidb-source-code-reading-1/", "title": "TiDB 源码阅读系列文章(一)序", "content": " 在 TiDB DevCon2018 上,我们对外宣布了 TiDB 源码阅读分享活动,承诺对外发布一系列文章以及视频帮助大家理解 TiDB 源码。大家一直很关心这项活动的时间,而我们忙于新版本的开发,一直不得闲。在春节放假期间,终于有时间开始动手写这个系列。为什么我们要做这件事情?事情的起因是随着 TiDB 项目逐渐发展,代码日渐复杂,我们发现新入职的同学越来越难上手修改代码。我们萌生了做内部培训的想法,通过录制视频、写教程的方式,加快新同事融入的速度,做了几次之后,我们发现效果不错,除了新同学有不少收获之外,老同志们也了解了之前自己并不熟悉的模块,大家都有收获。我们想到开源社区面临同样的问题,也可以通过这项工作收益,所以萌生了把这个活动做细做大的想法,于是有了这项活动。TiDB 作为一个开源项目,在开发过程中得到了社区的广泛关注,很多人在试用或者已经在线用 TiDB,并给出了很多很好的建议或者是问题反馈,帮助我们把项目做的更好。对于项目开发是这样,那么对于数据库技术的研究,也是这样。我们非常希望能和对数据库研究者、爱好者交流,我们在过去的两年中组织过近百场技术 Meetup 或者 Talk,在和大家的交流过程中,我们发现国内的数据库技术水平非常好,在交流过程中总能碰撞出火花。通过这项活动,我们希望能和大家做更深入的交流,通过源码阅读,让 TiDB 与大家 『坦诚相见』。前言 学习一种系统最好的方法是阅读一些经典著作并研究一个开源项目,数据库也不例外。单机数据库领域有很多好的开源项目,MySQL、PostgreSQL 是其中知名度最高的两个,不少人看过这两个项目的代码。我们在刚做数据库的时候也看过不少 MySQL、PG 的代码,从中受益良多。但是分布式数据库方面,好的开源项目并不多,有一些知名的系统并不开源,比如 F1/Spanner,还有一些系统疏于维护或者是从开源变成闭源,比如被 Apple 收购后闭源的 FoundationDB(还好当初 clone 了一份代码 :),参见 这里,我们在内部或者外部也组织过一些开源系统代码阅读的 Talk,不过并不系统。TiDB 目前获得了广泛的关注,特别是一些技术爱好者,希望能够参与这个项目。由于整个系统的复杂性,很多人并不能很好的理解整个项目。我们希望通过这一系列文章自顶向下,由浅入深,讲述 TiDB 的技术原理以及实现细节,帮助大家掌握这个项目。背景知识 本系列文章会聚焦在 TiDB 自身,读者需要有一些基本的知识,包括但不限于: Go 语言,不需要精通,但是至少要能读懂代码,知道 Goroutine、Channel、Sync 等组件的使用 数据库基础知识,了解一个单机数据库由哪些功能、哪些组件 SQL 基础知识,知道基本的 DDL、DML 语句,事务的基本常识 基本的后端服务知识,比如如何启动一个后台进程、RPC 是如何工作的 一些网络、操作系统的常识 总体而言,读者需要了解基本的数据库知识以及能看懂 Go 语言程序,我相信这一点对于大多数同学来说,并不是问题。 除了上述比较通用的知识之外,还希望读者能够看一下我之前写过的三篇文章(说存储,讲计算,论调度),了解一些 TiDB 的基本原理。读者可以有哪些收获 通过这一系列文章可以获得什么?首先是通过了解 TiDB 的基本原理,明白一个关系型数据库的基本原理;其次通过阅读 TiDB 的代码,知道一个数据库是如何实现的,将教科书中看到的数据库原理落地。第三,了解一个数据库的实现对其行为的影响,可以更好的理解数据库为什么是这样的,并推广到其他的数据库,相信对读者用好其他数据库也有帮助。第四,可以看到一个大型的分布式系统是如何设计、构建以及优化的。最后,大家理解了 TiDB 的代码后,如果后续工作中有需求,可以引用 TiDB 的代码,目前一些公司已经在自己的产品中用到了 TiDB 的部分模块,例如 Parser。内容概要 首先明确一个概念,一般来说我们提到 TiDB 是指整个分布式数据库,包括 tidb-server/pd-server/tikv-server 三大组件。由于整个项目比较复杂,又涉及到两种编程语言(Golang 和 Rust),想了解数据库相关的东西实际上只需要看 tidb-server 的代码即可。tikv-server 上面的计算相关逻辑也能够在 tidb-server 的代码中找到, 在 tidb-server 的代码目录下,可以找到一个叫 mock-tikv 的组件,这里利用本地存储模拟 tikv-server 的行为,这里能够找到不少和 tikv-server 上面一样的代码逻辑,特别是 Coprocessor 模块的逻辑,tikv-server 上的逻辑是从 mock-tikv 上移植过去的。所以本系列文章主要介绍 tidb-server 的代码,除非特别说明,文章中提到的 TiDB 就是指 tidb-server。这一系列文章会按照数据库的组件以及 SQL 处理的常见流程,讲解 Protocol 层,以及Parser、Preprocess、Optimizer、Executor、Storage Engine 等重要模块。从整体上分为两大部分,上半部分包括如下四篇文章: 第一篇文章介绍整体的架构,知道 TiDB 有哪些模块,分别是做什么的,从哪里入手比较好,哪些可以忽略,哪些需要仔细阅读。 第二篇文章从 SQL 处理流程出发,介绍哪里是入口,需要做哪些操作,知道一个 SQL 是从哪里进来的,在哪里处理,并从哪里返回。 第三篇文章从代码本身出发,介绍如何看懂某个模块的代码。 第四篇文章会引入一个例子,介绍如何让 TiDB 支持一个新的语法。 希望大家阅读完这部分后,对 TiDB 有了一定的基础,能够看懂大体流程,遇到问题或者想给 TiDB 添加一个新 Feature 的时候,不至于无从下手。下半部分会讲解的更深入,针对 TiDB 的每个重要模块进行讲解,包括优化器的详细实现、逻辑优化/物理优化是如何做的、重要的物理算子的实现等等。希望大家阅读后能对 TiDB 有深入的理解,能够完全理解 TiDB 的代码。这部分会比上半部分多很多,具体数量尚未定。这一系列文章也会作为 PingCAP 公司的内部培训资料,我们希望社区也能从中受益。所有文章会发布在 PingCAP 的微信公众号(微信号:pingcap2015)、知乎专栏以及 PingCAP 的官方博客,欢迎大家通过这些渠道关注。文章之外 除了这一系列文章之外,我们还有一个内部培训视频的开源计划,目前内部的源码讲解活动已经开展了 4 次,形式是由某一位同事花一周时间研究一个自己不熟悉的模块,然后用一个小时的时间给其他同事讲解。目的是让每个人了解所有的模块。这个培训还会继续下去,每次都录制了视频,我们计划将这些视频进行剪辑和整理,然后开放出来。近期会邀请一些社区贡献者做内部测试,然后根据他们意见做一些调整,再开放给整个社区。时间计划 这一系列文章刚开始提笔撰写,目前只是有一个大致的规划,我们会尽可能保证按照计划 Release 出来各篇文章。3 月中旬之前会发出上半部分的几篇文章,后续逐渐放出下半部分的文章。至于视频部分,要看剪辑以及测试的进度,我们会给出预告。一些期望 我们并没有编写系列教程的经验,希望在逐渐放出文章的过程中,能收到读者的反馈,指导我们不断改进这项工作,最终能够一起把这件事情做好。在整个活动过程中,我们会密切关注反馈,随时调整。除此之外,我们希望能有一起志同道合的人参与到 TiDB 的开发中来,可以通过开源社区,甚至是肉身投奔 :)。另外这一系列文章的目的在于帮助读者更好的理解 TiDB 源码,而不是替代阅读源码的过程。希望读者能在阅读源码的时候,以这些文章为参考,而不是只读文章,不看代码。切记『纸上得来终觉浅,绝知此事要 PR』。"}, {"url": "https://pingcap.com/weekly/2018-02-26-tidb-weekly/", "title": "Weekly update (February 12 ~ February 25, 2018)", "content": " Weekly update in TiDB Last two weeks, we landed 27 PRs in the TiDB repositories.Added Support the select 1 order by 1 syntax Fixed Fix the bug in insert statements when dropping columns Fix the bug when updating the stats table Improved Allow golint to check context.Context in make check Do not import golang.org/x/net/context as goctx alias Move the package context to sessionctx Add the recover mechanism for join workers Add StatementsPerTransaction and TransactionDuration metrics Add keep alive metrics to figure out whether TiDB instance is down Weekly update in TiKV and PD Last two weeks, we landed 13 PRs in the TiKV and PD repositories.Added Add peer label level statistics Support stream aggregation Support multiple Regions in tombstone Add a handler which is invoked after the client reconnects to PD Fixed Fix the misspelled word to improve GoReport Card Result Fix the panic caused by region not found Fix the bug of the hot region scheduler adding peers to down stores Improved Add the timestamp field for the Region heartbeat Increase the priority of replica checker’s operator Increase the default value of the replica scheduler limit "}, {"url": "https://pingcap.com/blog-cn/tidb-1.1-beta-release/", "title": "TiDB 1.1 Beta Release", "content": " 2018 年 2 月 24 日,TiDB 发布 1.1 Beta 版。该版本在 1.1 Alpha 版的基础上,对 MySQL 兼容性、系统稳定性做了很多改进。TiDB 添加更多监控项, 优化日志 兼容更多 MySQL 语法。 在 information_schema 中支持显示建表时间 提速包含 MaxOneRow 算子的查询 控制 Join 产生的中间结果集大小,进一步减少 Join 的内存使用 增加 tidb_config session 变量,输出当前 TiDB 配置 修复 Union 和 Index Join 算子中遇到的 panic 问题 修复 Sort Merge Join 算子在部分场景下结果错误的问题 修复 Show Index 语句显示正在添加过程中的索引的问题 修复 Drop Stats 语句失败的问题 优化 SQL 引擎查询性能,Sysbench 的 Select/OLTP 测试结果提升 10% 使用新的执行引擎提升优化器中的子查询计算速度。相比 1.0 版本,在 TPC-H 以及 TPC-DS 等测试中有显著提升 PD 增加 drop region 调试接口 支持设置 PD leader 优先级 支持配置特定 label 的节点不调度 raft leader 增加枚举各个 PD health 状态的接口 添加更多 metrics PD leader 尽量与 etcd leader 保持同步 提高 TiKV 宕机时数据恢复优先级和恢复速度 完善 data-dir 配置项的合法性较验 优化 region heartbeat 性能 修复热点调度破坏 label 约束的问题 其他稳定性问题修复 TiKV 使用 offset + limit 遍历 lock,消除潜在的 GC 问题 支持批量 resolve lock,提升 GC 速度 支持并行 GC,提升 GC 速度 使用 RocksDB compaction listener 更新 Region Size,让 PD 更精确的进行调度 使用 DeleteFilesInRanges 批量删除过期数据,提高 TiKV 启动速度 设置 Raft snapshot max size,防止遗留文件占用太多空间 tikv-ctl 支持更多修复操作 优化有序流式聚合操作 完善 metrics,修复 bug 源码地址:https://github.com/pingcap/tidb** 如今,在社区和 PingCAP 技术团队的共同努力下,TiDB 1.1 Beta 版已发布,在此感谢社区小伙伴们长久以来的参与和贡献。** 作为世界级开源的分布式关系型数据库,TiDB 灵感来自于 Google Spanner/F1,具备『分布式强一致性事务、在线弹性水平扩展、故障自恢复的高可用、跨数据中心多活』等核心特性。TiDB 于 2015 年 5 月在 GitHub 创建,同年 12 月发布 Alpha 版本,而后于 2016 年 6 月发布 Beta 版,12 月发布 RC1 版, 2017 年 3 月发布 RC2 版,6 月发布 RC3 版,8 月发布 RC4 版,并在 10 月发版 TiDB 1.0。 "}, {"url": "https://pingcap.com/blog/FOSDEM-2018-Rust-Devroom-reflection/", "title": "Bringing TiKV to Rust Devroom at FOSDEM 2018", "content": "At the crack of dawn on February 1, I landed in Brussels, Belgium, for the first time in my life. The goal of my trip wasn’t to taste the local cuisine, tour world-famous museums, or grab a pint of the local brew (though I ended up doing all those things anyway). It was to deliver a talk three days later at “FOSDEM 2018 Rust Devroom” about our experience at PingCAP using Rust to build TiKV, a distributed transactional Key-Value storage engine.FOSDEM 2018 Rust Devroom is the 1st edition of a dedicated Rust venue co-located with FOSDEM 2018. It was, by all accounts, very popular; at least a few hundred people visited the Rust Devroom, where my talk was supposed to be held. Because the room could only hold about 120 people, people had to line up to get into talks. When I showed up for my event, there was already a long line snaking through the hallway. I lined up with everyone else and almost didn’t get into my own talk!People lining up to listen to their favorite Rust talk. Photo credit: Andrew HobdenYou can find the slides of my presentation here and the full video here. But we are all busy people, so just in case you don’t have time to go through it all, here’s a summary of the highlights and where you can go learn more!Building TiKV, a distributed key-value store with RustBuilding a distributed key-value store with RustPresenting in front of a group of Rustaceans at FOSDEM 2018. Photo credit: Andrew HobdenIn my talk, I shared our experiences on the following topics from our process of building TiKV: Why another database and the challenges of building a modern distributed transactional Key-Value store: consistency, horizontal scalability, scalability, stability, performance, ACID compliance, High Availability, etc. How we build the TiKV core system using Rust, including the backend store, the gRPC framework, and the consensus replication mechanism. Backend store: TiKV adopts RocksDB as the backend storage engine for its high-performance and fast storage, and usesRaft and Multi-raft to ensure data safety and horizontal scalability. We implemented the Raft Consensus algorithm in Rust. Transaction: As a distributed Key-Value database, TiKV also supports transaction and is ACID compliant. To maintain consistency among the Multi-raft groups, TiKV adopts an optimized two-phase commit (2PC) protocol and supports Multiversion Concurrency Control (MVCC), Snapshot Isolation, and Optimistic Transaction. For different machines to communicate to each other, TiKV uses gRPC, a high-performance universal RPC framework. We develop agRPC library for Rust built on C Core library and futures. How we monitor the cluster and diagnose problems: to monitor the metrics of the cluster and gain insights, TiKV adopts Prometheus as the monitoring solution. We build a Prometheus instrumentation library for Rust applications, which is listed as a third-party client on the Official Prometheus Client Libraries. How we use the failure injection test to guarantee data safety. Inspired by FreeBSD’s failpoints, TiKV implemented a fail point to inject errors by users at runtime in Rust. The following diagram shows the TiKV architecture:TiKV ArchitectureOur team has big plans beyond just building a full-featured distributed transactional Key-Value database like TiKV. We have already built a stateless SQL layer, TiDB, mainly for Online transaction processing (OLTP) that works directly with TiKV, and TiSpark, an Apache Spark driver which sits on top of TiKV for handling heavy Online analytical processing (OLAP) workloads. Our ultimate vision is to build a Hybrid Transactional/Analytical Processing database that empowers businesses to meet both workloads with a single database and enables real-time business analysis based on live transactional data.Architecture of TiDB, a Hybrid Transactional/Analytical Processing (HTAP) databaseTiKV, TiDB, and TiSpark have been widely adopted in production environments by companies, ranging from e-commerce and gaming to financial services and bike-sharing. We are working to publish specific use case stories from our customers soon, and the best way to receive them is to subscribe to our blog. Stay tuned for more!Last but not least, we welcome everyone to fork, star, use, and contribute to the following projects that we’ve written in Rust for TiKV: Rustwrapper for RocksDB Raft Consensus algorithm implemented in Rust gRPC library for Rust built on C Core library and futures Prometheus instrumentation library for Rust applications Fail points for Rust We look forward to building a strong and vibrant Rust community together!"}, {"url": "https://pingcap.com/weekly/2018-02-12-tidb-weekly/", "title": "Weekly update (February 05 ~ February 11, 2018)", "content": " Weekly update in TiDB Last week, we landed 67 PRs in the TiDB repositories.Added CreateIndex supports the LOCK option. Add GoVersion info for tidb_version Add a session variable to show the configuration Support show stats_healthy to check if a table needs to be analyzed Removed Remove the useless field in jsonColumn Clean up the abandoned storage engine Fixed Check the CreateTable statement charset option Fix the bug of show index printing non-public index when add index operation is not finished Treat a decimal truncate as a warning in update Improved Run GC workers parallelly Pass the operator label from Plan to Executor Prepare the candidate index to improve performance Use pseudo estimation when the stats of some table is outdated Ignore the error and keep GC always working Set a min count for AutoAnalyze to avoid the auto analysis of small tables Improve importer tools: Support randDate by statistics Support generating other types of columns randomly by statistics Generate a string by statistics Support VARCHAR in set Generate the integer data by Histogram Refine metrics in TiDB: Rename _count to _num Unify metrics naming Add a metric for pseudo estimation Make metrics content clearer and compacter Move domain metrics and add the privilege load counter Add metrics for DDL and the server Add metrics for the DDL worker Add metrics for expensive executors and statement nodes Add metrics for stats Fix inconsistent labels for the panic counter Move DDL metrics from the ddl package to the metrics package Refine TiKV client metrics Add metrics for the DDL owner Add metrics and logs for ticlient Weekly update in TiSpark Last week, we landed 6 PRs in the TiSpark repositories.Improved Change the remote repository for the test data Add JDBC write guide usage Fixed Fix key range corner cases Fix the bug of group by without aggregates Fix the resetFilters method Fix the character decoding charset Weekly update in TiKV and PD Last week, we landed 19 PRs in the TiKV and PD repositories.Added Add the read pool Introduce the label property and the label scheduler Support configuring the label scheduler and the label property Fixed Fix the bug caused by limit=0 or by no limit Improved Add the file name and the line number for the box error Record the leader missing information Filter Store when counting the average leader and score Add stale_command in ASYNC_REQUESTS_COUNTER_VEC Check whether range.start < range.end Change the unit of heartbeat from ts to ms Limit the maximum total size of snapshot Collect gRPC logs Save the critical metadata in metrics Use local metrics Adjust the status of the store New contributor (Thanks!) TiDB: caojiafeng "}, {"url": "https://pingcap.com/weekly/2018-02-05-tidb-weekly/", "title": "Weekly update (January 29 ~ February 04, 2018)", "content": " Weekly update in TiDB Last week, we landed 35 PRs in the TiDB repositories.Added Support the load stats command Removed Remove iota in DDL package to make the constant clearer Fixed limit and offset can be parameter markers in the prepared statement IndexOption can be a list in creating a table Fix the bug of some field length missing in creating a table Fix the bug of parsing Datetime overflow Trim leading zeros before parsing integer literal Fix the float truncate bug Improved Importer tools support loadStats by path Support mock table info for importer tools Let DO statement be a read only statement Improve an error handling in ddl Reduce memory allocation in buildDataSource Make Explain clearer Add the metrics package and recover Panic of Worker Refine the joinResult generator to return maxChunkSize chunk Limit lock count for ScanLock request Enhance the IndexRange calculation Refine metrics in TiDB: Refine DistSQL metrics Add metrics for the meta package Move and refine the server metrics Add metrics for DDL syncer Update metrics for session Weekly update in TiSpark Last week, we landed 6 PRs in the TiSpark repositories.Improved Switch integration test to scalatest framework Fixed Fix Average on BIGINT overflow Fix scala version for some libraries Weekly update in TiKV and PD Last week, we landed 22 PRs in the TiKV and PD repositories.Added PD: implement GetAllStores API TiKV: implement GetAllStores API Add PD health API Support setting leader priority to etcd members Sync the PD leader with the etcd leader Add the future pool Fixed Fix hot Region DistinctScoreFilter Fix and update Region size Fix cleanup for raw KV Improved Check Range for DAG and analysis Sync the snapshots Remove the sync snapshot file Add operator duration metrics Support simple command line args Add Region statistics Clear stale data using DeleteFilesInRanges New contributor (Thanks!) TiDB: Boik "}, {"url": "https://pingcap.com/weekly/2018-01-29-tidb-weekly/", "title": "Weekly update (January 22 ~ January 28, 2018)", "content": " Weekly update in TiDB Last week, we landed 28 PRs in the TiDB repositories.Added Add the importer tool Add metrics for GC failure count Add metrics for TiDB-server panic Add metrics for async secondary lock cleanup Support create time in information_schema Removed Remove GetSessionVars() in expression evaluation Remove varsutil package, and make Systems a private member of SessionVars Fixed Avoid the generation of mysql.TypeNewDate Push down binaryliterals as varstring Improved Keep slow query log entry in order Make list.MemoryUsage() more efficient Limit statement count in a transaction Remove WithCancel in copIterator Uniform the way of iterating rows within a Chunk Weekly update in TiSpark Last week, we landed 4 PRs in the TiSpark repositories.Improved Improve index double read performance by around 30% Verify and add document for Hive integration Fixed Fix test for between expression Add placeholder for unsupported type preventing schema reading crash Weekly update in TiKV and PD Last week, we landed 17 PRs in the TiKV and PD repositories.Added Add ImportSST/UploadSST API Add drop region admin command Fixed Convert int to decimal in sum Fix join failure when log dir is the same as data dir Disable the portable on MacOS Improved Limit data size for scan lock Add metrics for checkers Remove schedule empty apply task Ignore Prometheus encoding error Debug trait for snapshot Reduce the lock overhead Update the region size New contributor (Thanks!) TiDB: yuananf "}, {"url": "https://pingcap.com/blog/tidb-devcon-2018-recap/", "title": "TiDB DevCon 2018 Recap - News, Latest Development, and Roadmap", "content": " On January 20th, 2018, a chilly Saturday in the middle of the winter, more than 200 coders, hackers, and techies streamed into Garage Café, a chic coffee shop in the heart of Beijing’s techhub, Zhongguancun. They weren’t there to get coffee. They weren’t there to stay warm. They were there to be part of TiDB DevCon 2018, a technology party for the developers, by the developers.TiDB DevCon 2018 attendees signing-in on the event bannerA packed audience at TiDB DevCon 2018At this party, the team behind TiDB announced exciting news, shared the project’s latest development, and unveiled the future plans of the TiDB project. Here are some important news and highlights:PingCAP co-founder and CEO, Max Liu, giving the opening address at TiDB DevCon 2018 Team Community Partners TiDB 1.1 Alpha Release Performance & latency TiDB Lightning Tools and Ecosystem TiDB deployment Import & Export Tools TiDB Syncer TiDB Binlog TiDB Lightning Wormhole–Enterprise synchronization tool TiDB Insight Monitoring & Alerting 2018 Roadmap Team The team behind TiDB, PingCAP, grew from 35 members in 2016 to almost 90 members in 2017.Community Github stars on the TiDB project (TiDB and TiKV combined) reached 14000+ in January 2018, almost doubled its number in January 2017. Number of contributors reached 213, an increase of 126%. More than 200 users are running TiDB in production environments, 50 times more than 2016. Three distinguished TiDB contributors were recognized as TiDB committers. For more information about how to join the TiDB community, see TiDB Community repo and How to become a TiDB committer. PingCAP co-founder & CTO, Ed Huang (left), recognizing three distinguished TiDB contributors as TiDB committer Partners Designed to be a cloud-native HTAP database, TiDB has been fully integrated and available on UCloud and Tencent Cloud. Close partnerships with other public cloud vendors will be announced soon. Stay tuned!Some of TiDB’s largest customers, Mobike, Toutiao, SpeedyCloud, Qunar.com, Ele.me, also shared their use cases and best practices:A Senior Manager of the databse team at Mobike, sharing their best practices of TiDBTech Lead of the Database Middleware and Distributed Database Team at Toutiao, sharing their best practices of TiDBTech lead of the architecture team in the Technical Innovation department at Ele.me, sharing their use case with TiDBSenior Database Administrator at Qunar.com, sharing their best pratices of TiDBSenior Database Architect at SpeedyCloud, sharing their query cache in TiDBTiDB 1.1 Alpha Release On January 19th, one day before DevCon, TiDB 1.1 Alpha was released with the following improvements:Performance & latency Average QPS of TiDB increased by 50%. To support requirement from Toutiao, TiDB 1.1 Alpha is able to scale auto-increment ID and achieve 16x speed improvement for queries like alter table t shard_row_id_bits = 4 and is also able to handle millions of TPS. Read QPS speed of TiKV improved by 2x. Counting table is now 70% faster than the previous version. Hash-join is 3 times faster than the previous version. Some complex queries using index are now more than 10x faster than the previous version. Cost based optimizer (CBO) is smarter. Loading data using the following statement is now 15x faster: load data local infile 'output.csv' into table xxx; TiDB Lightning With TiDB Lightning, it takes less than 5 hours to import 1 TB of raw SQL file from MySQL to TiDB–10x faster than before.Tools and Ecosystem TiDB deployment Deploying a TiDB cluster is much easier than ever before. Developers can use Docker Compose to launch a local TiDB cluster with one command on their laptops and play around with it. Moreover, the container-based components of TiDB managed by a special software named tidb-operator can be simply deployed and maintained on a Kubernetes environment in production.Import & Export Tools TiDB Syncer TiDB Syncer is a smart tool to migrate data from MySQL to TiDB in real-time. It poses as a MySQL slave and listens to the changes of master by parsing the MySQL Binary Logs, and replaying the changes sequentially on the TiDB instance.TiDB SyncerTiDB Binlog TiDB Binlog is a tool designed to help users to synchronize data to downstream database in real-time. For example, users can use TiDB binlog to synchronize data from one TiDB instance to another as a Hot-backup cluster. In addition, TiDB Binlog can also be used for other purposes, such as incremental backup, message triggering and subscription or driving stream computing and analytics.BinlogTiDB Lightning Lightning is a high-speed data importing tool, customized for TiDB:TiDB LightningWormhole–Enterprise synchronization tool Wormhole is an enterprise edition tool for data synchronization. It contains the following features: Web UI dashboard Multi-source and destination configuration Distributed scheduling Sharding source supported Pre-checking Lightweight ETL in real-time Cloud DB integration with: AliCloud RDS TencentCloud CDB Wormhole–Enterprise synchronization toolTiDB Insight TiDB Insight provides users with a real-time visualization and overview into the region distribution, leader regions status, hotspots, region & leader transfer, traffic flow, and the health of the entire cluster.TiDB InsightMonitoring & Alerting The TiDB monitoring system collects metrics from TiDB cluster and is integrated with Grafana to visualize data. Alerts are defined based on Prometheus’s flexible query language. And the alerting system can keep users informed of any abnormal status in their TiDB cluster via email, SMS, Slack messages, or other customized ways.TiDB Monitoring & Alerting2018 Roadmap After recapping all the news and developments from an exciting and productive 2017, PingCAP co-founder and CEO, Max Liu, unveiled TiDB’s 2018 roadmap.PingCAP co-founder and CEO, Max Liu, sharing TiDB’s 2018 roadmap Region level SQL query cache (2018 Q1) View (2018 Q1) Region merging (2018 Q1) Partition table (2018 Q2-Q3) Customized Raft storage engine (2018 Q3) Blob storage to reduce compaction (2018 Q3 working with RocksDB team) Full-text search (2018 Q4) Geo-Index (2018 Q4-2019 Q1) Window function (2018 Q4) Last but not least, we want to thank all the attendees for braving the cold to participate in the first (but definitely not the last) TiDB DevCon, all the speakers from our customer companies to share their use cases and best practices, and all the amazing contributors to the vibrant and growing TiDB community. We know you have big hopes for 2018; we won’t let you down.DevCon 2018 Group Photo"}, {"url": "https://pingcap.com/weekly/2018-01-22-tidb-weekly/", "title": "Weekly update (January 15 ~ January 21, 2018)", "content": " Weekly update in TiDB Last week, we landed 43 PRs in the TiDB repositories.Added Add an interface for Chunk to count the memory usage Add a session variable to log the query string Removed Remove the old, never used IndexLookUpJoin Fixed group_concat should not modify the argument during execution Correct the unsigned pk’s behavior Improved Optimize the com_field_list command and make Use Database faster Improve the sort efficiency on lookupTableTask.rows Enlarge the default distsql_scan_concurrency Log a warning when the memory usage of HashJoinExec exceeds threshhold Refine the behavior when updating StatsDelta Split the presentation and evaluation layers of aggregation functions Use BatchGet to speed up LOAD DATA Weekly update in TiSpark Last week, we landed 13 PRs in the TiSpark repositories.Improved Refactor the type and expression systems totally Reorganize the type and expressions Use the visitor instead of raw expressions when processing traversal Fixed type infer logics Refactor predicates processing logic according to the visitor pattern Fixed index encoding Change CodecDataInput to use non-synchronized ByteArrayInputStream Add TiKV, PD, and TiDB’s config files for Docker test environment Weekly update in TiKV and PD Last week, we landed 18 PRs in the TiKV and PD repositories.Added simulator: add hot region cases Fixed proto: compatible with proto3 heartbeat: rebind the stream server: delete overlap from etcd Improved Refactor the raftstore Callback API Remove the unused rocksdb.backup_dir Adjust Scheduler metrics impl Runnable for Scheduler "}, {"url": "https://pingcap.com/blog-cn/tidb-1.1-alpha-release/", "title": "TiDB 1.1 Alpha Release", "content": " 2018 年 1 月 19 日,TiDB 发布 1.1 Alpha 版。该版本对 MySQL 兼容性、SQL 优化器、系统稳定性、性能做了大量的工作。TiDB SQL parser 兼容更多语法 SQL 查询优化器 统计信息减小内存占用 优化统计信息启动时载入的时间 更精确的代价估算 使用 Count-Min Sketch 更精确的估算点查的代价 支持更复杂的条件,更充分使用索引 SQL 执行器 使用 Chunk 结构重构所有执行器算子,提升分析型语句执行性能,减少内存占用 优化 INSERT INGORE 语句性能 下推更多的类型和函数 支持更多的 SQL_MODE 优化 Load Data 性能,速度提升 10 倍 优化 Use Database 性能 支持对物理算子内存使用进行统计 Server 支持 PROXY protocol PD 增加更多的 API 支持 TLS 给 Simulator 增加更多的 case 调度适应不同的 region size Fix 了一些调度的 bug TiKV 支持 Raft learner 优化 Raft Snapshot,减少 IO 开销 支持 TLS 优化 RocksDB 配置,提升性能 Coprocessor 支持更多下推操作 增加更多的 Failpoint 以及稳定性测试 case 解决 PD 和 TiKV 之间重连的问题 增强数据恢复工具 TiKV-CTL 的功能 region 支持按 table 进行分裂 支持 delete range 功能 支持设置 snapshot 导致的 IO 上限 完善流控机制 源码地址:https://github.com/pingcap/tidb如今,在社区和 PingCAP 技术团队的共同努力下,TiDB 1.1 Alpha 版已发布,在此感谢社区的小伙伴们长久以来的参与和贡献。 作为世界级开源的分布式关系型数据库,TiDB 灵感来自于 Google Spanner/F1,具备『分布式强一致性事务、在线弹性水平扩展、故障自恢复的高可用、跨数据中心多活』等核心特性。TiDB 于 2015 年 5 月在 GitHub 创建,同年 12 月发布 Alpha 版本,而后于 2016 年 6 月发布 Beta 版,12 月发布 RC1 版, 2017 年 3 月发布 RC2 版,6月份发布 RC3 版,8月份发布 RC4 版,并在 10 月发版 TiDB 1.0。 "}, {"url": "https://pingcap.com/weekly/2018-01-15-tidb-weekly/", "title": "Weekly update (January 08 ~ January 14, 2018)", "content": " Weekly update in TiDB Last week, we landed 43 PRs in the TiDB repositories.Added Support the ODBC syntax of time/date/timestamp literal Add MaxProcs and make the runtime.GOMAXPROCS parameter configurable Fixed Fix a bug about index join Close HashJoin goroutines as soon as possible to avoid unexpected errors fetchShowTableStatus should append an integer to the third column instead of a string Correct the behavior when RunWorker is false Refine the typeInfer of group_concat Improved Avoid the Children type assertion Merge IntColumnRange with NewRange Upgrade the username length limit to 32 to be compatible with MySQL 5.7 Garbage collects useless stats info InsertExec eliminates unnecessary CastValue operations Speed up row count estimation Support encoding a Chunk row Use dep instead of glide Optimize the insert ignore statement Support Chunk in: HashJoinExec ExecuteExec Weekly update in TiKV and PD Last week, we landed 25 PRs in the TiKV and PD repositories.Added Add the node case Support Region split Support query regions by read/write flow Fixed Change the version Fix a RocksDB task name error Cancel call when refreshing client Improved Use dep instead of glide Optimize write type parsing for MVCC properties collector Update README and upgrade Dockerfile golang:1.9.2 Specify gRPC event engine Add the debug log Fix some ineffassign to improve the GoReport Result Rename AggregationExecutor to HashAggExecutor Improve the GoReport Result Dump the ConfChange type Raft log entry Make meta key return array New contributor (Thanks!) PD: maiyang "}, {"url": "https://pingcap.com/weekly/2018-01-08-tidb-weekly/", "title": "Weekly update (January 01 ~ January 07, 2018)", "content": " Weekly update in TiDB Last week, we landed 37 PRs in the TiDB repositories.Added Support the PACK_KEYS option in the CreateTable statement. Show job’s start time in the result of admin show ddl .... Fixed Fix a bug when initializing HTTP stats handler. Fix a bug when estimating row count for outdated histograms. Consider time zone for builtin functions curtime/sysdate/curdate. Improved Refactor Chunk.AppendRow to handle virtual. Refactor hybrid type expressions. Only do a shallow copy when evaluating a “Column” expression. Refine the design of schema. Use more compact structure for histograms. Convert the aggregation operator max/min to topN. Shard the implicit row ID to avoid hot spot. Support Chunk for StreamAggExec. Support Chunk for HashAggExec. Weekly update in TiSpark Last week, we landed 4 PRs in the TiSpark repositories.Improved Add potential missing test cases. Simplify Aggregation pushdown. Fixed Fix the dependency for jackson and joda-time. Fix the error handling logic. Weekly update in TiKV and PD Last week, we landed 10 PRs in the TiKV and PD repositories.Added Add timer to support worker timeout later. tikv-ctl: add bad-regions subcommand. coprocessor/endpoint: initialize runtime in response. Fixed tests: fix some failpoints name. scheduler: fix hot region scheduler select store problem. Fix the score when region size is zero. Improved raftstore: add Lease. util: remove BatchRunnable and use Runnable instead. tests: remove redundant storage tests. Change github.com/Sirupsen/logrus to github.com/sirupsen/logrus. New contributor (Thanks!) TiDB: Cruth kvinc "}, {"url": "https://pingcap.com/weekly/2018-01-02-tidb-weekly/", "title": "Weekly update (December 25 ~ December 31, 2017)", "content": " Weekly update in TiDB Last week, we landed 36 PRs in the TiDB repositories.Added Add the Iterator interface in Chunk. Removed Remove the useless aggregation function during buildQuantifierPlan. Fixed Flen and Decimal of TypeNewDecimal should not be -1. To pass sysbench Prepare tests, set Fields for SelectStmt in PrepareExec. Fix the case that fails to split a table. Correct the type inference of the sum and avg functions. Make set transaction read only work, compatible with JDBC connector. Improved Change BuildRange to build column/index/table range to improve performance. Make KvEncoder support encoding Prepare SQL. Refine codes about maxOneRow. Use chunk.Iterator for joinGenerator. Merge ranger.IndexRange and ranger.ColumnRange to ranger.NewRange. Reduce allocation for DetachCondsForSelectivity, and add a Filter function. Support alter table auto_increment. Support pushing down stream aggregation on mocktikv. Support Chunk in executors: NestedLoopApply UnionScanExec Weekly update in TiSpark Last week, we landed 12 PRs in the TiSpark repositories.Improved Dynamically downgrade the index scan plan to table scan plan. Optimize the column logic of Aggregation pushing down. Add the date type pushing down logic. Reduce dependencies. Add tests for issues. Add switching to ignore the unsupported type. Use the parent child POM mode instead of submodule. Fixed Fix the NPE issue of Aggregation pushing down. Remove time test cases. Modify integration scripts and .gitignore files. Remove the Scala lang provided in the POM file. Delete the unnecessary variable. Weekly update in TiKV and PD Last week, we landed 18 PRs in the TiKV and PD repositories.Added Support builtin aggregation functions bit_and, 'bit_or and bit_xor in Coprocessor. Upgrade the version of gRPC-rs to 0.2. Make delete_range configurable. Enable table split by default. Add trend API in PD. Increase the priority of the raftstore thread. Add ScatterRegion API in PD. Move SST instead of copying in injestion. Update the version of fail-rs to 0.2. Fixed Fix the return type of avg and sum in Coprocessor. Catch stale command in the scheduler. Fix build error on macOS. Improved Clean up the select interface in Coprocessor. Collect metrics more efficiently in Coprocessor. Make fail point tests more stable. New contributor (Thanks!) TiKV: Rain Li "}, {"url": "https://pingcap.com/blog/pingcap-reflection-and-gratitude/", "title": "2017 Reflection and Gratitude", "content": " In open source, we trust!2017 has witnessed the growth of PingCAP, from Beijing to Silicon Valley, and the evolution of TiDB, from RC1 to the 1.0 release, and then to the 1.0.5 release. As our CEO Max said in the TiDB 1.0 announcement, “because of the hard work and dedication of not just every member of our team, but also every contributor, user, and partner in our open source community.“As 2017 draws to a close, let’s take a look back upon the highlights that shape PingCAP and TiDB:Community 1818 forks 13000+ stars 1106 watches 210+ contributors 41 weekly updates 26 PingCAP Infra Meetups 1 of the gRPC popular projects Listed on the CNCF Cloud Native Landscape Merged 14 PRs to RocksDB and 5 PRs to etcd 40 changed files in 1 PR from Samsung Electronics Cloud A cloud-native HTAP Database on UCloud and Tencent Cloud Product 30+ customers in APAC region 1.0 Release, marking the production readiness of TiDB 1st version of TiSpark: sitting SparkSQL on top of TiKV. Distributed HTAP made possible Meetup 1st Rust China Meetup Siddon’s talk atRust meetup in Bay area Siddon’s talk at RocksDB meetup in Bay area 2nd invitation to Percona Live for Speech (Edward) Company $15M in Series B funding led by China Growth Capital 1st of many steps towards a global impact by opening the Silicon Valley office We connect, contribute, collaborate, and we will never stop.Thank you all, our beloved contributors, customers, and partners, for an amazing 2017!Hello, 2018!See the following infographic for a recap of PingCAP in 2017:"}, {"url": "https://pingcap.com/weekly/2017-12-25-tidb-weekly/", "title": "Weekly update (December 18 ~ December 24, 2017)", "content": " Weekly update in TiDB Last week, we landed 48 PRs in the TiDB repositories.Added Support the builtin aggregation function bit_or. Removed Remove the old JSON type. Remove the HashSemiJoin plan and executor. Fixed Support showing the current auto_increment id in the result of show create table. Fix a bug of NewIndexLookUpJoin's Next(). Fix the trigger condition for AutoAnalyze. Only rebuild the range when using prepared cache. Improved Merge ApplyExec and NestedLoopJoin into NestedLoopApply. Refine the UnionAll plan building. Metrics: record details of the RPC type and store id. Replace JSON with BinaryJSON. Collect and store the query feedback. Make the function ExtractColumns more efficient. Add BinaryJSON functions. Enhance the index join, making it can be used for more scenarios. Graceful shutdown will wait clients to close. Support Chunk in executors: LoadData GrantExec RevokeExec DeallocateExec SimpleExec AnalyzeExec TableScanExec ShowDDLjobsExec TableDualExec ReplaceExec DeleteExec MergeJoinExec Weekly update in TiSpark Last week, we landed 10 PRs in the TiSpark repositories.Added Add counting single column tests. Add request.timezone.offset config. Add the test framework for each issue. Add index related integration tests. Add debug utils. Add null data for DAG test cases. Removed Remove timezone in the TisparkTest.sql file. Fixed Fix the Load tests problem. Fix the test framework concerning null tests. Weekly update in TiKV and PD Last week, we landed 13 PRs in the TiKV and PD repositories.Added Support Raft Learner. Add transaction tests with fail-rs. Add more configurations for the RocksDB column family. Add more complex configurations for the PD simulator. Coprocessor: collect output counts for each executor. Fixed PD: support join without scheme. Return the stale epoch error for retry. Add the require option to the addr command flag. Update rustc_serialize to pass newer Rust version compilation. Improved Coprocessor: speed up the CM sketch test. Add key_only to avoid fetching the data value. Avoid calling Raft status to reduce allocation. New contributors (Thanks!) TiKV: Jiahao Huang Andrew Hobden "}, {"url": "https://pingcap.com/meetup/meetup-2017-12-23/", "title": "【Infra Meetup No.60】初探 Orca 查询优化器", "content": " 上周六,PingCAP Infra Meetup 迎来了第 60 期 👏 由我司 “SQL 小王子”韩飞同学出台,为大家带来了《初探 Orca 查询优化器》主题分享~视频回顾 视频 | Infra Meetup No.60:初探 Orca 查询优化器可下载 完整 PPT 配合观看干货节选 Orca 优化器是基于代价面向 MPP 执行引擎的优化器,使用了先进 Cascades 模型,将优化分为 Exploration,Stats Derivation,Implemetation 等阶段。Orca 优化器可以将优化任务分解,利用多核 CPU 并行执行,以加快优化速度。知乎上有个热门问题:在做一个数据库的过程中,最难的是哪个部分?很多人都认为查询优化器可能是数据库中一个最难的部分。也有人会有疑问:一个 SQL 生成一个执行计划可能是一个很确定的事情,为什么会是最难的?对此,韩飞同学表示,难点主要集中在基于代价的物理计划生成。在本次分享中,韩飞同学从逻辑计划的优化及物理计划的优化讲起,重点介绍了 Orca 优化器的架构,算法实现,优化效果以及测试保证等问题。 PingCAP Infra Meetup作为一个基础架构领域的前沿技术公司,PingCAP 希望能为国内真正关注技术本身的 Hackers 打造一个自由分享的平台。自 2016 年 3 月 5 日开始,我们定期在周六的上午举办 Infra Meetup,邀请业内大牛与大家深度探讨基础架构领域的前瞻性技术思考与经验。在这里,我们希望提供一个高水准的前沿技术讨论空间,让大家真正感受到自由的开源精神魅力。 "}, {"url": "https://pingcap.com/meetup/meetup-20171223-no60/", "title": "【Infra Meetup No.60】初探 Orca 查询优化器", "content": " 上周六,PingCAP Infra Meetup 迎来了第 60 期 👏 由我司 “SQL 小王子”韩飞同学出台,为大家带来了《初探 Orca 查询优化器》主题分享~视频回顾 视频 | Infra Meetup No.60:初探 Orca 查询优化器可下载 完整 PPT 配合观看干货节选 Orca 优化器是基于代价面向 MPP 执行引擎的优化器,使用了先进 Cascades 模型,将优化分为 Exploration,Stats Derivation,Implemetation 等阶段。Orca 优化器可以将优化任务分解,利用多核 CPU 并行执行,以加快优化速度。知乎上有个热门问题:在做一个数据库的过程中,最难的是哪个部分?很多人都认为查询优化器可能是数据库中一个最难的部分。也有人会有疑问:一个 SQL 生成一个执行计划可能是一个很确定的事情,为什么会是最难的?对此,韩飞同学表示,难点主要集中在基于代价的物理计划生成。在本次分享中,韩飞同学从逻辑计划的优化及物理计划的优化讲起,重点介绍了 Orca 优化器的架构,算法实现,优化效果以及测试保证等问题。 PingCAP Infra Meetup作为一个基础架构领域的前沿技术公司,PingCAP 希望能为国内真正关注技术本身的 Hackers 打造一个自由分享的平台。自 2016 年 3 月 5 日开始,我们定期在周六的上午举办 Infra Meetup,邀请业内大牛与大家深度探讨基础架构领域的前瞻性技术思考与经验。在这里,我们希望提供一个高水准的前沿技术讨论空间,让大家真正感受到自由的开源精神魅力。 "}, {"url": "https://pingcap.com/blog/Time-in-Distributed-Systems/", "title": "Tick or Tock? Keeping Time and Order in Distributed Databases", "content": " Preface At re:Invent 2017, Amazon Web Services (AWS) announced Amazon Time Sync Service, a highly accurate and reliable time reference that is natively accessible from Amazon EC2 instances. It is much like the Google TrueTime published in 2012. Why do Google and AWS both want to make efforts to provide global time service? Is there any inspiration for building distributed database? This topic is important to think about.Time synchronization remains a hard nut to crack in distributed systems, especially for distributed databases such as TiDB where time is used to confirm the order of the transaction to guarantee the ACID compliance.In this post, I will introduce the existing solutions to tackle the time synchronization issue in distributed systems, as well as their pros and cons. I will also share why we chose to use the timestamp oracle (TSO) from Google Percolator in TiDB.Order of the events Linearizability is important for distributed systems, especially for distributed databases. We can’t allow reading stale value after the update. For example, if account A has $100, and transfers $10 to B. After the transaction finishes, we can’t read $100 again from account A.Another simple explanation is: if we write a data at time T1 like set a = 10, after T1, we must always read 10 as the value of a, not 11 or any other values.But how can we ensure we can read the newest data? How can we know the order of two events?We usually use “happened before”(hb or ->) to describe the relationship of two causal events. For two events e1 and e2, e1 -> e2, we can say that e1 happened before e2, or e1 causes e2.If we have only one process, determining the order is easy, because all the events can only happen in the process in sequence. However, in a distributed system, things become more complex. The events may happen in different places, and it becomes hard to determine the order of all the events.At first, we may consider using wall time, but the time is not the same in all the processes – one process may run faster, and the other process may walk slower. So we can’t use the time directly to check the order of the events. Luckily, we have other ways to do it.Logical clock A simple way is to use logical clock which was proposed by Lamport in 1978 for timestamping and ordering events in a distributed system. The algorithm is: Every process starts with an initialized clock counter. A process increments the value of its counter before each event in that process. When a process sends a message, it includes the counter value with the message. When a process receives a message, it increases its clock counter value to be bigger than both its current clock counter value and the value in the received message. If two events have the same clock value, we may think they happen simultaneously so we should use process ID or any other unique ID to differentiate them. Using this can easily determine the order of events. For example, assuming we have processes P1, P2, both with an initialized counter value 0. P1 increases the counter value to 1 and executes event A. P2 wants to do something but needs to know the result of the event A, so it increases its counter to 1 and sends a message with counter 1 to P1. P1 receives the message and increases its counter to 2, then increases the counter to 3 and replies to P2. P2 receives the message and increases the counter to 4 then executes event B with counter 5. We use C(A) and C(B) as the counter value of the events, if events A and B happen in one process, and A happens before B, we can know that C(A) < C(B). If A and B happen in different processes, we can also know C(A) < C(B) based on the message, so if A happens before B, we can infer C(A) < C(B). But if C(A) < C(B), it doesn’t necessarily mean that A happens before B.If the two events are not causally related (no communication between the processes), we can’t determine the order of the events. We can use vector clock to fix this. But whether it’s logical clock or vector clock, they both have a disadvantage: we can’t know what time the event happens because both of the two clocks merely record the order of the events instead of the time.To get the chronological order of the events, we have to go back to square one and use real time. But we can’t depend on Network Time Protocol (NTP) directly because it has some errors and the time is not accurate, so what should we do?TrueTime In Google Spanner, it uses TrueTime API to fix the problem of time. Spanner uses GPS and Atomic Clock to correct the time and can guarantee clock uncertainty bound (ε) is very small. The ε value is less than 7ms in 2012; it may be less now.The TrueTime API is very simple: Method Return TT.now() TTinterval: [earliest, latest] TT.after(t) true if t has definitely passed TT.before(t) true if t has definitely not arrived Spanner can’t get an accurate time point but only an interval. We can use function now to get an interval. Assuming event A happens at the time point tt.a, and tt.b is for event B. We can know that tt.a.earliest <= tt.a <= tt.a.latest. For event A and B, if A happens before B, we can infer tt.a.latest < tt.b.earliest.Because TrueTime has the clock uncertainty bound ε, so for every transaction commit, it must wait 2ε time to guarantee linearizability, but ε is so small that the performance is still high.The biggest hurdle to adopting TrueTime is that it depends on special hardware, such as GPS clocks and atomic clocks, which many companies do not have.Hybrid Logical Clock Hybrid logical clock (HLC) is another way for timekeeping and timestamping in distributed systems.Based on NTP, HLC can only read time from NTP, but it won’t change it. HLC contains two parts: physical clock + logical clock. For example, assuming: pt: the physical time l: the maximum of pt information learned so far c: the logical clock To compare the order of two events, we can first check their l time, if equal, we can check c time, for any two events e and f, if e happened before f, we can know (l.e, c.e) < (l.f, c.f).The HLC algorithm for node j: Initialize l.j = 0 and c.j = 0 when node j starts up. Send a message to another node, or a local event happens:l’.j = l.j l.j = max(l’.j, pt.j) if (l.j = l’.j) then c.j = c.j + 1 else c.j = 0 Timestamp with l.j, c.j Receive a message from node m.l’.j = l.j l.j = max(l’.j, l.m, pt.j) if (l.j = l’.j = l.m) then c.j = max(c.j, c.m) + 1 else if (l.j = l’.j) then c.j = c.j + 1 else if (l.j = l.m) then c.j = c.m + 1 else c.j = 0 Timestamp with l.j, c.j As we can see, HLC is very easy to implement and doesn’t depend on hardware. But HLC is not the silver bullet to solve the time synchronization problem of distributed systems. HLC still needs to guarantee |l.e - pt.e| <= ε to make HLC bounded, because sometimes the user wants to use the physical timestamp to query the events directly, and if the HLC is not unbounded, we can’t know whether the event happens or not at this time.HLC still has a bound value ε, so for the transaction, we still need to handle the wait time problem which exists in Spanner with TrueTime.To tolerate the NTP synchronization error to the greatest extent, we may use a big value for ε. Some system uses 250 ms or 500 ms by default. Obviously, these default values are big and can cause a high latency for the transaction. The large ε value has little impact when supporting multiple data centers because the network latency is high as well and might be even higher than the value of the clock offset. When we send a message to the remote node, we don’t need to wait for too much time after we subtract the network transfer time.But what can we do if the NTP is not working as expected? Start panicking? Or just ignore this error?Why we choose TSO? As a distributed relational database, TiDB supports cross-instance transactions by using an optimized two-phase commit protocol (2PC) from Google Percolator. In the practical …"}, {"url": "https://pingcap.com/weekly/2017-12-18-tidb-weekly/", "title": "Weekly update (December 11 ~ December 17, 2017)", "content": " Weekly update in TiDB Last week, we landed 46 PRs in the TiDB repositories.Added Support SEPARATOR in the group_concat aggregate function. Support the BinaryJSON type. Add a config for the SQL parser to enable parsing syntax for window function. Support the http index MVCC interface. Fixed Show the index column length if necessary in show create table statement. Clear the delta info when rolling back a transaction. Only set defaultValues in aggregation push down. Fix a bug when applying meets index join. Improved Support analyzing all indices statements. Load timezone from TiKV when starting a new session. Support date_format push down. NewIndexLookUpJoin executor for Chunk. Attach the requiredProp info to physical plans. Support tls connection to pd and tikv. Support Chunk in executors: DDLExec CancelDDLJobsExec ShowDDLExec PrepareExec CheckTableExec SelectLockExec ExplainExec SetExecutor ExistsExec UpdateExec JoinResultGenerator Weekly update in TiSpark Last week, we landed 10 PRs in the TiSpark repositories.Fixed Fix the PD cache invalidation not synced for the TiSpark side. Fix the Region Request failure not synced with the TiSpark driver. Fix the inconsistent datatype mapping for Datetime type. Fix inconsistent datatype mapping for DOUBLE type. Fix not printing index name in plan. Fix the schema change that causes a SQL failure. Fix inconsistency of the timestamp unit. Weekly update in TiKV and PD Last week, we landed 14 PRs in the TiKV and PD repositories.Added Coprocessor: support date_format. Pd/Client: support get_region_info. Worker: add pending capacity. Storage: add more fail points. Fixed Tests: use the same RocksDB configuration as production. PD: fix the stale region info when overlapping. PD: fix tls for join. PD: fix the panic that the cluster status is nil. Improved Update Prometheus. Use the lower case of logrus. Correct a typo. "}, {"url": "https://pingcap.com/weekly/2017-12-11-tidb-weekly/", "title": "Weekly update (December 04 ~ December 10, 2017)", "content": " Weekly update in TiDB Last week, we landed 45 PRs in the TiDB repositories.Added Add hints to force to choose HashJoin. Provide the HTTP API of table disk usage for tidb-ctl. Fixed Fix a bug when updating the JSON field. Delete the auto ID key when renaming the table. Fix a bug in JoinResultGenerator. Fix a bug when backfilling the index with nil. The value of a session variable should not be modified when getting a global variable. Improved Move the Cancel function from session to clientConn. Reduce a comparison in the union scan. Move the binary-tree library from petar/GoLLRB to google/btree. Add the Format interface on ExprNode to convert AST back to string. Improve the performance of ShowVariables. Add Chunk/List to hold a slice of Chunk. Add the explain info for TopN. Support coprocessor streaming API for the TiKV client. Support sql_mode IGNORE SPACE. Support the builtin aggregation function bit_xor. Refactor SQL query optimizer: Replace Sort with LogicalSort and PhysicalSort. Add Physical operator for Lock, Limit and UnionAll. Make Show no longer a logical/physical plan. Add Physical plan for MaxOneRow, Dual and Exists. Add Physical plan for Projection and TopN. Extract getChildrenPossibleProp to a file. Add PhysicalStreamAgg and remove AggType. Support Chunk in executors: InsertExec MaxOneRowExec TopN UnionExec Weekly update in TiSpark Last week, we landed 12 PRs in the TiSpark repositories.Added Implement the Coprocessor DAG mode reading. Implement TopN pushdown. Add the switch for disabling a specific expression pushdown for old versions of TiKV. Add the Cache invalidation notification for the client. Fixed Fix the reading error when all values in group aggregate to null. Fix a potential error escape from Handler. Fix inconsistent PD cache eviction and add capture for leaked exception. Fix the pushdown type problem of timestamp. Weekly update in TiKV and PD Last week, we landed 21 PRs in the TiKV and PD repositories.Added Add TiltCase and Main. Support lower_bound for iterator. Add on_tick for BatchRunnable. Support getting the unique index. Add role_observer in the coprocessor. Record the wait time of APPLY_TASK. Support disabling the block cache for test. Support setting bytes_per_sync and wal_bytes_per_sync. Fixed Use the same configuration for tikv-ctl and tikv-server. Fix zero truncation in decimal decoding. Call the post_apply hook. Support the TLS connection in pd-recover. Improved Improve scheduler metrics. Avoid cloning prs in Raft. Update Limiter using all pending operators. Use a bit field to present the operator kind. Update RocksDB with optimized ingesting SST. Reduce the log in the MVCC layer. Refactor tests for the RPC client. Optimize the dev build and fix typo. New contributors (Thanks!) TiDB: Evgeniy Kulikov denofiend docs-cn: Guangkuo Bian "}, {"url": "https://pingcap.com/blog/Silicon-Valley-Office-Announcement/", "title": "PingCAP Plants its Seed in Silicon Valley", "content": " PingCAP Plants its Seed in Silicon Valley PingCAP, a cutting-edge distributed Hybrid Transactional/Analytical Processing (HTAP) database company, is excited to announce the opening of its Silicon Valley office, located at the GSV Labs in Redwood City, California. GSV (Global Silicon Valley) Labs is a global innovation platform that houses more than 170 startups, investors, and partners in its 60,000 square foot space in the heart of Silicon Valley. Its member startups work in a wide range of technologies and industries, from Big Data and healthcare, to VR and education.Image sourceFrom day one, PingCAP was conceived and built to be a global technology company with global impact. With the GA 1.0 release of its flagship product TiDB in October 2017, PingCAP has gained significant adoption in the APAC region from leading companies like Mobike and Gaea. Opening a Silicon Valley office is a natural progression of its growth trajectory.“Even before we wrote the first line of code, we wanted the impact of our vision to be global. That’s why we adopted the open source way from the beginning,” said Max Liu, co-founder and CEO. “I’m thrilled to be taking our first of many steps in pursuit of that mission.”With a physical presence in Silicon Valley, PingCAP plans to aggressively drive product adoption in the U.S., build a strong local community of developers and contributors, and recruit a team of top-notch engineers and evangelists to further develop and raise awareness of its products. To see current U.S.-based job openings, please visit: Jobs at PingCAP."}, {"url": "https://pingcap.com/weekly/2017-12-04-tidb-weekly/", "title": "Weekly update (November 27 ~ December 03, 2017)", "content": " Weekly update in TiDB Last week, we landed 43 PRs in the TiDB repositories.Added Add an option to disable Chunk. Add the schema info API of the http status server. Removed Remove the Align method of IndexRange. Fixed Set the priority for IndexLookupExecutor when reading the table. Fix the length metadata of the decimal column returned to the client. Fix the bug about auto-increment key after renaming a table from the old DB to another DB. Fix large float64 to bigint. Notify TiDB of updating privileges after Alter User and Drop user. Improved Refine codes and make backoffer the is-a go context. Refactor NewDomain. Speed up loading full stats info. Speed up loading stats info when the server is started. Remvove the hasGby field. Limit the Chunk size to MaxChunkSize. Remove the useless object clone. Split Selection to the logical plan and physical plan. Move Range to the package ranger. No longer treat DML as a logical/physical plan. Support Chunk in: LimitExec Sort SelectionExec Weekly update in TiSpark Last week, we landed 6 PRs in the TiSpark repositories.Added Support the version print for both the client and TiSpark. Fixed Fix the inconsistent timezone behavior of Datetime. Fix wrongly folded common aggregation expressions. Fix the inconsistent PD cache eviction and add capture for leaked exception. Weekly update in TiKV Last week, we landed 17 PRs in the TiKV and PD repositories.Added Implement the count-min sketch in TiKV Coprocessor. Add the fake TiKV client. Add TLS support in TiKV and PD. Fixed Fix weird leader distribution after adding a new node and restarting. Fix wrong key range generation in tests. Fix wrong default features. Improved Limit the generation IO of region snapshot. Update to protobuf 3. Reduce the slow log in endpoint and scheduler. Use readyNotify of etcd. Always link to RocksDB statically. Use the latest rust-prometheus. Update RocksDB to 5.8. New contributors (Thanks!) TiDB: Johnny Bergström Docs: Du Chuan "}, {"url": "https://pingcap.com/blog/optimizing-raft-in-tikv/", "title": "A TiKV Source Code Walkthrough – Raft Optimization", "content": " Paxos or Raft is frequently used to ensure data consistency in the distributed databases. But Paxos is known for its complexity and is rather difficult to understand while Raft is very simple. Therefore, a lot of emerging databases tend to use Raft as the consensus algorithm at its bottom layer. TiKV is no exception.Simple as Raft is, its performance is not ideal if we follow exactly the way introduced in the Paper. Therefore, optimizations are essential. This blog introduces how we optimize Raft to ensure its performance in TiKV. It presumes that the audience is very familiar with Raft algorithm and don’t need much explanation. (If not, please see Raft in TiKV).A simple Raft process Below is the simple Raft process: The leader receives the request sent by the client. The Leader appends the request to its log. The Leader sends the corresponding log entry to other followers. The Leader waits for the result of followers. If the majority of nodes have committed this log, then Leader applies. The Leader returns the result to the client. The Leader continues to handle the next request. You can see, the above flow is a typical sequential operation and if we exactly follow this workflow, the performance would be far from ideal.Batch and Pipeline The first approach that comes to our minds is to use batch to solve the performance problem. As is known to all, using batch could remarkably improve the performance in most cases. For example, as for the writes to RocksDB, we usually don’t write one value each time; instead, we use WriteBatch to cache a batch of updates and write them all. For Raft, the Leader can gather multiple requests at a time and send this batch to its Follower. Of course, we also need a maximum size to limit the amount of data sent each time.If we merely use batch, the Leader couldn’t proceed to the subsequent flow until its Follower returns the result. Thus, we use Pipeline to speed up the process. The Leader maintains a NextIndex variable to represent the next log position that will be sent to the Follower. Usually, once the Leader establishes a connection with the Follower, we will consider that the network is stable and connected. Therefore, when the Leader sends a batch of logs to the Follower, it can directly update NextIndex and immediately sends the subsequent log without waiting for the return of the Follower. If the network goes wrong or the Follower returns a few errors, the Leader needs to readjust NextIndex and resends log.Append Logs Parallelly We can execute the 2nd and 3rd steps of the above simple Raft process in parallel. In other words, the Leader can send logs to the Followers in parallel before appending logs. The reason is that in Raft if a log is appended by the majority of nodes, we consider the log committed. Thus, even if the Leader cannot append the log and goes panic after it sends a log to its Follower, the log can still be considered committed as long as N/2 + 1 followers have received and appended the log. The log will then be applied successfully.Since appending log involves disk writing and overhead, we’d better make the Follower receive log and append as quickly as possible when the Leader is writing to the disk.Note that though the Leader can send the log to the Follower before appending log, the Follower cannot tell the Leader that it has successfully appended this log in advance. If the Follower does so but fails, the Leader will still think that the log has been committed. In this case, the system might be at the risk of data loss.Asynchronous Apply As I mentioned previously, when a log is appended by the majority of the nodes, we consider it committed. When the committed log is applied has no impact on data consistency. So when a log is committed, we can use another thread to apply this log asynchronously.So the entire Raft process becomes as follows: The leader receives a request sent by a client. The Leader sends the corresponding log to other followers and appends locally. The leader continues to receive requests from other clients and executes step 2. The Leader finds that the log has been committed, and apply the log in another thread. Leader returns the result to the corresponding client after asynchronously applying the log. The benefit of using asynchronous apply is that we are now able to append and apply log in parallel. Although to a client, its single request still needs to go through the whole Raft process; to multiple clients, the overall concurrency and throughput have improved.SST Snapshot In Raft, if a Follower lags far behind the Leader, the Leader will probably send a snapshot to the Follower directly. In TiKV, Placement Driver sometimes schedules a few replicas inside a Raft Group onto other machines. All of this involves Snapshot.Below is a Snapshot process in the current implementation: The Leader scans all data of a region and creates a snapshot file. The Leader sends the snapshot file to Follower. The Follower receives the snapshot file, reads it and writes to RocksDB in batches. If there are multiple Followers of the Raft Group processing the snapshot file within one node, RocksDB’s write load will be huge, which easily leads to the condition that the whole write process slows down or stalls when RocksDB struggles to cope with so many compactions.Fortunately, RocksDB offers the SST mechanism, with which we can directly create an SST snapshot file. Then the Follower loads the SST file to RocksDB by calling DB::IngestExternalFile() and passes the file paths as a vector of std::string. For more information, see Ingesting SST files.Asynchronous Lease Read or Append Log TiKV uses ReadIndex and Lease Read to optimize the Raft Read operation, but these two operations are performed within the Raft thread, which is the same as the appended log process of Raft. However fast the appended log is written to RocksDB, this process still delays Lease Read.Thus, currently, we are trying to asynchronously implement Lease Read in another thread. We’ll move the Leader Lease judgment to another thread, and the thread in Raft will update Lease regularly through messages. In this way, we can guarantee that the write process of Raft will not influence that of read.We are also trying to append the Raft log in another thread at the same time. We will compare the performance of the two approaches and choose the better one later.Summary We will continuously optimize the Raft process in the future. And up to now, our hard work pays off as we have significant improvements in performance. But we know that there are more difficulties and challenges to resolve. We are looking forward to experienced experts who are good at performance optimization. If you have interest in our project and want to improve Raft, do not hesitate to contact us: info@pingcap.com.Fore more information Raft in TiKV The Design and Implementation of Multi-raft "}, {"url": "https://pingcap.com/weekly/2017-11-27-tidb-weekly/", "title": "Weekly update (November 20 ~ November 26, 2017)", "content": " Weekly update in TiDB Last week, we landed 60 PRs in the TiDB repositories.Added Support the Create View syntax. Support the PAD_CHAR_TO_FULL_LENGTH sql_mode. Support the PROXY protocol. Fixed Fix a bug in retry(). Fix a bug about parse duration when the fsp round overflows 60 seconds. Fix the missing index update about automatic updating for TIMESTAMP. Fix a bug when val > MaxInt32 in the from_unixtime argument. Clean up the goroutine after closing a domain. Deep clone TopN when pushing it down through Join. Add overflow Truncate when converting Str to Float. The password used to grant the privilege should be a hash string. Throw out error if the index hint not exist. Fix an invalid time cast bug. Improved Use Chunk in TableReader. Support Chunk in IndexLookupReader. Support Chunk in ProjectionExec. Make chunk.Row iterable. Load the stats table asynchronously. Support vectorized execution of expressions. Avoid updating delta when the modified count is 0. Limit the length of the index name. Support the builtin aggregation function bit_and. Weekly update in TiSpark Last week, we landed 5 PRs in the TiSpark repositories.Added Add the code format for scala. Fixed Fix a column binding error which prevents the pushdown. Fix the integration test loading. Fix the Stale Region error. Improved Upgrade to GRPC 1.7. Weekly update in TiKV Last week, we landed 10 PRs in the TiKV repositories.Added Add the fake TiKV. Support the namespace configuration. Fixed Fix potential disk full due to too many stale snapshots. Fix Chunk count detection. Fix a deadlock when trying to reconnect to PD. Improved Update to protobuf 3. Adjust the gRPC metrics. Clean up codes. New contributors (Thanks!) TiDB: ZhengQian Zheng Dayu "}, {"url": "https://pingcap.com/weekly/2017-11-20-tidb-weekly/", "title": "Weekly update (November 13 ~ November 19, 2017)", "content": " Weekly update in TiDB Last week, we landed 48 PRs in the TiDB repositories.Removed Remove redundant ResolveIndices. Remove useless error return. Fixed Fix the index recognized as prefix index when the column length is enlarged. Check the MaxInt64 and MinInt64 to avoid range error. Fix the estimation in betweenRowCount. Refine sql_mode no_backslash_escapes. Add deep copies for the update operation. Refine projection elimination when projection is the inner child of an outer join. Fix a data race in dataReaderBuilder. Support not in and correct the behavior. Improved Remove returned value isNull in Row methods. Replace *ast.Row with types.Row and prepare to use Chunk. Increase the batch size slowly for double read, which benefits small queries. Remove unionscan schema and add LogicalUnionScan. Build the logical plan to check the column name validation when doPrepare. Covert max/min to Limit + Sort operators. Support adding columns with parentheses. Prealloced space. Ignore the DDL statement for query duration metrics. Refine the use of idAllocator. Use baseExecutor for all Executors. Support decoding data to Chunk. Make tokenLimit configurable. New contributors (Thanks!) liubo ZhengQian Zhengwanbo Weekly update in TiSpark Last week, we landed 3 PRs in the TiSpark repositories.Fixed Fix the unsupported expression error of not being pushed back. Fix the thread pool error of not closing properly. Fix the Bit type being pushed down. Weekly update in TiKV Last week, we landed 23 PRs in the TiKV repositories.Added Add more observers. Support configuring namespaces. Fixed Fix a range check in debugging API. Fix CI execution. Make the progresses stored in Raft leader never false positive. Fix the Chunk size of coprocessor response. Fix a potential dead lock when resolving address. Return the correct leader when the NotLeader error occurs. Fix wrong log info. Improved As a part of introducing streaming, remove lifetime in the transaction layer. Code cleanup. Move mod debug from raftstore into server Fix typos Move opt into clusterInfo Clean up scheduelr Move server methods to server.go Use git describe to assign PDReleaseVersion. Prealloc pre-makes space. Use CGO_ENABLED instead of ENABLE_CGO. Add the log signal before exit. Limit the duration metric buckets of gRPC messages. Shorten write guard lifetime when sending the snapshot. New contributors (Thanks!) Drogon "}, {"url": "https://pingcap.com/blog-cn/rust-key-value-store/", "title": "使用 Rust 构建分布式 Key-Value Store", "content": " 引子 构建一个分布式 Key-Value Store 并不是一件容易的事情,我们需要考虑很多的问题,首先就是我们的系统到底需要提供什么样的功能,譬如: 一致性:我们是否需要保证整个系统的线性一致性,还是能容忍短时间的数据不一致,只支持最终一致性。 稳定性:我们能否保证系统 7 x 24 小时稳定运行。系统的可用性是 4 个 9,还有 5 个 9?如果出现了机器损坏等灾难情况,系统能否做的自动恢复。 扩展性:当数据持续增多,能否通过添加机器就自动做到数据再次平衡,并且不影响外部服务。 分布式事务:是否需要提供分布式事务支持,事务隔离等级需要支持到什么程度。 上面的问题在系统设计之初,就需要考虑好,作为整个系统的设计目标。为了实现这些特性,我们就需要考虑到底采用哪一种实现方案,取舍各个方面的利弊等。后面,我将以我们开发的分布式 Key-Value TiKV 作为实际例子,来说明下我们是如何取舍并实现的。TiKV TiKV 是一个分布式 Key-Value store,它使用 Rust 开发,采用 Raft 一致性协议保证数据的强一致性,以及稳定性,同时通过 Raft 的 Configuration Change 机制实现了系统的可扩展性。TiKV 提供了基本的 KV API 支持,也就是通常的 Get,Set,Delete,Scan 这样的 API。TiKV 也提供了支持 ACID 事务的 Transaction API,我们可以使用 Begin 开启一个事务,在事务里面对 Key 进行操作,最后再用 Commit 提交一个事务,TiKV 支持 SI 以及 SSI 事务隔离级别,用来满足用户的不同业务场景。Rust 在规划好 TiKV 的特性之后,我们就要开始进行 TiKV 的开发。这时候,我们面临的第一个问题就是采用什么样的语言进行开发。当时,摆在我们眼前的有几个选择: Go,Go 是我们团队最擅长的一门语言,而且 Go 提供的 goroutine,channel 这些机制,天生的适合大规模分布式系统的开发,但灵活方便的同时也有一些甜蜜的负担,首先就是 GC,虽然现在 Go 的 GC 越来越完善,但总归会有短暂的卡顿,另外 goroutine 的调度也会有切换开销,这些都可能会造成请求的延迟增高。 Java,现在世面上面有太多基于 Java 做的分布式系统了,但 Java 一样有 GC 等开销问题,同时我们团队在 Java 上面没有任何开发经验,所以没有采用。 C++,C++ 可以认为是开发高性能系统的代名词,但我们团队没有特别多的同学能熟练掌握 C++,所以开发大型 C++ 项目并不是一件非常容易的事情。虽然使用现代 C++ 的编程方式能大量减少 data race,dangling pointer 等风险,我们仍然可能犯错。 当我们排除了上面几种主流语言之后,我们发现,为了开发 TiKV,我们需要这门语言具有如下特性: 静态语言,这样才能最大限度的保证运行性能。 无 GC,完全手动控制内存。 Memory safe,尽量避免 dangling pointer,memory leak 等问题。 Thread safe,不会遇到 data race 等问题。 包管理,我们可以非常方便的使用第三方库。 高效的 C 绑定,因为我们还可能使用一些 C library,所以跟 C 交互不能有开销。 综上,我们决定使用 Rust,Rust 是一门系统编程语言,它提供了我们上面想要的语言特性,但选择 Rust 对我们来说也是很有风险的,主要有两点: 我们团队没有任何 Rust 开发经验,全部都需要花时间学习 Rust,而偏偏 Rust 有一个非常陡峭的学习曲线。 基础网络库的缺失,虽然那个时候 Rust 已经出了 1.0,但我们发现很多基础库都没有,譬如在网络库上面只有 mio,没有好用的 RPC 框架,HTTP 也不成熟。 但我们还是决定使用 Rust,对于第一点,我们团队花了将近一个月的时间来学习 Rust,跟 Rust 编译器作斗争,而对于第二点,我们就完全开始自己写。幸运的,当我们越过 Rust 那段阵痛期之后,发现用 Rust 开发 TiKV 异常的高效,这也就是为啥我们能在短时间开发出 TiKV 并在生产环境中上线的原因。一致性协议 对于分布式系统来说,CAP 是一个不得不考虑的问题,因为 P 也就是 Partition Tolerance 是一定存在的,所以我们就要考虑到底是选择 C - Consistency 还是 A - Availability。我们在设计 TiKV 的时候就决定 - 完全保证数据安全性,所以自然就会选择 C,但其实我们并没有完全放弃 A,因为多数时候,毕竟断网,机器停电不会特别频繁,我们只需要保证 HA - High Availability,也就是 4 个 9 或者 5 个 9 的可用性就可以了。既然选择了 C,我们下一个就考虑的是选用哪一种分布式一致性算法,现在流行的无非就是 Paxos 或者 Raft,而 Raft 因为简单,容易理解,以及有很多现成的开源库可以参考,自然就成了我们的首要选择。在 Raft 的实现上,我们直接参考的 etcd 的 Raft。etcd 已经被大量的公司在生产环境中使用,所以它的 Raft 库质量是很有保障的。虽然 etcd 是用 Go 实现的,但它的 Raft library 是类似 C 的实现,所以非常便于我们用 Rust 直接翻译。在翻译的过程中,我们也给 etcd 的 Raft fix 了一些 bug,添加了一些功能,让其变得更加健壮和易用。现在 Raft 的代码仍然在 TiKV 工程里面,但我们很快会将独立出去,变成独立的 library,这样大家就能在自己的 Rust 项目中使用 Raft 了。使用 Raft 不光能保证数据的一致性,也可以借助 Raft 的 Configuration Change 机制实现系统的水平扩展,这个我们会在后面的文章中详细的说明。存储引擎 选择了分布式一致性协议,下一个就要考虑数据存储的问题了。在 TiKV 里面,我们会存储 Raft log,然后也会将 Raft log 里面实际的客户请求应用到状态机里面。首先来看状态机,因为它会存放用户的实际数据,而这些数据完全可能是随机的 key - value,为了高效的处理随机的数据插入,自然我们就考虑使用现在通用的 LSM Tree 模型。而在这种模型下,RocksDB 可以认为是现阶段最优的一个选择。RocksDB 是 Facebook 团队在 LevelDB 的基础上面做的高性能 Key-Value Storage,它提供了很多配置选项,能让大家根据不同的硬件环境去调优。这里有一个梗,说的是因为 RocksDB 配置太多,以至于连 RocksDB team 的同学都不清楚所有配置的意义。关于我们在 TiKV 中如何使用,优化 RocksDB,以及给 RocksDB 添加功能,fix bug 这些,我们会在后面文章中详细说明。而对于 Raft Log,因为任意 Log 的 index 是完全单调递增的,譬如 Log 1,那么下一个 Log 一定是 Log 2,所以 Log 的插入可以认为是顺序插入。这种的,最通常的做法就是自己写一个 Segment File,但现在我们仍然使用的是 RocksDB,因为 RocksDB 对于顺序写入也有非常高的性能,也能满足我们的需求。但我们不排除后面使用自己的引擎。因为 RocksDB 提供了 C API,所以可以直接在 Rust 里面使用,大家也可以在自己的 Rust 项目里面通过 rust-rocksdb 这个库来使用 RocksDB。分布式事务 要支持分布式事务,首先要解决的就是分布式系统时间的问题,也就是我们用什么来标识不同事务的顺序。通常有几种做法: TrueTime,TrueTime 是 Google Spanner 使用的方式,不过它需要硬件 GPS + 原子钟支持,而且 Spanner 并没有在论文里面详细说明硬件环境是如何搭建的,外面要自己实现难度比较大。 HLC,HLC 是一种混合逻辑时钟,它使用 Physical Time 和 Logical Clock 来确定事件的先后顺序,HLC 已经在一些应用中使用,但 HLC 依赖 NTP,如果 NTP 精度误差比较大,很可能会影响 commit wait time。 TSO,TSO 是一个全局授时器,它直接使用一个单点服务来分配时间。TSO 的方式很简单,但会有单点故障问题,单点也可能会有性能问题。 TiKV 采用了 TSO 的方式进行全局授时,主要是为了简单。至于单点故障问题,我们通过 Raft 做到了自动 fallover 处理。而对于单点性能问题,TiKV 主要针对的是 PB 以及 PB 以下级别的中小规模集群,所以在性能上面只要能保证每秒百万级别的时间分配就可以了,而网络延迟上面,TiKV 并没有全球跨 IDC 的需求,在单 IDC 或者同城 IDC 情况下,网络速度都很快,即使是异地 IDC,也因为有专线不会有太大的延迟。解决了时间问题,下一个问题就是我们采用何种的分布式事务算法,最通常的就是使用 2 PC,但通常的 2 PC 算法在一些极端情况下面会有问题,所以业界要不通过 Paxos,要不就是使用 3 PC 等算法。在这里,TiKV 参考 Percolator,使用了另一种增强版的 2 PC 算法。这里先简单介绍下 Percolator 的分布式事务算法,Percolator 使用了乐观锁,也就是会先缓存事务要修改的数据,然后在 Commit 提交的时候,对要更改的数据进行加锁处理,然后再更新。采用乐观锁的好处在于对于很多场景能提高整个系统的并发处理能力,但在冲突严重的情况下反而没有悲观锁高效。对于要修改的一行数据,Percolator 会有三个字段与之对应,Lock,Write 和 Data: Lock,就是要修改数据的实际 lock,在一个 Percolator 事务里面,有一个 primary key,还有其它 secondary keys, 只有 primary key 先加锁成功,我们才会再去尝试加锁后续的 secondary keys。 Write,保存的是数据实际提交写入的 commit timestamp,当一个事务提交成功之后,我们就会将对应的修改行的 commit timestamp 写入到 Write 上面。 Data,保存实际行的数据。 当事务开始的时候,我们会首先得到一个 start timestamp,然后再去获取要修改行的数据,在 Get 的时候,如果这行数据上面已经有 Lock 了,那么就可能终止当前事务,或者尝试清理 Lock。当我们要提交事务的时候,先得到 commit timestamp,会有两个阶段: Prewrite:先尝试给 primary key 加锁,然后尝试给 second keys 加锁。如果对应 key 上面已经有 Lock,或者在 start timestamp 之后,Write 上面已经有新的写入,Prewrite 就会失败,我们就会终止这次事务。在加锁的时候,我们也会顺带将数据写入到 Data 上面。 Commit:当所有涉及的数据都加锁成功之后,我们就可以提交 primay key,这时候会先判断之前加的 Lock 是否还在,如果还在,则删掉 Lock,将 commit timestamp 写入到 Write。当 primary key 提交成功之后,我们就可以异步提交 second keys,我们不用在乎 primary keys 是否能提交成功,即使失败了,也有机制能保证数据被正常提交。 在 TiKV 里面,事务的实现主要包括两块,一个是集成在 TiDB 中的 tikv client,而另一个则是在 TiKV 中的 storage mod 里面,后面我们会详细的介绍。RPC 框架 RPC 应该是分布式系统里面常用的一种网络交互方式,但实现一个简单易用并且高效的 RPC 框架并不是一件容易的事情,幸运的是,现在有很多可以供我们进行选择。TiKV 从最开始设计的时候,就希望使用 gRPC,但 Rust 当时并没有能在生产环境中可用的 gRPC 实现,我们只能先基于 mio 自己做了一个 RPC 框架,但随着业务的复杂,这套 RPC 框架开始不能满足需求,于是我们决定,直接使用 Rust 封装 Google 官方的 C gRPC,这样就有了 grpc-rs。这里先说一下为什么我们决定使用 gRPC,主要有如下原因: gRPC 应用广泛,很多知名的开源项目都使用了,譬如 Kubernetes,etcd 等。 gRPC 有多种语言支持,我们只要定义好协议,其他语言都能直接对接。 gRPC 有丰富的接口,譬如支持 unary,client streaming,server streaming 以及 duplex streaming。 gRPC 使用 protocol buffer,能高效的处理消息的编解码操作。 gRPC 基于 HTTP/2,一些 HTTP/2 的特性,譬如 duplexing,flow control 等。 最开始开发 rust gRPC 的时候,我们先准备尝试基于一个 rust 的版本来开发,但无奈遇到了太多的 panic,果断放弃,于是就将目光放到了 Google gRPC 官方的库上面。Google gRPC 库提供了多种语言支持,譬如 C++,C#,Python,这些语言都是基于一个核心的 C gRPC 来做的,所以我们自然选择在 Rust 里面直接使用 C gRPC。因为 Google 的 C gRPC 是一个异步模型,为了简化在 rust 里面异步代码编写的难度,我们使用 rust Future 库将其重新包装,提供了 Future API,这样就能按照 Future 的方式简单使用了。关于 gRPC 的详细介绍以及 rust gRPC 的设计还有使用,我们会在后面的文章中详细介绍。监控 很难想象一个没有监控的分布式系统是如何能稳定运行的。如果我们只有一台机器,可能时不时看下这台机器上面的服务还在不在,CPU 有没有问题这些可能就够了,但如果我们有成百上千台机器,那么势必要依赖监控了。TiKV 使用的是 Prometheus,一个非常强大的监控系统。Prometheus 主要有如下特性: 基于时序的多维数据模型,对于一个 metric,我们可以用多种 tag 进行多维区分。 自定义的报警机制。 丰富的数据类型,提供了 Counter,Guage,Histogram 还有 Summary 支持。 强大的查询语言支持。 提供 pull 和 push 两种模式支持。 支持服务的动态发现和静态配置。 能跟 Grafana 深度整合。 因为 Prometheus 并没有 Rust 的客户端,于是我们开发了 rust-prometheus。Rust Prometheus 在设计上面参考了 Go Prometehus 的 API,但我们只支持了 最常用的 Counter,Guage 和 Histogram,并没有实现 Summary。后面,我们会详细介绍 Prometheus 的使用,以及不同的数据类型的使用场景等。测试 要做好一个分布式的 Key-Value Store,测试是非常重要的一环。 只有经过了最严格的测试,我们才能有信心去保证整个系统是可以稳定运行的。从最开始开发 TiKV 的时候,我们就将测试摆在了最重要的位置,除了常规的 unit test,我们还做了更多,譬如: Stability test,我们专门写了一个 stability test,随机的干扰整个系统,同时运行我们的测试程序,看结果的正确性。 Jepsen,我们使用 Jepsen 来验证 TiKV 的线性一致性。 Namazu,我们使用 Namazu 来干扰文件系统以及 TiKV 线程调度。 Failpoint,我们在 TiKV 很多关键逻辑上面注入了 fail point,然后在外面去触发这些 fail,在验证即使出现了这些异常情况,数据仍然是正确的。 上面仅仅是我们的一些测试案例,当代码 merge 到 master 之后,我们的 CI 系统在构建好版本之后,就会触发所有的 test 执行,只有当所有的 test 都完全跑过,我们才会放出最新的版本。在 Rust 这边,我们根据 FreeBSD 的 Failpoint 开发了 fail-rs,并已经在 TiKV 的 Raft 中注入了很多 fail,后面还会在更多地方注入。我们也会基于 Rust 开发更多的 test 工具,用来测试整个系统。小结 上面仅仅列出了我们用 Rust 开发 TiKV 的过程中,一些核心模块的设计思路。这篇文章只是一个简单的介绍,后面我们会针对每一个模块详细的进行说明。还有一些功能我们现在是没有做的,譬如 open tracing,这些后面都会慢慢开始完善。我们的目标是通过 TiKV,在分布式系统领域,提供一套 Rust 解决方案,形成一个 Rust ecosystem。这个目标很远大,欢迎任何感兴趣的同学加入。"}, {"url": "https://pingcap.com/weekly/2017-11-13-tidb-weekly/", "title": "Weekly update (November 06 ~ November 12, 2017)", "content": " Weekly update in TiDB 2017-11-13Last week, we landed 45 PRs in the TiDB repositories.Added Support more SQL modes in TiDB: the NO_UNSIGNED_SUB sql_mode the REAL_AS_FLOAT sql_mode the PIPES_AS_CONCAT sql_mode the high_not_precedence sql_mode the ONLY_FULL_GROUP_BY sql_mode Parse more privilege types like RELOAD, EVENT and so on. Support part of window function AST. Removed Remove joinBuilder. Remove resolver.go. Fixed Return error instead of panic if a subquery in JOIN ON condition. Set the error to be undetermined error if not recovered from an RPC error. Fix the issue that DDL is always running and saves the reorg doneHandle regularly. Let the in clause handle more cases. Improved Use types.Row to write the result set and prepare to use Chunk. Support the alter table add column(col_name column_definition) syntax. Build and use the Count-Min sketch. Stop reusing the Executor in IndexLookUpJoin and remove doRequestForDatums(). Begin OpenTracing from dispatch() and change the interface to Execute(ctx, sql) to avoid too many noises. Remove the read-only statement from transaction auto retry. Make the batch size of index join increase slowly. Let select push across projects to support generated column index. Support insert into from selectStmt that has brackets. Remove the type assertion on types.DatumRow. Improve hash join to support all the join types. Implement the Count-Min Sketch. Enable OpenTracing for the TableReader, IndexReader, IndexLookup executor. Weekly update in TiSpark Added Add R language support. Add Python language support. Add Index Read Support and related task concurrent read. Improved Improve integration tests and frameworks. Fixed Fix racing condition in thread pool allocation. Weekly update in TiKV Last week, We landed 18 PRs in the TiKV repositories.Added Support splitting table Support resolving multiple locks in a batch. Use size as a factor of score when scheduling. Support OpenTracing for pd-client. Support set namespace for meta. Support checking the region stats using API. Fixed Verify before destroying a peer. Fix the LIKE behavior for coprocessor. Fix the do_div_mod bug. Fix a nil pointer dereference bug in pd-client. Clear hot region related gauges if a region is not hot any more. Improved Add meta decoding for tables. Better region key output API. Unify ApplyContext and ExecContext. Use recover_safe! to hide the panic stack trace. Remove the pending peers before adding a new peer. New contributers (Thanks!) wudi xiaojian cai "}, {"url": "https://pingcap.com/weekly/2017-11-06-tidb-weekly/", "title": "Weekly update (October 30 ~ November 05, 2017)", "content": " Weekly update in TiDB Last week, we landed 51 PRs in the TiDB repositories.Added Provide the command option and log the success/fail information for slow-query. Removed Remove the old planner. Remove xeval. Remove the localstore storage engine. Fixed Change the selection plan to dual plan directly if the condition is always false. Insert column char(4) with latin1 charset by incorrect padding. Remove the check of initialized auto ID. Support alter table add column(...). Fix a bug in JSON decoding. Use utf8_bin for unsupported column collation. Fix the bug of alter table table_options, other_alter_specification. Improved Move the safepoint checker to tikvStore. Enable pushing float down to TiKV. Fix estimation in index point query. No longer add enforcer. Improve index join to support all join types. Extract the process of getting full CMP type to method. Opentracing for Execute, ParseSQL, Compile, and runStmt. Reduce growslice in dumpRowValuesBinary. New Contributor (Thanks!) wudi Weekly update in TiKV Last week, We landed 16 PRs in the TiKV repositories.Added Add recursion limit check for coprocessor. Reset the RocksDB statistics periodically. Fixed Save the region meta information to cache even if it is failed to be written to the disk. Fix the read statistics. Clear the hot store related gauges when store is not hot any more. Fix the LIKE behavior. Improved Move operator influence into ShouldBalance. Reduce allocation. Remove the pending peer before adding a new peer. Refactor the split check. Add limitation for key size. New Contributor (Thanks!) wudi "}, {"url": "https://pingcap.com/weekly/2017-10-30-tidb-weekly/", "title": "Weekly update (October 23 ~ October 29, 2017)", "content": " Weekly update in TiDB Last week, we landed 52 PRs in the TiDB repositories.Added Support the window function syntax. Fixed Fix an issue when the values builtin function meets the null value. Support the signed field option for the numeric type. Fix an issue of index reader. Fix an issue that the binlog client is not initialized correctly. Correct the schema type of ShowStmt. The default value length for Join should be changed for column pruning. Add retry for dialPumpClient. Parse but ignore the REPLICATION CLIENT/SLAVE, USAGE privileges in the GRANT statement. Fix an issue with visibility check. Fix an issue with renaming tables. Parse PARTITION BY RANGE COLUMNS. Support the straight_join syntax. Support the row_count built-in function. Load the column histograms as needed. Start safePointChecker before running a worker. Truncate the information field for show processlist and support show full processlist. Improved Build the prepared statement plan in the Optimization phase. Support the ALTER TABLE t ENGINE = 'string' syntax. Remove reorgTableDeleteLimit. Fold the true item in the CNF predicator. Use max uint64 as the start timestamp for the ANALYZE statement . Improve merge join to support all join types. Add highlight to log. Add the Row interface. Simple improvement for range calculation for Primary Key. Change the behavior of the the in function. Support a plan cache for prepared statements. Introduce Chunk to replace the current datum slice Row. Introducing OpenTracing into TiDB: For two phase commit. Tracing config and gRPC interceptor middleware. Weekly update in TiSpark Added Add redundant aggregation elimination. Fixed Fix meta deserialize overflow. Fix broken integration test. Fix potential time type NPE. Fix and upgrade Bazel for CI. Fix test dependency in CI. New Contributor Ry Weekly update in TiKV Last week, We landed 21 PRs in the TiKV repositories.Added Add adjacent region balancing scheduler. Add WAL bytes per the sync configuration. Flow control based on total writing bytes. Implement the in function for coprocessor. Filter the stores with lots of pending peers when balancing. Add region and hot region scheduling API. Record the approximate size of a store in PD. Fixed raftstore: fix an issue with stale peer check. Record snapshot metrics in SCHED_STAGE_COUNTER_VEC. Fix the illegal JSON format in the hotspot/stores API. Improved Inline get_limit_at_size. Group the metrics by namespaces. Document defer macro LIFO behavior. Remove redundant verbose KV for coordinator. Adjust table ID calculation. Set stack size to 10 MB for the coprocessor threads. New contributor odeits "}, {"url": "https://pingcap.com/meetup/meetup-2017-10-25/", "title": "【Infra Meetup No.55 Rust 专场】《Rocket Web 框架解析》", "content": " Rust 专场 2.0 Rust 作为系统级编程语言,同样可以非常方便的开发上层 Web 应用。借助目前 Rust 社区最火的 web 框架 Rocket,可以像动态语言一样方便地创建高性能的 Web 应用,同时可以拥有 Rust 强大的类型安全保障。在上周六,我们邀请了 Rocket 的作者 Sergio Benitez,与大家面对面分享了《Rocket Web 框架解析》。据 Sergio 现场表示,这是他首次来中国,以往虽然也有在公开场合解读过 Rocket Web 框架,但本次,有些新鲜内容可是第一时间共享给 Rust 中国社区的小伙伴哦~这一次,让我们跳过现场内容解读环节,直接为大家奉上新鲜出炉的干货视频,enjoy~~视频 | Infra Meetup No.55:Rocket Web 框架解析讲师介绍: Sergio Benitez,斯坦福大学博士四年级的学生,主要研究如何将编程语言理论与操作系统和安全性融合在一起。目前在做项目包括对 Rust 的类型系统 “Rusty Types” 的规范化,以及 Rust 的 Rocket Web Framework。在斯坦福大学之前,Sergio 曾在 Google、Apple 和 SpaceX 实习,参与的项目包括设计异常检测算法,火箭及其它航天器的操作系统的性能调优。 PingCAP Infra Meetup作为一个基础架构领域的前沿技术公司,PingCAP 希望能为国内真正关注技术本身的 Hackers 打造一个自由分享的平台。自 2016 年 3 月 5 日开始,我们定期在周六的上午举办 Infra Meetup,邀请业内大牛与大家深度探讨基础架构领域的前瞻性技术思考与经验。在这里,我们希望提供一个高水准的前沿技术讨论空间,让大家真正感受到自由的开源精神魅力。 "}, {"url": "https://pingcap.com/weekly/2017-10-23-tidb-weekly/", "title": "Weekly update (October 9 ~ October 22, 2017)", "content": " Weekly update in TiDB Last two weeks, we landed 83 PRs in the TiDB repositories.Added Support writing slow query log into separate files. Dummy implementation for the SHOW PROFILES statement. Add metrics for automatic analyzing. Support the operation of cancel DDL jobs. Add a new http status API to get meta regions. Removed Remove the self field in baseBuiltinFunc completely. Remove foldable from baseBuiltinFunc. Fixed Fix a bug occurred in select sum(float col)*0.1 Cast types for the expression of assignments of updateList. Fix a PhysicalReader range bug when data is MaxInt64. Add unsigned and zerofill flags to field type year. Fix a select distinct bug. Fix a bug when auto_increment meets unsigned. Change the DNV of default null column to 0. Correct the signature building of Values. Add schema state check when executing the show create table or analyze statistic statement. Set missing result field Org_table and Database to Navicat for MySQL compatibility. Fix a bug in the copy function. Fix a bug when converting time to scalar. Fix a bug when building histograms for columns. Fix a bug when merging sample collectors. Fix ineffectual assignments. Fix the issue that the show grants statement displays empty entries. Set proper parent for newly projection-eliminated child. Put RPC handler in response instead of returning it. Quit the builtin function SLEEP when it is killed. Fix the issue that the unsigned integer column length is not consistent with MySQL. Add the ParseErrorWith function to make the parse error compatible with MySQL. Improved Rename the DDL job state variable. Rename the package inspectkv to admin. Change reorg wait time from 1ms to 50ms. Support int1, int2, int3, int4, int8 type syntax. Estimate NDV more precisely. Return MySQL error code for Unsafe SafePoint. Estimate NDV as pseudo when its value is zero. Make some builtin functions foldable. Return NULL when error is not nil. Improvement for multi-delete. Split the detach process from BuildRange. Use single method to set parent and children. Use pattern match to check dbRecord in mysql.db. Check sc.IgnoreZeroInDate when parsing the string or number type to date/datetime/timestamp. Enforce errcheck in Makefile. Open auto analyze by default. Improve the fold constant. Avoid type assertion for ast.ExprNode. Avoid come assertion for StmtNode. Use ParseTimeFormNum instead of ParseTime. Support plan cache for the SELECT statement. Weekly update in TiSpark Added Add support for explain Fixed Fix tispark-sql table alias problem Weekly update in TiKV In the last two weeks, We landed 46 PRs in the TiKV repositories.Added Register classifiers by name when using namespace. Add the operator priority mechanism. Support setting a region to tombstone status. Add MVCC scan support to debug API. Support fail point. Support removing table_id/store_id from namespace. Persist scheduler list to etcd. Support namespace(experimental). Support health check in pd-ctl. Store case-insensitive labels. Support adding/removing region peer in pd-ctl. Fixed Fixes typos in raft. Fix table namespace classifier. Fix split check tests. Improved Refactor clusterInfo. Refactor the debug API for tikv-ctl. Adjust scheduler interface. Reduce allocation in Raft. Report read statistics to pd-worker directly. Move out the PD work from raftstore. Use try shorthand. Move significant send to Raft router. Adjust label checks. Optimize approximate region size for region heartbeat. Flow control based on current writing KV count. "}, {"url": "https://pingcap.com/blog/2017-10-17-announcement/", "title": "PingCAP Launches TiDB 1.0", "content": " PingCAP Launches TiDB 1.0, A Scalable Hybrid Database Solution October 16, 2017 - PingCAP Inc., a cutting-edge distributed database technology company, officially announces the release of TiDB 1.0. TiDB is an open source distributed Hybrid Transactional/Analytical Processing (HTAP) database that empowers businesses to meet both workloads with a single database.In the current database landscape, infrastructure engineers often have to use one database for online transactional processing (OLTP) and another for online analytical processing (OLAP). TiDB aims to break down this separation by building a HTAP database that enables real-time business analysis based on live transactional data. With TiDB, engineers can now spend less time managing multiple database solutions, and more time delivering business value for their companies. One of TiDB’s many users, a financial securities firm, is leveraging this technology to power its application for wealth management and user personas. With TiDB, this firm can easily process web-scale volumes of billing records and conduct mission-critical time sensitive data analysis like never before.“Two and a half years ago, Edward, Dylan and I started this journey to build a new database for an old problem that has long plagued the infrastructure software industry. Today, we are proud to announce that this database, TiDB, is production ready,” said Max Liu, co-founder and CEO of PingCAP. “Abraham Lincoln once said, ‘the best way to predict the future is to create it.’ The future we predicted 771 days ago we now have created, because of the hard work and dedication of not just every member of our team, but also every contributor, user, and partner in our open source community. Today, we celebrate and pay gratitude to the power of the open source spirit. Tomorrow, we will continue to create the future we believe in.”TiDB has already been deployed in production in more than 30 companies in the APAC region, including fast-growing Internet companies like Mobike, Gaea, and YOUZU. The use cases span multiple industries from online marketplace and gaming, to fintech, media, and travel.TiDB features Horizontal ScalabilityTiDB grows as your business grows. You can increase the capacity for storage and computation simply by adding more machines.Compatible with MySQL ProtocolUse TiDB as MySQL. You can replace MySQL with TiDB to power your application without changing a single line of code in most cases and with nearly no migration cost.Automatic Failover and High AvailabilityYour data and applications are always-on. TiDB automatically handles malfunctions and protects your applications from machine failures or even downtime of an entire data-center.Consistent Distributed TransactionsTiDB is analogous to a single-machine RDBMS. You can start a transaction that crosses multiple machines without worrying about consistency. TiDB makes your application code simple and robust.Online DDLEvolve TiDB schemas as your requirement changes. You can add new columns and indexes without stopping or affecting your ongoing operations.Try TiDB Now!Use cases How TiDB tackles fast data growth and complex queries for yuanfudao.comMigration from MySQL to TiDB to handle tens of millions of rows of data per dayFor more information: TiDB internal: Data Storage Computing Scheduling Release NotesBest PracticeDocumentsWeekly Update"}, {"url": "https://pingcap.com/blog-cn/ga-1.0/", "title": "写在 TiDB 1.0 发布之际 | 预测未来最好的方式就是创造未来", "content": "如果只能用一个词来描述此刻的心情,我想说恍如隔世,这样说多少显得有几分矫情,或许内心还是想在能矫情的时候再矫情一次,毕竟当初做这一切的起因是为了梦想。还记得有人说预测未来最好的方式就是创造未来,以前看到这句话总觉得是废话,如今看到这一切在自己身上变成现实的一刻,感受是如此的真切,敲击键盘的手居然有点颤抖,是的,预测未来最好的方式就是创造未来。还记得刚开始做的时候,只有很少的几个人相信这个事情可以做,毕竟难度比较高,就像有些户外旅行,只有方向,没有路。从零开始到发布 1.0 版本,历时 2 年 6 个月,终于还是做出来了。这是开源精神的胜利,是真正属于工程师们的荣耀。这个过程我们一直和用户保持沟通和密切协作,从最早纯粹的为 OLTP 场景的设计,到后来迭代为 HTAP 的设计,一共经历了 7 次重构,许多看得见的汗水,看不见的心跳,也许这就是相信相信的力量,总有那么一群人顶着世俗的压力,用自己的信念和力量在改变世界。在这个过程中,质疑的声音变少了,越来越多的人从观望,到为我们鼓舞助威,帮助我们快速成长。特别感谢那些从 beta 版本开始一路相随的用户,没有你们的信任,耐心和参与,就没有今天的 PingCAP。开心的时刻总是特别想对很多帮助和支持我们的童鞋们说声谢谢,没有你们就没有 PingCAP,特别感谢每一位项目的贡献者。也许你已经知道了,我们专门为你们定制了一面荣誉墙,那里的色彩记录了你们的每一次贡献,如果你仍在埋头工作,来不及知道,我想请你过去逛逛,不负好时光。这个世界还是有人相信未来是可以被创造的。感谢开源精神,让我们这样一个信仰创造未来的团队,可以站在未来的入口,因为相信和努力,获得源源不绝的正向的力量。面对未来,让我们可以摒弃对未知的恐惧和对不完美的妥协。也感谢那些曾经的诋毁和吐槽,让我们不敢懈怠,砥砺前行。然而 1.0 版本只是个开始,是新的起点,愿我们一路相扶,不负远途。"}, {"url": "https://pingcap.com/blog/2017-10-10-nextcon/", "title": "Scale the Relational Database with NewSQL", "content": " This is the speech Li SHEN gave at the 3rd NEXTCON: Cloud+Data NEXT Conference Seattle on September 16th, 2017. Speaker introduction Why we build a new relational database TiDB Project - Goal Architecture The core components of TiDB The Storage stack Dynamic Multi-Raft Safe Split ACID Transaction Something we haven’t mentioned Placement Driver The SQL Layer What Happens behind a query SQL Layer Overview Cost-Based Optimizer Tools matter Spark on TiKV Future plans Speaker introduction Hello everyone, I am glad to be here in this beautiful city and share this talk with you. The talk‘s name is “Scale the Relational Database with NewSQL”. It is about a new distributed relational database named TiDB. In this talk I’ll draw a detailed picture of TiDB to help you understand why and how we build it.First of all, I’d like to introduce myself and our company PingCAP. My name is Shen Li, an infrastructure software engineer and the VP of Engineering at PingCAP. Our company is a startup based in Beijing, China. We focus on building database solutions. We are building a distributed transactional database TiDB and have more than thirty adoptions for production use in China.So today we will cover the following topics: Motivations The goals of TiDB The core components of TiDB The tools around TiDB Spark on TiKV Future plans Back to the topWhy we build a new relational database Ok. Let’s begin. I want to ask a question: what would you do when your RDBMS is becoming the bottleneck of your application? Maybe most of you guys have experienced the following situations: RDBMS is becoming the performance bottleneck of your backend service The amount of data stored in the database is overwhelming You want to do some complex queries on a sharding cluster e.g., simple JOIN or GROUP BY Your application needs ACID transaction on a sharding cluster In the old days, all you can do is to either refactor your application or use database middleware, something like MySQL proxy. But once you decide to use the sharding solution, it’s one-way path, and you will never get rid of the sharding keys and have to say goodbye to complex queries… So how to scale your relational database is a pain point for the entire industry.Back to the topTiDB Project - Goal And there comes TiDB, when we were designing TiDB, we want to achieve the following goals: - Make sharding and data movement transparent to users so that the developers can be freed to focus on application development. - 100% OLTP and 80% OLAP support. TiDB aims to be a Hybrid database that supports both OLTP and OLAP workload. This is feasible because TiDB supports transactions and has our own full-featured distributed SQL engine (including the parser , optimizer and query executor). We build it from the ground up. - Twenty-four/Seven availability, even in case of datacenter outages. Thanks to the Raft consensus algorithm, TiDB can ensure the data strong consistency and availability all the time. - TiDB has to be compatible with the MySQL protocol, by implementing the MySQL syntax and protocol. In this way, our users can easily migrate their existing application to TiDB with nearly zero costs. And also use their familiar MySQL tools to manage the database. - Open source, of course. You can find all our projects on GitHub.Back to the topArchitecture Let’s see the TiDB architecture. In this diagram, there are three components: - The SQL layer, which is TiDB servers. TiDB servers are stateless. They don’t store data, just do the computing. - The distributed storage layer, which is TiKV. TiKV is a distributed key-value database, acting as the underlying storage layer of TiDB and it’s the place where data is actually stored. This layer uses Raft consensus algorithm to replicate data and guarantee data safety. - And Placement Driver, aka PD. The brain of the entire cluster and provides a God’s view.These three components communicate with each other through gRPC.Back to the topThe core components of TiDB The Storage stack One thing I need to point out here is that TiDB doesn’t depend on any distributed file system.TiKV is the underlying storage layer where data is actually stored. More specifically, data is stored in RocksDB locally which is the bottom layer of the TiKV architecture as you can see from this diagram. On top of RocksDB, we build a Raft layer. So what is Raft? Raft is a consensus algorithm that equals to Paxos in fault-tolerance and performance. It has several key features such as leader election, auto failover, and membership changes. And Raft ensures that data is safely replicated with strong consistency.We have exposed the Raw Key-Value API at this layer, if you want a scalable, high-performance, highly available Key-Value database, and don’t care about a cross-row ACID transaction; you can use raw KV API for higher performance.The middle layer is MVCC, Multi-version concurrency control. The top two layers are transaction and gRPC API. The API here is the transactional KV API.TiKV is written in Rust and the reason is that the storage layer is performance critical and stability is the first-class citizen of course. We only got c/c++ in the past, and now we have Rust is great for infrastructure system software like database, operation system… No extra cost for GC and runtime, high performance, and another great thing is that Rust does a lot of innovation works in preventing memory leaks and data race, that matters a lot for us.Back to the topTiKV is a key-value storage engine. Keys and values are both byte arrays. Logically, we could regard TiKV as a giant sorted key-value map. In order to achieve data distribution, we split the key space into multiple ranges. Each range has a metadata which contains start_key and end_key.Back to the topNow we know that the actual data is stored in RocksDB. And we also know that the key space is split into ranges. Region is a set of continuous key-value pairs in byte-order. Let’s take a look at the diagram here: The data is split into a set of continuous key-value pairs which we name them from a to z. Region 1 stores “a” to “e”, Region 2 “f” to “j”, Region 3 “k” to “o”, etc. notice that region is a logical concept, all the regions in a physical node share the same RocksDB instance.In each RocksDB instance, there are several regions and each region is replicated to other instances by Raft. The replicas of the same Region, Region 4 for example, make a Raft group.The metadata of the Raft groups is stored in PD. And of course, PD is a cluster, replicating the metadata by Raft, too. I will introduce it later.Back to the topDynamic Multi-Raft In TiKV, we adopt a multi-raft model. What’s multi-raft? It’s a way to split and merge regions dynamically, and of course, safely. We name this approach “safe split/merge”.For example, Region 1 from “a” to “e” is safely split into Region 1.1 “a” to “c” and Region 1.2 “d” to “e”, we need to guarantee no data is lost during the split.This explains how one Region is split, but how about its replicas on other nodes? Let’s go to next few slides.Back to the topSafe Split This is the initial state for Region 1. You can see there is a Raft group with three TiKV nodes.Region 1 on TiKV1 is the Leader and the other two replicas are the followers. However, there comes a situation that there are too much data in Region 1 and it needs to be split.It’s easy if there is only one Region 1. But in this case, we have three replicas. How can all the replicas be split safely? The answer is also Raft. Let’s see how it works.Back to the topThe split is initiated by the Leader, which means Region 1 is split to Region 1.1 and Region 1.2 firstly in the Leader as you can see from the diagram.Back to the topWhen the split-log is written to WAL in the Leader, the split log is replicated by Raft and sent to the followers. Then, the followers apply the split log, just like any other normal Raft log.Back to the topAnd finally, once the …"}, {"url": "https://pingcap.com/weekly/2017-10-09-tidb-weekly/", "title": "Weekly update (September 25 ~ October 08, 2017)", "content": " Weekly update in TiDB Last two weeks, we landed 62 PRs in the TiDB repositories.Added Support the SyncLog Key-Value request option. Support the NotFillCache Key-Value request option. Support the combination SQL modes. Removed Close the aggregation pushdown by default and remove the CBO switch. Remove some useless code. Remove the usage of TypeClass completely. Fixed Change the like function to be case sensitive. Prepare to enforce errcheck, step 1. Make the prepare statement retry when the schema is out-dated. Revoke etcd on ctx.Done to prevent the situation that no owner entry left. Pre-calculate the lower and upper scalar. Add length limitation for index comment. Make insert with calculated value behave the same as MySQL. Drop invalid cached region. Improved Turn on the analyze statement pushdown switch. Upgrade pd-client to fix a bug. Rewrite the unit test for Minus and Plus functions. The analyze statement uses NewSelectResult. Remove the usage of evalExprToXXX functions to improve performance. Change structured slow log to friendly JSON output. Refactor parser step 2: to be compatible with MySQL syntax. Refactor the SelectDAG function parameter. Speed up the add index operation. Optimize the SortExec executor. Split separated region for newly created table. Change the schema validator data structure to queue. Change the way of transferring the handle. Support more signatures pushdown. Weekly update in TiSpark Added Add the Configuration Framework Fixed Fix invalid leader store ID cases Remove unused parameter for TiSpark context during the startup Weekly update in TiKV Last two weeks, We landed 39 PRs in the TiKV repositories.Added Use expression in DAG. Namespace isolation: http interface and classifier. Report read statistics to PD. Pushdown sampling: implement histogram. Support ppc64le. Pushdown the analyze request. Support the must_sync flag for raft ready. Introduce Disconnected and LowSpace states for store. Add an API to compact a range for the specified column family. Fixed Stop the thread pool on shutdown. Fix block send problem in grpc. Fix potential unreachable drop. Fix tablecodec. Improved Select response of DAG don’t need row meta. Add drop message metrics. Debug: implement size. Debug: implement region information. Add slow log for applying. Update gRPC to 1.6.1. Check whether peers need to split after initialization. Refactor Key-Value for PD. Config: change all the names to kebab-case](https://github.com/pingcap/pd/pull/772). Flush the leader message as soon as possible. Return error instead of panic if an expression is illegal. Update etcd to v3.2.6 for PD. Synchronize data before applying snapshots. Update the client URLs continuously. Adjust the region heartbeat metrics. New contributors Priya Seth "}, {"url": "https://pingcap.com/blog/2017-09-26-whyrust/", "title": "Why did we choose Rust over Golang or C/C++ to develop TiKV?", "content": " What is Rust Rust is a systems programming language sponsored by Mozilla Research. It moves fast and steady with a 6-week release cycle ever since its 1.0 version in May 2015.See the following list for some of the features that most attract us: The design principles of Rust resemble with C++ in Abstraction without overhead and RAII (Resource acquisition is initialization). The minimum runtime and efficient C bindings empower Rust to be as efficient as C and C++, thus making it very suitable for the systems programming field where high performance matters the most. The powerful type system and unique life cycle management facilitate the memory management during the compiling, which ensures the memory and thread safety and makes the program run very fast after the compiling. Rust provides pattern matching and type inference like a functional programming language and makes the code simple and elegant. The macros and traits allow Rust to be highly abstract and save quite a few boilerplates during the engineering especially when it comes to the libraries. The Rust Ecosystem Because of the excellent package management tool, Cargo, Rust has many types of libraries, such as Hyper for HTTP, Tokio and mio for asynchronous I/O, basically all the libraries that are required to construct a backend application.Generally speaking, Rust is mainly used to develop server-side applications with high performance at this stage. In addition, its innovation in the type system and syntax gives it a unique edge in developing Domain-Specific Libraries (DSL).The Rust adoption As a new programming language, Rust is unique. To name just a few projects that are using Rust, The backend distributed storage system of Dropbox Servo, the new kernel of Firefox Redox, the new operating system TiKV, the storage layer of TiDB, a distributed database developed by PingCAP. As one of the listed Friends of Rust, TiKV has been one of the top projects in Rust according to the Github trending.TiKV is a distributed key-value database. It is the core component of the TiDB project and is the open source implementation of Google Spanner. We chose Rust to build such a large distributed storage project from scratch. In this blog, I will uncover the rationale.In the past long period of time, C or C++ has dominated the development of infrastructure software such as databases. Java or Golang has problems such as GC jitter especially in case of high read/write pressure. On the one hand, Goroutine, the light-weight thread and the fascinating feature of Golang, has significantly reduced the complexity of developing concurrent applications at the cost of the extra overhead in context switching in the Goroutine runtime. For an infrastructure software like a database, the importance of performance goes without saying. On the other hand, the system needs to remain its “Certainty” which makes it convenient for performance tuning. But introducing GC and another runtime contributes to the opposite. So for quite a long time, C/C++ seems to be the only choice.TiKV originates from the end of 2015. Our team was struggling among different language choices such as Pure Go, Go + Cgo, C++11, or Rust. Pure Go: Our core team has rich experience in Go. The SQL layer of TiDB is developed in Go and we have benefited quite a lot from the high efficiency brought by Go. However, when it comes to the development of the storage layer, Pure Go is the first option to rule out for one simple reason: we have decided to use RocksDB as the bottom layer which is written in C++. The existing LSM-Tree implementations (like goleveldb) in Go were hardly as mature as RocksDB. Cgo: If we had to use Go, we had to use Cgo to bridge but Cgo had its own problems. At the end of 2015, the performance might be greatly impacted if calling Cgo in Go code rather than calling Cgo in the same thread with Goroutine. Besides, databases require frequent calls to the underneath storage libraries, aka RocksDB. It was highly inefficient if the extra overhead was needed every time the RocksDB functions were called. Of course, some workarounds could be introduced to enlarge the throughput of calling Cgo, such as packaging the calls within a certain period to be a Cgo batch call that will increase the latency of a single request and erase the Cgo overhead. But, the implementation might be very complex while the GC problem was not entirely solved. At the storage layer, we want to use the memory as efficiently as possible. Hacky workarounds such as extensive use of syscall.Mmap or object reuse might damage the readability of the code. C++11: There ought to be absolutely no issue with C++11. RocksDB is developed using C++11. But given the team background and what we want to do, we didn’t choose C++11. The reasons are as follows: The core team members are experienced C++ developer with rich experience in large C++ projects. But the seemingly inevitable problems in large projects like Dangling pointers, memory leak, or data race make them shudder at the thought. Of course, the probability of these problems could be lowered if well guided, or having a stringent code review and coding rules in place. But if a problem occurred, it might be costly and burdened to debug. Not to mention that we have no controls if the third-party libraries could not meet our coding rules. There are too many and too different programming paradigms in C++ as well as too many tricks. It demands extra costs to unify the coding style especially when there are more and more new members who might not be familiar with C++. After years of using languages with GC, it is very hard to go back time for manually managing the memory. The lack of package management and CI tools. It appears not to be trivial, but the automated tools are very important for a large project because it is directly related to the development efficiency and the speed of iterating. What’s more, the C++ libraries are far from enough and some of them need to be created by ourselves. Rust: The 1.0 version of Rust is released in May 2015 with some charming features: Memory safety High performance which is empowered by LLVM. The runtime is practically no different from C++. It also has affinities to the C/C++ packages. Cargo, the powerful package management tools Modern syntax Almost consistent troubleshooting and performance tuning experience. We can directly reuse some of the tools like perf which we are already very familiar with. FFI (Foreign Function Interface), call directly into the C APIs in RocksDB free of losses. The first and foremost reason is memory safety. As mentioned earlier, the issues in the memory management and data race might seem to be easy for C++ veterans. But I believe the utmost solution, which is what Rust is doing, is to put constraints in the compiler and solve it from the very beginning. For large projects, never ever bet the quality solely on human beings. To err is human. Though Rust is hard to begin with, I think it’s totally worth the while. Besides, Rust is a very modern programming language with its extraordinary type system, pattern modeling, powerful macros, traits, etc. Once you are familiar with it, it can greatly improve the efficiency which might be the same as if we chose C++ counting the time to debug. According to our experience, it takes about 1 month for a software engineer to code in Rust from zero experience. The efficiency is almost the same between an experienced Rust engineer and a Golang engineer. To sum up, Rust, as an emerging programming language, seems to be new to most of the developers in China, but it has become the most promising challenger to C/C++. Rust was also crowned the “most loved” technology in StackOverflow’s 2016 developer survey. So from a long term, Rust will shine in scenarios where memory safety and performance matter the most."}, {"url": "https://pingcap.com/weekly/2017-09-25-tidb-weekly/", "title": "Weekly update (September 18 ~ September 24, 2017)", "content": " Weekly update in TiDB 2017-09-25Last week, we landed 63 PRs in the TiDB repositories.Added Use new expression framework by default. Support the DOT explain format. Support the syntax for EXPLAIN FORMAT = stringlit Support the TIME/TIMESTAMP literal Removed Remove expression/typeinfer.go entirely. Abandon the selection controller. Fixed Roll back the ID allocator when a transaction fails to commit. Fix the returned column length of all the SHOW statements. Fix the Navicat for MySQL compatibility issue of the SHOW CREATE TABLE statement. Fix a bug in GC worker. Fix a bug of merge JOIN/stream aggregation and ORDER BY. Support the aggregation function that contains an aggregation function. Abort an unsafe transaction subject to GC command Fix a bug in parseDatetime. Improved Refactor the aggregation to reduce memory usage. Use continuous-value assumption to estimate cost. Speed up the add index operation. Don’t return the killed session when SHOW PROCESSLIST. Refine the return type, charset and collation for the get variable expression. First step to make parser to be totally compatible with MySQL. Add real tables for global/session status in the performance schema. Implement the ANALYZE columns pushing down. Rewrite the builtin function MOD Use the Goroutine pool to avoid runtime.morestack. Remove the usage of “TypeClass” in: builtin_arithmetic.go builtin_string.go expression.go builtin_cast.go builtin_math.go builtin_op.go Weekly update in TiSpark Fixed Fix the Region client error in handling for store no match and leader switch Fix an issue in PD Client leader switch. Weekly update in TiKV Last week, We landed 30 PRs in the TiKV repositories.Added Add benchmarks for JSON binary codec. Implement fmsketch for coprocessor. Add the SplitRegion API. Synchronize the Raft log when necessary. Add the debug framework. Add the namespace checker for PD. Support setting the store state for PD. Support initial schedulers’ name from the config file. Add the table namespace classifier for PD. Support scheduling based on regions’ read flow for PD. Support getting region’s namespace in PD. Fixed Fix setting a nonempty store to the tombstone state. Improved Replace opp_neg with overflowing_neg. Enhance synchronizing the WAL log. Add metrics for transactions. Use 96MB as the default size for regions. Use counters instead of histogram when statistics scan details. Fix resource downloading and extracting when bench JSON. Add more statistics for RocksDB. Update the futures. Refactor the cluster information for PD. New contributors (Thanks!) David Ding Hu Ming OuYang Jin Liang SHANG "}, {"url": "https://pingcap.com/blog-cn/talk-about-opensource/", "title": "谈谈开源(一)", "content": " 源码面前,了无秘密 —- 侯捷 前言 很多人的『开源』是一个比较时髦且有情怀的词汇,不少公司也把开源当做 KPI 或者是技术宣传的手段。但是在我们看来,大多数人开源做的并不好,大多数开源项目也没有被很好的维护。比如前一段时间微博上流传关于 Tengine 的讨论,一个优秀的开源项目不止是公布源代码就 OK 了,还需要后续大量的精力去维护,包括制定 RoadMap、开发新功能、和社区交流、推动项目在社区中的使用、对使用者提供一定程度的支持,等等。目前我们在国内没看到什么特别好的文章讲如何运营一个开源项目,或者是如何做一个顶级的开源项目。TiDB 这个项目从创建到现在已经有两年多,从开发之初我们就坚定地走开源路线,陆续开源了 TiDB、TiKV、PD 这三个核心组件,获得了广泛的关注,项目在 GitHub 的 Trending 上面也多次登上首页。在这两年中,我们在这方面积累了一些经验和教训,这里和大家交流一下我们做开源过程中的一些感受,以及参与开源项目(至少是指 TiDB 相关项目)的正确姿势。什么是开源 Open-source software (OSS) is computer software with its source code made available with a license in which the copyright holder provides the rights to study, change, and distribute the software to anyone and for any purpose.—- From Wikipedia 本文讨论的开源是指开源软件,简而言之,开源就是拥有源代码版权的人,允许其他人在一定许可证所述范围内,访问源代码,并用于一些自己的目的。 最基本的要求就是其他人可以访问源代码,另外获取代码后能做什么,就需要一个专门的许可证来规范(可以是自己写的,也可以用一个别人写好的)。里面一般会规定诸如对修改代码、新增代码、后续工作是否需要开源以及专利相关的事项。 OK,我们写一个 main.py 里面有一行 print "Hello World!",再和某个许可证文件一起扔到 GitHub 上,我们就有一个满足最低要求的开源项目了。为什么要开源 很多人觉得代码是一个软件公司最宝贵的资产,把这些最宝贵的资产让别人免费获取,对你们有什么好处?如果对手拿走了你们的代码,另起炉灶和你们竞争怎么办?或者是用户直接获取源代码,用于自己的环境中,那你们如何收钱呢? 对一个技术型公司来说,最宝贵的资产其实是人,对一个开源项目来说,最核心的资产是一个活跃的开源社区以及他人对这个项目的认可。 我们从这两方面来看一下开源在这两方面的影响。 Branding 很明显,开源是一种非常好的 PR、Branding 的手段,大多数大公司做开源也是这个目的,可以以一种成本几乎为零的方式宣传企业名,树立技术型企业形象。一个知名且良好的企业形象,对于各个方面都很有好处。比如国外有一个知名的技术媒体叫 HackNews,我司的产品曾经多次登上其首页,获得了大量的关注。其实那几次都不是我们自己发的帖子,而是其他人关注到我们的产品,自行做的传播。 人才获取 人才招聘最大的难处就是如何鉴别这个人的能力,他是否能干活、是否是靠刷题通过了面试。如何能和这个人工作一段时间,看到他是如何完成日常工作,那么对于这个人的能力了解会更进一步。为了实现这个目的,传统的手段是 Some How 找到和这个人共事过的人,听取他的意见。这样做首先要看运气,有的时候要转几层关系才能找到这样的人,并且不一定得到的是正确、真实的答案。 但是如果这个人已经给你的项目贡献了一些代码,并且代码质量比较高、贡献过程中和你的沟通很顺畅,那么一方面说明这个人软硬实例都不错,另一方面说明这个人对你做的事情很有兴趣。TiDB 有大量的正式、实习员工都是从 Contributor 中转化来的,以至于我们担心别把所有的人都招进来,社区没了 :) 。 社区贡献 可以这么说,如果没有开源社区,整个互联网都不会是现在这样。想象一下如果没有 Linux、MySQL、GCC、Hadoop、Lucence 这些东西,那么整个互联网的基础技术栈将不复存在(当然,肯定会出现另外一套东西,但是可能不会像开源的这套这么完善)。无数的开源社区贡献者贡献自己的力量,共同维持这样一个互助互利的社区,支撑社会技术进步。 我们也从开源社区中获得了很多支持,包括大家报的问题、提的建议以及来自全球一百四十多名贡献者提交的代码。随着项目的发展,我相信社区贡献代码的比例会持续提升。 提升项目质量 当一个项目以开源方式运营时,代码质量是项目的脸面,大家无论是在提交代码的时候,还是在 Comment 别人的 PR 的时候,都会非常谨慎,因为你的一举一动全世界都能看到,毕竟谁也不想人前露怯是吧。 对基础软件的意义 对于一个数据库这样的基础软件,最重要的就是正确性、稳定性和性能。前两点尤其重要,要保证这两点,一方面需要在开发和测试过程中尽可能提高质量,另一方面广泛的使用也非常重要。只有当你的产品有足够多的人试用,甚至用于生产环境,才可能有足够多的问题反馈以及产品建议。开发人员能做的测试毕竟是有限的,很多场景、环境或者是业务负载是我们想象不到的。来自实际用户的问题反馈有助于我们提升产品质量,来自用户的建议有利于我们提升产品易用性。只有长期在生产环境中运行过的基础软件的,才算是合格的基础软件的。 所以我们认为开源是基础软件的大趋势,无论是 Hadoop、MySQL、Spark 这样的知名产品,或者是 Linux 基金会、Apache 基金会、CNCF 基金会这样的巨头,都证明了这个观点。国内目前大公司比较热门的开源项目,也都集中在基础软件领域,比如百度的 Brpc、Palo、Tera,以及腾讯的 PaxosStore。PingCAP 开源了哪些项目 这里简单讲一下我们开源的几个 Repo 都是做什么: TiDB:数据库的 SQL 层 TiKV:数据库的分布式存储引擎 PD:集群的管理节点 Docs:项目的英文文档 Docs-cn:项目的中文文档 大家可以在 GitHub 上浏览我们的代码,看到我们完整的开发过程。开源模式下的开发流程 PingCAP 攻城狮小申典型的一天:8:00 起床,先登录 Slack 看一下昨晚定时跑的测试任务是否结果正常,然后关注一下 Slack 上各种 Channel 以及微信群、邮箱是否有什么重要的消息9:00 洗漱完+吃完早饭,逗一会可爱的女儿(也可能是被女儿逗),然后去上班9:30 到达公司,开始干活。* 打开电脑看看 GitHub 上面有什么新的 Issue * 看看自己的 PR 有没有被别人 Comment,如果有 Comment 的话,尽快解决;如果还没人看的话,at 一下相关的同学,求 Review * 看看有没有别人的 PR 需要自己 Review,特别是 at 自己的那些 PR * 带上耳机开始写点代码 * Slack 有人 at 我,赶紧回复一下 * Slack 上我关注的 Channel 中有人在讨论问题,我很感兴趣,加入进去讨论一会 * 同事要做一个新的 Feature,写了设计文档,我点进去看了一遍提了几个 Comment 12:00 肚子可耻的饿了,呼朋唤友去吃饭,路上顺便讨论讨论技术以及八卦13:00 吃饭归来,看看邮件、Slack、微信留言,处理一下紧急的事情13:30 小睡一会14:00 小睡结束,接一杯咖啡,开始下午的工作,键盘敲起来。。。。。15:30 参与同事的设计评审会议,通过视频会议系统和远程的同事一起讨论设计方案,拍板后开干16:30 休息一下,然后继续敲代码、Review PR18:00 大部分同事已经去吃饭了,我准备开车回家吃饭去20:30 吃完饭,收拾完,没什么事情,打开电脑看一会邮件、Issue、PR22:30 休息一会,准备洗澡睡觉如何做一个开源项目 首先你需要根据自己的诉求、商业模式等选择一个开源协议,常见的有 GPL 、BSD、Apache 和 Mit ,这些开源协议的区别在阮一峰老师的这篇博客中解释的很清楚了,推荐大家阅读。协议选定之后,再选择一个代码托管平台,目前的标准选择是 GitHub,注册一个 GitHub 账号,申请一个 Orgnization 之后,就可以开始用了,如果不需要私有 Repo 的话,那么不需要交任何费用。开始代码开发,提交第一次 Commit,完成 Readme 的撰写(一个好的 Readme 真的很重要)。后续的开发都需要通过 Pull Request 进行,最好不要直接 Push Master。一个严肃的项目需要把 Master 加入 Protected Branch,禁止直接 Push。为了保证后续的代码提交都是 Work 的,最好在 GitHub 中集成至少一个 CI 服务,常用的有 TravisCI、CircleCI (最近一段时间 CircelCI 似乎总是出问题)。然后在 PR 的设置页面上要求 PR 通过了 CI 才能合并。如果有人试用项目时发现一些问题,会通过 Issue 反馈,所以需要关注 Issue ,尽快给予回复。另外将 Issue 通过 Label 分门别类是一个好的实践,便于大家快速搜索、分类 Issue。比如我们会将一部分简单些的 Issue 标记为 Help Wanted,如果有新加入社区的同学想要开始贡献代码,那么这些 Issue 就是不错的起点。当参与的人越来越多,那么会有一部分人开始贡献代码,Maintainer 需要 Review 其他人的 PR,保证能项目自身的代码质量要求、编码风格一致。最后一点,一个好的项目需要配备完善的文档,帮助大家使用项目。包括架构、简要介绍、详细介绍、FAQ、使用范例、接口文档、安装部署以及最佳实践等等。这点也是大多数项目所忽略的。如何参与开源项目 试用 最简单的参与方式是试用开源项目,这也是开源最大的一个好处,所有人都可以随时试用,相当于有很多人帮助项目作者做测试。毕竟如果只有作者自己做测试,遇到的环境、场景、应用方式会比较单一,总有一些你想像不到的地方会出问题。所以每一个测试出来的问题都很宝贵,我们都会尽可能快的评估和回复。报 Issue 试用过程中大家可能会遇到各种问题,特别是文档中没有提及的问题,反馈问题的最佳方式是在 GitHub 上新建 Issue,这样所有的人都可以看到,而且通过 Issue 来反馈我们也会更重视一些,有人会定期扫一遍未处理的 Issue。当然,建立 Issue 之前先搜索是否和已有的 Issue 重复是个好习惯。在 Issue 中尽可能详细的描述清楚遇到的问题,以及一个可操作的复现步骤,包括所用 Binary 的版本、部署方式、客户端以及服务的日志、操作系统的日志(如 dmesg 的输出)。如果不能复现,也尽可能详细地提供 Log。这些对开发人员追踪 Bug 会非常有用。提出建议 如果对项目有什么建议,也可以通过新建 Issue 来反馈, 我们一般会给出是否会支持,如果要支持的话,大概会在什么时候支持。提 PR 当你使用 TiDB 遇到问题或者需要新的 Feature,而觉得自己有能力 Fix 或者是当前官方还没有精力 Fix 时,可以尝试自己修改代码,解决问题。目前 TiDB 项目的 Contributor 有 140 多个,分散在全球十几个国家。其中不乏深度参与的用户。如果是小的功能或者是简单的 Bug Fix,可以在相关的 Issue 下面吼一声,让大家知道你在做这个事情即可,这样不会有人做重复的工作。如果做的过程中遇到了什么问题,也可以在相关的 Issue 中和 Maintainer 讨论。如果要做的是比较大的功能,那么最好先和官方做一轮讨论,然后写一个尽可能详细的 Design,讨论 OK 后,开始开发。讲一点好玩的事情 在开源项目中总能或多或少的发现奇葩的 Issue,比如这个看到这个 Issue 真的是震惊了。"}, {"url": "https://pingcap.com/meetup/meetup-20170920-no56/", "title": "【Infra Meetup No.56】MonetDB/X100 Paper 解读", "content": " 上周六,PingCAP Infra Meetup 第 56 期特设论文专场,我司核心工程师张建与大家一起分享并解读了“MonetDB/X100: Hyper-Pipelining Query Execution” 论文。此篇论文作为分析型数据库领域内引用次数最多的论文之一,它为何如此火爆?在今天的文章里你应该可以找到答案。 精彩视频 视频 | Infra Meetup No.56: MonetDB/X100 Paper 解读精彩现场 在 PingCAP Infra Meetup 第 56 期论文专场,来了很多对 MonetDB/X100 论文感兴趣的小伙伴们。分享一开始,我司联合创始人兼 CEO 刘奇就为何选择 MonetDB/X100 这篇论文分享了自己看法。刘奇提到:“如果大家有阅读近两年新出的一些 Paper,会发现里面引用率最高的一篇文章就是 MonetDB/X100。MonetDB/X100 发表于 2005 年,其实不算新。但读过该论文的人会发现目前主流的 OLAP 系统相关的技术,基本上都能在这篇论文中找到影子,如文中提到了列存、Pipeline,甚至是 JIT。他做 JIT 的思路不一样,都是比较早就有的,所以这是一篇很不错的论文。现在也可以看到很多性能比较的时候,大家新做了一个系统,说我的性能非常好,会拿出来 benchmark 说你看我打败了 MonetDB。另外还有一些比较创新的项目,多是基于 MonetDB 改造的。一个就是英特尔最近出的一篇论文,他把 MonetDB 改造一下,把正则表达式的搜索,放到 FPGA 里面去。英特尔最近出了一款服务器,这个服务器的 CPU 和 FPGA 是放在一起的,他们得到 Performance 最小提倡是 2.3 倍以上,大概意思上就是说,MonetDB 在这上面做一个简单的改造,就可以适应到更新的硬件。在 2012年的时候,第一个提供论文、代码的基于 MonetDB 的 GPU 的 Database 也出来了。当时是在 TPCH 的 query 里面,有一些复杂的 query,提升是非常的明显。所以大家可以看到,基于 MonetDB 改造的,在 FPGA 或者 GPU上运行的系统都有,实际上这是一个非常优秀的学术的原形,今年得了十年最佳论文奖。”接下来,我司核心工程师张建就这篇最佳论文做了拆分讲解。为了让大家更好的理解今天分享的主题,张建首先简单介绍了一下 SQL 的执行流程、Volcano 执行框架以及 CPU 的硬件特性,进一步展示了当时一些数据库的 performance 情况,并分析了为什么其执行效率低。就大家关心的 MonetDB/X100 的设计思路以及总体架构,分析了一些 MonetDB/X100 的执行算子,通过具体的列举简单介绍了 MonetDB/X100 的执行过程以及动态生成的 Vectorized Primitive 的特点。技术干货节选 以上就是张建带给大家的部分论文精彩内容,小伙伴们可以观看现场演讲视频,慢慢 Enjoy~ 也敬请期待我们下一期的内容 :)附:完整 PPT 链接 PingCAP Infra Meetup作为一个基础架构领域的前沿技术公司,PingCAP 希望能为国内真正关注技术本身的 Hackers 打造一个自由分享的平台。自 2016 年 3 月 5 日开始,我们定期在周六的上午举办 Infra Meetup,邀请业内大牛与大家深度探讨基础架构领域的前瞻性技术思考与经验。在这里,我们希望提供一个高水准的前沿技术讨论空间,让大家真正感受到自由的开源精神魅力。 "}, {"url": "https://pingcap.com/weekly/2017-09-18-tidb-weekly/", "title": "Weekly update (September 11 ~ September 17, 2017)", "content": " Weekly update in TiDB Last week, we landed 46 PRs in the TiDB repositories.Added Add required tables of MySQLX . Add TOML configuration file support. Removed Remove the performance schema instrumentation. Fixed Fix show create table with foreign key. Cast values only for modified columns in the update statement to avoid unnecessary check. Fix an OOM issue when analyzing table. Fix a cast (date as datetime) error. Fix a bug about the DATE literal. Improved Change the FMSketch hash function from “fnv” to “murmur”. Add the PARTITION BY KEY grammar support. Refine setting/getting the SQL_MODE variable. Support the NVARCHAR syntax. Refine the parser of localtime and localtimestamp. Push down the ANALYZE INDEX statement. Support stream aggregation in the new optimization plan. Hide the security information in SHOW PROCESSLIST. Add a goroutine pool package utility. Refactor the following expression/builtin-function evaluation framework: ADDDATE, SUBDATE TIMEDIFF VALUES ROW SETVAR, GETVAR GREATEST, LEAST CONVERT_TZ MAKETIME ADDTIME, SUBTIME Weekly update in TiSpark Added Add the JDBC Thrift Server / spark-sql support. Add the back-off retry policy. Add the Meta table prefix support. Fixed Fix the Null decoding error. Fixed some Styling issues. Improved Added the Integration test framework. New contributors (Thanks!) Cheng Lian Weekly update in TiKV Last week, We landed 34 PRs in the TiKV repositories.Added Balance regions based on the read flow. Make the Raft tick configurable for PD. Add a classifier interface for namespace. Balance by the namespace. Fixed Fix a race condition for threadpool. Fix the active region statistics. Fix cleaning up data between regions. Stop the threadpool before quitting the scheduler. Fix the marshal operator. Fix the operator timeout issue. Fix a bug in cast_str_as_int. Wrap InitLogger in sync.Once for thread safety. Fix a compiling error. Improved Add tests for the gRPC services. Add two queues cache for PD. Cache elf sections for backtrace. Optimize JSON. Skip checking region 0. Adjust metrics for the coprocessor. Remove the stale peers as soon as possible. Enable pin_l0_filter_and_index by default. Enhance metrics for the scheduler. Optimize the LIKE expression. Check the leader request when becoming a follower after receiving message with higher term. Use util::time::instant instead of std::time::instant. Add metrics for compression ratio at different levels. Remove the statistics that may overflow. New contributors (Thanks!) Rain Li OuYang Jin "}, {"url": "https://pingcap.com/blog/2017-09-15-rocksdbintikv/", "title": "RocksDB in TiKV", "content": " This is the speech Siddon Tang gave at the RocksDB meetup on August 28, 2017. Speaker Introduction Agenda Why did we choose RocksDB? How are we using RocksDB? TiKV Architecture Region Raft InsertWithHint Prefix Iterator Table Property for Region Split Check Table Property for GC Check Ingest the SST File Others How are we contributing? Future Plans Speaker Introduction Hi every one, thanks for having me here, the RocksDB team.Today, I will talk about how we use RocksDB in TiKV. Before we start, I will introduce myself briefly. My name is Siddon Tang, chief engineer of PingCAP. Now I am working on TiDB, the next generation SQL database; and TiKV, a distributed transactional key-value store. I am an open source lover and I have developed some open source projects like LedisDB (BTW, the backend engine is also RocksDB), go-mysql, go-mysql-elasticsearch, etc…Agenda What I will talk about today is as follows: Why did we choose RocksDB in TiKV? How are we using RocksDB in TiKV? How are we contributing to RocksDB? Our future plan Why did we choose RocksDB? OK, let’s begin. Why did we decided to use RocksDB instead of LevelDB, WiredTiger, or any other engines. Why? I have a long list of reasons: First of all, RocksDB is fast. We can keep high write/read speed even there’s a lot of data in a single instance. And of course, RocksDB is stable. I know that RocksDB team does lots of stress tests to guarantee the stability; And it’s easy to be embedded. We can call RocksDB’s C API in Rust directly through FFI, because TiKV is written in Rust. Not to mention that it has many useful features. We can use them directly in production to improve the performance. In addition, RocksDB is still in fast development. Many cool features are added, and the performance is being improved continuously. What’s more, RocksDB has an very active community. If we have questions, we can easily ask for help. Many RocksDB team members and us are even WeChat (a very popular IM tool in China) friends, we can talk to each other directly. Back to the topHow are we using RocksDB? TiKV Architecture After we decided to use RocksDB, the next question is how to use it in TiKV. Let me start with the TiKV architecture briefly.First of all, all data in a TiKV node shares two RocksDB instances. One is for data, and the other is for Raft log.Region Region is a logical concept: it covers a range of data. Each region has several replicas, residing on multiple machines. All these replicas form a Raft group.Raft TiKV uses the Raft consensus algorithm to replicate data, so for every write request, we will first write the request to the Raft log, after the log is committed, we will apply the Raft log and write the data.The key format for our Raft log saved in RocksDB is: region ID plus log ID, the log ID is monotonically increased.InsertWithHint We will append every new Raft log to the region. For example, we first append log 1 for region 1, then we might append log 2 for the same region later. So we use memtable insert with the hint feature, and this feature improves the insert performance by fifteen percent at least.The version is embedded in the key as a suffix, and used for ACID transaction support. But transaction management is not our topic today, so I just skip it.Back to the topPrefix Iterator As you can see, we save the key with a timestamp suffix, but can only seek the key without the timestamp, so we set a prefix extractor and enable the memtable bloom filter, which helps us improve the read performance by ten percent at least.Table Property for Region Split Check If we insert a lot of data into a region, the data size will soon exceed the threshold which we predifine and need to be split.In our previous implementation, we must first scan the data in the range of the region, then calculate the total size of the data, if the total size is larger than the threshold, we split the region.Scanning a region has a high I/O cost, so now, we use table properties instead. We record the total data size in the SST table property when doing compaction, get all table properties in the range, then add up the total size.Although the final calculated total size is approximate, it is more effective, we can avoid the useless scan to reduce the I/O cost.Table Property for GC Check We use multiple versions for a key, and will remove the old keys periodically. But we don’t know whether we need to do GC in a range or not, in the past, we simply scanned all the data.However, since we only need to do GC before a specified safe point, and most keys have only one version, scanning these keys every time is wasteful.So we create an MVCC property collector to collect the version information, including the maximum and minimum timestamp, the row number and version number. Then every time before scanning a range, we can check these properties to see if we can skip the GC procedure or not.For example, if we find the minimal timestamp in the table property is bigger than the safe point, we can immediately skip scanning the range.Back to the topIngest the SST File And in our previous implementation, if we wanted to do bulk load, we must scan all the key-values in the range and save them into a file. Then in another RocksDB, read all the key-values from this file and inserted them in batches.As you can see, this flow is very slow and can cause high pressure in RocksDB. So now, we use the IngestFile feature instead. At first, we scan the key-values and save them to an SST file, then we ingest the SST file directly.Others More than that, we enable sub compaction, pipelined write, and use direct I/O for compaction and flush. These cool features also help to improve the performance.How are we contributing? We are not only using RocksDB, we also do our best to contribute to the community. We have done many stress tests and have found some serious data corruption bugs. Like these issues. #1339: sync write + WAL may still lose newest data #2722: some deleted keys might appear after compaction #2743: delete range and memtable prefix bloom filter bug Thank goodness, we haven’t found any of our users meet these problems in production.We also added features and fixed some bugs, like these. Because TiKV can only call the RocksDB C API, we also add many missing C APIs for RocksDB. #2170: support PopSavePoint for WriteBatch #2463: fix coredump when release nullptr #2552: cmake, support more compression type many C APIs Future Plans In the future, we are planning DeleteRange API, which is a very useful for us. But now we found some bugs 2752 and 2833, we are trying our best to fix them, of course, together with the RocksDB team.And we will try to use BLOB DB when it’s stable. On the other hand, we will also try different memtable types to speed up the insert performance, and use partitioned indexes and filters for SATA disks.Back to the top"}, {"url": "https://pingcap.com/blog/2017-09-12-futuresandgrpc/", "title": "Futures and gRPC in Rust", "content": " This is the speech Tang Liu (tl@pingcap.com) gave at the Bay Area Rust Meetup August 2017. See the video. Speaker Introduction Async Programming Why not Sync? Why Async? Callback Hell Coroutine Makes it Easy Future, Another Way Futures in Rust Futures Combinator Synchronization Stream Sink Task gRPC Why gRPC? HTTP/2 gRPC based on HTTP/2 Combine Futures and gRPC C gRPC Keywords Pseudo Flow Unary Client Streaming Server Streaming Duplex Streaming Unary Future Implementation Client Unary Unary Future Resolve Future Benchmark Misc Speaker Introduction Hi everyone! I am very glad to join the meetup here. Thanks, the Rust team.Today I will talk about the Futures and gRPC in Rust. Before we start, let me introduce myself briefly. My name is Siddon Tang, and siddontang on Github, chief engineer at PingCAP. I have been working on the next generation SQL database, TiDB, and a distributed key-value store, TiKV. By the way, TiKV is also written in Rust. I’m also an open source lover, and have some open source projects, such as LedisDB, go-mysql, go-mysql-elasticsearch, rust-prometheus, etc.Today, I will first discuss Async briefly, then I will introduce Futures in Rust. Of course, you guys here are very familiar with them, so I will just go through it quickly. Then I will talk about gRPC, and in the end, I will show you how we use futures to wrap the gRPC in Rust.Async Programming Let’s begin. About Async.Why not Sync? The first thing is why not Sync. As we all know, the Sync programming is easier. If the load of your service is low, using Sync may be better. You just need to start some threads to handle the concurrence.But if we want to support a high performance service, such as a database, Sync is not enough. Sync I/O can block the execution, which reduces the performance. Although we can use threads, but thread is heavy and wastes system resources. What’s more, frequent thread switching is inefficient and causes the performance to reduce seriously.Why Async? So we chose Async.There is no blocking in Async programming, so we don’t have to wait the slow I/O and can do other things. When the I/O is ready, the system can notify us and we can handle it again. This is very efficient and therefore, the performance is high. But as you can see, the Async way is much more complex and it is hard to write the code correctly. The code logic is split into pieces when the I/O is not ready and we have to switch to do other things.Callback Hell auto r = make_shared<int>(); do_async_foo() { do_foo_a(|| { do_finish(|| { *r = 10; }) }) }) Sometimes, we have to use the callback mechanism to handle the I/O or other asynchronous notifications, and may sink into the callback hell, like this. Oh, so many callbacks.Coroutine Makes it Easy Of course, if we have to write code like this, it might drive us crazy. Luckily, we have at least two ways to bypass it. First, it is the coroutine.Coroutine is a lightweight thread which is supported in many languages. Like the boost coroutine library, WebChat libco library in C plus plus, yield and greenlet in Python, and of course, goroutine in Go.Here is a simple example to use goroutine and channel in Go. The two internal cool features allow us to write high performance concurrent code easily. I personally believe that it is the main reason that Go becomes more and more popular nowadays.Future, Another Way let future = do_async( future() ) .then( future_a() ) .then( future_b() ) .then( future_c() ); future.wait(); Some languages don’t provide coroutine, but we can have another workaround, which is future. Future is a kind-of promise. When we begin to resolve a future, the result of the future may not be ready now and cannot be retrieved now, but after the future is performed later, we can get the result again.You can wait the future to be finished, and multiple futures can be combined into a future chain.Futures in Rust So what about futures in Rust?In Rust, future has already been supported by Alex. Thanks, Alex!Based on the Rust trait, the future is zero cost, which means that you don’t need to do extra heap allocation or dynamic dispatch. Future is easy to use, you can combine many futures into a chain, and use the combinator like an Iterator API.The future is demand-driven, not callback, you should poll the future explicitly to check whether the future is ready or not. No callback can also avoid the heap allocation, and we can cancel the future easily too.Futures Future is a trait and the main function is poll.pub trait Future { type Item; type Error; // check the future is resolved, return Ready or NotReady fn poll(&mut self) -> Poll<Self::Item, Self::Error>; // wait until the future is resolved fn wait() -> result::Result<Self::Item, Self::Error>; } pub type Poll<T, E> = Result<Async<T>, E>; pub enum Async<T> { Ready(T), NotReady, } We must implement the poll for our customized future. The poll can return NotReady, which means the future is not ready and we should poll later. If Ready is returned, the future is finished and we can get the result. We can also wait the future to finish explicitly. If we call wait, the execution will be blocked until the future is performed.Future ExampleHere are some very simple future examples. For the ok future, wait will return Ready, the result is 1; for the empty future, poll will return NotReady.let f = ok::<u32, u32>(1); assert_eq!(f.wait().unwrap(), 1); let mut f = empty::<u32, u32>(); assert_eq!(f.poll(), Ok(Async::NotReady)); Combinator We can use combinator to chain the futures.let f = ok::<u32, u32>(1).map(|x| x + 1); assert_eq!(f.wait().unwrap(), 2); let f1 = ok::<u32, u32>(1); let f2 = ok::<u32, u32>(2); let (_, next) = f1.select(f2).wait().ok().unwrap(); assert_eq!(next.wait().unwrap(), 2); For example, we can use the ok future plus map combinator, and the end result is 2. We can use select to wait for two futures. If either future is ready, the select future is finished and returns the result plus a next future to be resolved later.Synchronization The future library provides two synchronization channels. One-shot is for SPSC and channel is for MPSC. Both can be used for communication cross threads.Stream Stream is like Future, and you can resolve the value one by one until the stream is finished.pub trait Stream { type Item; type Error; // check the future is resolved, return Ready or NotReady // Ready(Some) means next value is on the stream // Ready(None) means the stream is finished fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error>; } If the poll of the stream returns Ready Some, it means you can still get the next value of the stream. If Ready None is returned, it means the stream is finished and you can never poll the stream again.Sink Sink is a way to send value asynchronously.pub trait Sink { type SinkItem; type SinkError; fn start_send(self, item: Self::SinkItem) -> StartSend<Self::SinkItem, Self::SinkError>; fn poll_complete(&mut self) -> Poll<(), Self::SinkError>; fn close(&mut self) -> Poll<(), Self::SinkError>; } We can use start_send to send one value, and use poll_complete to flush the sink and check whether all values are sent or not, or you can use close to close the sink.Task The task is used to drive the future computation.# If the future is not ready? let handle = task::current(); # If the event of interest occurs? handle.notify(); # What to do after notify? executor.poll(f); If the future is not ready, we can use task current to get a task handle. We can use task notify to wake up the task when it is ready, and the executor should poll the future again.That’s all about the Rust futures for today.gRPC Now let’s talk about gRPC.If you want to develop a service, the first thing you need to decide is how the client communicates with your service. You may implement your own protocol and RPC. Although it is …"}, {"url": "https://pingcap.com/weekly/2017-09-11-tidb-weekly/", "title": "Weekly update (September 04 ~ September 10, 2017)", "content": " Weekly update in TiDB Last week, we landed 49 PRs in the TiDB repositories.Added Add the column size limit when creating table. Add the syntax for admin show ddl jobs. SSL/TLS support. Fixed Fix an ORDER BY bug. Add entry limit for transactions when doing DDL job. Fix a bug during the limit operator pushdown. Check the default value of the column option in the CREATE TABLE statement. Fix the DEFAULT output in SHOW CREATE TABLE. Fix a bug during the TopN operator pushdown. Fix an OOM issue when analyzing tables in some cases. Improved Do some prework before pushing down the analyze table statement. Rewrite fieldTp2EvalTp() to use mysql.TypeXXX instead of TypeClass. Add timezone for CastAsTime. Rewrite hashCode() for requireProp. Use temporary session in gc_worker instead of global singleton. Change the log package to logrus. Let allocID() return int to be more efficient. Rewrite hex and bit literals implementation. Support client specified collation. Refactor IndexLookUpExecutor. Update the time Add() implementation. Refactor the following expression/builtin-function evaluation framework: FROM_UNIXTIME EXTRACT EXPORT_SET GET_FORMAT INTERVAL FIELD CONVERT FORMAT INSERT Builtin abot JSON CURRENT_TIME TIME_TO_SEC, SEC_TO_TIME INTDIV New Contributor (Thanks!) Wang Guoliang Weekly update in TiKV Last week, We landed 32 PRs in the TiKV repositories.Added Implement div_real and div_decimal for expression. Add JSON functions for DAG. Add the LIKE signature for DAG. Add the short name for raftdb in tikv-ctl. Implement the bit operation for expression. Implement the int_as_true and decimal/real_as_false for expression. Add the IfJson, IfNullJson signature and some flags for DAG. Fixed Fixed capacity parsing. Fixed an unwrapping panic in scheduler. Drop the delete-range feature temporarily. Improved Add more tests for config structs. Refactor 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 on PD. Cleanup the threadpool. Add the panic detail information. Optimize merging array elements. Use time.Since instead of time.Now().Sub. Check if the log is initialized when starting up. New Contributor (Thanks!) Wang Guoliang "}, {"url": "https://pingcap.com/blog/2017-09-08-rocksdbbug/", "title": "How we Hunted a Data Corruption bug in RocksDB", "content": " Data was corrupted. A cluster panicked. The crime scene was compromised. What happened? Detective Huang (huachao@pingcap.com) went all lengths to locate the criminal and solved it once and for all.Background As a distributed open source HTAP database, TiDB uses TiKV as its storage engine. Inside TiKV, we use RocksDB as the local storage. RocksDB is a great project. It’s mature, fast, tunable, and widely used in very large scale production environments. We have been working very closely with the RocksDB team. Recently, we found a bug in the DeleteRange feature in RocksDB.Before we begin, let’s introduce some basic knowledge about RocksDB first.RocksDB is a log structured storage engine. All writes are append-only, and every write is assigned a globally increasing sequence number to distinguish it.Let’s use (key,sequence,entry_type) to denote an entry in RocksDB. If we put “a”, “b”, and “c”, RocksDB will append three PUT entries to the disk: (a,1,PUT),(b,2,PUT),(c,3,PUT). If we put it in a table, it goes like this: key sequence entry_type c 3 PUT b 2 PUT a 1 PUT If we delete “c”, RocksDB will not erase the (c,3,PUT) entry in place, but append a DELETE entry: (c,4,DELETE) instead, so the table becomes: key sequence entry_type c 4 DELETE c 3 PUT b 2 PUT a 1 PUT Then if we try to get “c”, RocksDB will encounter entry (c,4,DELETE) first and return that “c” is not found.Of course, RocksDB cannot keep all the entries forever. It needs to compact and drop old entries when necessary. RocksDB organizes entries into SST (Sorted String Table) files, we can think of an SST as a big sorted array of key-value pairs in the disk, and SST files will be compacted into different levels later.All the entries are appended to a WAL (Write Ahead Log) and a Memtable first. When the Memtable is large enough, it will be flushed to a new SST in Level-0. SST files in Level-0 can be overlapped with each other because they haven’t been compacted yet. When the files in Level-0 are large enough, RocksDB will compact the SST files in Level-0 with overlapped SST files in Level-1, and then output new SST files to Level-1 without overlap. Then files in Level-1 will be compacted to the next level and so on. In short, only SST files in Level-0 can be overlapped, SST files under Level-0 must not overlap with each other in the same level.Additionally, RocksDB logs some compaction information in its LOG file, including all the input and output file numbers of each compaction, and other useful statistics. RocksDB also records all deleted and added files of each compaction in the MANIFEST file, plus the information of all the files of each level. The LOG file and the MANIFEST file are two important sources to track RocksDB’s behaviors, we will use them later.Well, that’s an overly simplified introduction to RocksDB, but enough to go on now.DeleteRange Now we know how to delete a key in RocksDB, but what if we want to delete a range of keys? For example, if we want to delete keys in a range [a,c), we can first scan keys in [a,c), which are “a” and “b” in the above example, and delete them one by one. The result of the above example will be:(a,1,PUT),(b,2,PUT),(c,3,PUT),(c,4,DELETE),(a,5,DELETE),(b,6,DELETE) In the table, it looks like: key sequence entry_type a 6 DELETE b 5 DELETE c 4 DELETE c 3 PUT a 2 PUT b 1 PUT That’s how we delete a range in TiKV now, for example, to drop a table or destroy a replica. It’s easy, but has two drawbacks: A replica can contain a lot of keys, it’s costly to scan them all Deleting all keys appends a lot of delete entries. So as you can see, deleting data can result in more data temporarily (before compaction), and more IO amplification. Let’s see how the DeleteRange feature from RocksDB comes to rescue. In the above example, instead of scanning range [a,c) and delete “a” and “b” separately, we just append a DeleteRange entry ([a,c),5,DELETE_RANGE), which results in:(a,1,PUT),(b,2,PUT),(c,3,PUT),(c,4,DELETE),([a,c),5,DELETE_RANGE) In the table, it looks like: key sequence entry_type [a,c) 5 DELETE_RANGE c 4 DELETE c 3 PUT a 2 PUT b 1 PUT Now, if we try to get “a”, we will encounter the DELETE_RANGE first, and return that “a” is not found. That’s good, we don’t need to scan all data anymore, and the size of a DeleteRange entry can be ignored in face of a large range. So we planned to use the DeleteRange feature in TiKV and started to test it.The BUG Before telling the story, let’s see how we check data in tests first. TiKV has a useful consistency check mechanism, which has helped to expose some serious bugs. When it is enabled, TiKV runs the consistency check periodically. Consistency check will calculate a hash of each replica and compare the hashes of all replicas to check whether they are consistent. If the hashes don’t match, something must be terribly wrong, so it will panic.Everything worked great until one of our test clusters panicked?The panicked cluster, which we named it Cluster A, was running a branch with the DeleteRange feature, so that’s why we started hunting the DeleteRange bug.Back to the topRound 1 There are 4 TiKV instances KV1, KV2, KV3, and KV4 in Cluster A, and the consistency check showed that we had an abnormal replica R2 in KV2, and two normal replicas R1 and R3 in KV1 and KV3. We used tikv-ctl to print out the diff of R2 and R1 to see what’s wrong. The diff showed that R2 had lost some ranges of data, and some deleted data reappeared too. Since we were testing the DeleteRange branch in this cluster, we guessed that this could happen if a DeleteRange entry dropped some entries in a wrong way during the compaction.We tried to collect more evidence to locate the problem, but unfortunately, the crime scene had been destroyed after we used tikv-ctl to open the underlying data directory, because tikv-ctl started RocksDB, which reorganized the data in some background compaction, and we hadn’t made any backup.However, the problem was still there, we did with what we got. We analyzed the log of the abnormal KV2 and found out that R2 sent a snapshot to R1 in 2017-08-15 11:46:17, and panicked in 2017-08-15 12:11:04. Since R1 was restored from R2’s snapshot in 11:46:17 and R1 was OK in 12:11:04, it meant that R2 should be OK in 11:46:17, so what happened between 11:46:17~12:11:04? We assumed that one of the compaction in RocksDB between that time was wrong and started investigating RocksDB’s LOG and MANIFEST files. The LOG file showed that some compactions were done in that time. We could do a cross-reference with the MANIFEST file to get more details. However, remembered that the crime scene had been destroyed? It meant that the MANIFEST file was truncated and the SST files generated in that time were deleted and we were stalled.So we decided to deploy another test cluster, which we called it Cluster B, and hopefully, it would panic again soon so that we could have another fresh crime scene. Meanwhile, we kept investigating here and there, but still without any clue. We had no choice but tried to locate the bug in the source code of RocksDB directly. We believed that the bug was related to either the DeleteRange feature or the compaction, so we dived into there. After a few days, we got some suspicious places but still nothing solid, except to realize that the DeleteRange implementation was more complicated than we expected.Round 2 A few days later, Cluster B panicked again, so we were given another chance to hunt, let’s go. This time, we protected the crime scene very well and made a backup before doing anything.The consistency check showed that we had an abnormal replica R3 in KV3, and two normal replicas R1 and R2 in KV1 and KV2. And …"}, {"url": "https://pingcap.com/meetup/meetup-2017-09-06/", "title": "【Infra Meetup No.55】TiDB Pre-GA 版本新特性介绍以及后续功能展望", "content": " 上周六,PingCAP Infra Meetup 第 55 期,由我司 Engineering VP 申砾为大家分享《TiDB Pre-GA 版本新特性介绍以及后续功能展望》。在活动现场,小伙伴们就 TiDB 新特性提出了很多问题,申砾在现场与大家有一番深度的交流与讨论。精彩现场小编立马为你呈现。 精彩视频 视频 | Infra Meetup No.55:TiDB Pre-GA 版本新特性介绍以及后续功能展望精彩现场 上周,TiDB 正式发布了 Pre-GA 版本。针对 Pre-GA 版本的新特性,PingCAP Infra Meetup 第 55 期特设定 Pre-GA 详解专场。活动当天,现场来了很多关注 TiDB 的粉丝们。简单开场后,我司 Engineering VP 申砾同学介绍到本期内容主要围绕新版本带来的变化和内部实现细节,以及这种新型的 HTAP 数据库解决的实际问题和典型应用场景等做深度解析。技术干货节选 TiDB Pre-GA 版本对 MySQL 兼容性、SQL 优化器、系统稳定性、性能方面做了大量优化工作。本次分享中,申砾就各个组件的优化做了详解:TiDB 在优化器方面 RC4 已经从一个假的基于代价产品模型,切换成一个真的基于代价产品模型,也真的是用统计信息去算。在 RC3 版本中,一些代价实际上是有规则算法的,比如说,A 等于 10 设置一个过滤比例,A 大于 10 又算另外一个过滤比例,这都是一些规则,RC4 是基于代价的一个传统模型。 Pre-GA 新特性也主要对代价模型做了一些调整。 其次,在索引选择上做了优化,可以支持不同类型字段比较的索引选择,这一优化用户反馈查询速度明显变快。 再者,支持 Join Reorder,对于 OLTP 层面来说,Join Reorder 不太会用到,但对于一些比较复杂的场景,比如说有的用户使用参报表。这个时候有可能会出现 Join 报表,特别是在 TCH 里面,多表 Join 比较常见。下一步计划也将统计信息导入 TiSpark 里,指导 TiSpark 做 Join Reorder 。 在执行器方面 首先在 MySQL 兼容性做了大量的工作,特别是像时间类型这种比较复杂的类型,字面值的表达方式多种多样,还要考虑各种不合法的字面值,不合法的字面值需要处理成零,还是 Null,其实挺多细节在里面。 支持 Natural Join,我们以前支持 Using 来制订,现在我们支持 Natural Join 这个语法。这个是由我们的 Contributor 一个大二的学生贡献出来的 PR,在此特别感谢。 支持 JSON,然后支持 JSON 字段上各种操作。同时支持去修改使用某一个字段,并支持对 JSON 字段中某一属性去建索引,这样才可以更快速的用其中某一个字段做过滤条件。 减小执行器内存占用,大部分内存消耗在读出来的数据上面,我们把读出来的数据表示结构做了精简,在数据量比较大的时候,大概能比之前的版本少 20% 的内存。 支持在 SQL 语句中设置优先级,并根据查询类型自动设置部分语句的优先级。 完成表达式框架重构,执行速度提升 30% 左右。 在介绍完 TiDB 后,申砾接下来介绍了下 PD 方面的优化。PD 主要工作还是支持手动切换 PD 集群 Leader,可以手动的把 PD Leader 做一个迁移。TiKV Raft Log 使用独立的 RocksDB 实例。以前是一个 TIKV ,一个 RocksDB,数据和 Raft Log 都写在里面,现在是把数据和 Raft Log 分成两个 RocksDB 实例。这样对未来底层的优化有了更多的可能性。例如 Raft Log 可以不用写入在 RocksDB 中。 使用 DeleteRange 加速数据迁移,比如把一个副本从 PGA 迁到 PGB ,然后 PGA 这个副本的数据没有用了,以前的做法是一点点删除,现在可以用 DeleteRange 直接删除。 在 TiKV 上支持更多运算符下推,让 where 条件包含这些运算符的聚合操作可以下推到 TiKV 上进行计算。 至少有 10% 的性能提升,稳定性提升。 最后,申砾就大家关注的 TiDB GA 版本发布及后续功能优化做了分享。TiDB GA 将在 9 月底左右发布,核心主要围绕稳定性、性能、正确性、兼容性方面做大量工作。申砾就后续功能做了详解,主要是以下几点: 一个更好用的调度器,这个调度器指的是 PD 去调度 TiKV 的 Region 的位置。通过给不同的 TIKV 节点设置不同的权重, PD 会往这些 TIKV 节点 根据这个节点的权重调度不同数量的 Region。 增加 SQL Plan Cache ,通过增加 SQL 语法解析 Cache 可以让相同逻辑的 SQL 在命中语法解析 Cache 时速度变得更快。 增加更多的并行算子,最大化利用多核 CPU 的能力。 增加物理备份,直接使用 RocksDB 的 SST 文件进行备份,这样可以有比较快的备份恢复速度。 以上就是申砾给大家带来的部分精彩内容,干货满满,小伙伴们还可以观看完整版演讲视频,慢慢 Enjoy~ 也敬请期待我们下一期的内容 :)附:完整 PPT 链接 PingCAP Infra Meetup作为一个基础架构领域的前沿技术公司,PingCAP 希望能为国内真正关注技术本身的 Hackers 打造一个自由分享的平台。自 2016 年 3 月 5 日开始,我们定期在周六的上午举办 Infra Meetup,邀请业内大牛与大家深度探讨基础架构领域的前瞻性技术思考与经验。在这里,我们希望提供一个高水准的前沿技术讨论空间,让大家真正感受到自由的开源精神魅力。 "}, {"url": "https://pingcap.com/weekly/2017-09-04-tidb-weekly/", "title": "Weekly update (August 28 ~ September 03, 2017)", "content": " Weekly update in TiDB Last week, we landed 42 PRs in the TiDB repositories.Added Add JSON into builtin if function. Fixed Fix bugs when doing natural JOIN or JOIN with using clause. Check whether date is zero and returns error when casting int as the time type. Support date time format when parse duration. Fix the issue that SHOW CREATE TABLE COMMENT is not escaped and the issue that FieldType.CompactStr() is escaped. Support empty bit-value literal syntax b''. Fix the OCT() bug when it meets a binary value. Fix float and binary literal bugs. Fix index join key incompatible encoded problem. EvalDuration supports the time format in int. Fix the batch insert bug on duplicate keys. Fix the bug for parsing the UTC_TIME/UTC_TIMESTAMP/CUR_TIME/CURRENT_TIME/CURRENT_TIMESTAMP builtin Improved Make NOW() folded in constant folding stage. Refine the time stamp index selection. Disable auto analyze. Support sig pushdown in mocktikv. Support more types when getting default FLEN and DECIMAL. Refactor the following expressions/builtin-function evaluation framework: GET_LOCK, RELEASE_LOCK FOUND_ROWS, DATABASE, CURRENT_USER, USER, CONNECTION_ID, VERSION STR_TO_DATE BIT_COUNT RLIKE MAKE_SET, QUOTE DATE_FORMAT PERIOD_ADD, PERIOD_DIFF UNIX_TIMESTAMP Weekly update in TiKV Last week, We landed 32 PRs in the TiKV repositories.Added Use delete range to destroy a replica. Add builtin_cast-III for DAG/expression. Support decoding Time from tipb.Expr. Add statistics for coprocessor. Support builtin UnaryMinus* for DAG. Add more math functions for DAG. Implement eval for expression. Support storing weight when balancing data. Adjust the decimal parsing interface for coprocessor Implement coalesce for corprocessor. Implement case_when for DAG. Improved Refactor storeInfo. Speed up reconnecting to PD leader. Use FnvHashMap. Cleanup code for coprocessor. Add more tests for exprssion/builtin_cast. Use RocksDB 5.7.3. Add more write statistics. Make error message more friendly. Refactor replica selector for PD. "}, {"url": "https://pingcap.com/blog/2017-09-01-tidbmeetsjepsen/", "title": "When TiDB Meets Jepsen", "content": " What is Jepsen? How does Jepsen work? DB Client Checker Nemesis Generator Jepsen tests that TiDB goes through The Bank Test The Set Test The Register Test Miscellaneous What is Jepsen? Written by Kyle Kingsbury in Clojure. Jepsen is a test framework for distributed systems verification. Kingsbury has used it to verify the consistency of many famous distributed systems (etcd, ZooKeeper, CockroachDB, etc.) and found multiple bugs in some of these systems. The verification process and reflections on the consistency verification are presented in the author’s blog.How does Jepsen work? Jepsen consists of 6 nodes, one control node and five controlled nodes (by default they’re named n1, n2, n3, n4, and n5). The control node sends all instructions from shell script to SQL statements, to some or all of the controlled nodes. Jepsen provides a few key APIs for distributed systems verification:DB DB encapsulates the download, deployment, startup and shutdown commands of the target system. The core function consists of setup and teardown. When Jepsen is testing TiDB, setup is responsible for downloading binaries and starting PD (Placement Driver), TiKV and TiDB in turn while teardown shutdowns the entire TiDB cluster and deletes logs.Client Client encapsulates the client that each test needs to provide and each client provides two interfaces: setup and invoke. Setup is responsible for connecting with TiDB and invoke includes SQL statements that the client calls to TiDB during the test and the statements are subject to test cases.Checker Checker is used for verifying the history produced by the test, determining whether the test result is as expected. Below shows the format of the history:Nemesis Nemesis introduces failures across the cluster, such as the common network partition, network latency, and node downtime. In TiDB testing, there are the following types of Nemesis: parts: network partition majority-ring: each node sees different majority of other nodes start-stop: send SIGSTOP to some nodes start-kill: send SIGKILL to some nodes After introducing the parts type into the tests, a time-out error occurs when executing some statements as shown below:Generator Generator, the event generator of Jepsen, interweaves the operations of Client with that of Nemesis and generates specific execute statements for the entire test process.Jepsen tests that TiDB goes through TiDB has gone through 3 Jepsen tests: bank, set and register.The Bank Test The Bank Test is used for verifying snapshot isolation. This test simulates various transfers in a bank system and each initial bank system is as follows:1 to 5 represents the account name respectively and 10 means the account balance. The test will randomly generate transfer information:The above diagram means that the amount of 5 is transferred from Account 1 to Account 2. Meanwhile, the test randomly reads the deposit information of all accounts. For example, at some point, the deposit information of an account can be as below:Below is a screenshot in a test:In snapshot isolation, all transfers should ensure that the total amount of all accounts in each moment should be the same. TiDB passed the test even if all kinds of nemesis have been introduced.The Set Test This test concurrently inserts many rows into a table from different nodes and performs a final read of all rows to verify their presence. At the same time, due to the introduction of Nemesis, it is normal that values that return time-out will or will not appear in this table.Below is a screenshot in a test:Once again, TiDB passed the test.The Register Test It is easy to understand this test: create a table and insert a value. We will then regard this value as a register and concurrently execute the read, write and cas (compare and swap) operations to it from different nodes in the test.Later, we use a series of action history produced by Jepsen (as shown above) for Linearizability verification. This algorithm is the core of Jepsen and the reason why Jepsen is well-known in the industry.Miscellaneous Each time when there is an update in the TiDB code, we will internally trigger continuous integration (CI) to execute Jepsen and use Jepsen to guarantee the data consistency of TiDB. If you are interested in distributed test and consistency verification, please join us.TiDB Jepsen: https://github.com/pingcap/jepsen/tree/master/tidb"}, {"url": "https://pingcap.com/blog-cn/tidb-meets-spark/", "title": "When TiDB Meets Spark", "content": " 本文整理自 TiSpark 项目发起人马晓宇在 Strata Data Conference 上分享的《When TiDB Meets Spark》演讲实录。 先介绍我自己,我是 PingCAP 的马晓宇,是 TiDB OLAP 方向的负责人,也是 TiSpark 项目的发起人,主要是做 OLAP 方面的 Feature 和 Product 相关的工作,之前是网易的 Big Data Infra Team Leader,先前的经验差不多都是在 SQL、Hadoop 和所谓大数据相关的一些东西。今天主要会讲的议程大概这么几项。首先稍微介绍一下 TiDB 和 TiKV,因为 TiSpark 这个项目是基于它们的,所以你需要知道一下 TiDB 和 TiKV 分别是什么,才能比较好理解我们做的是什么事情。另外正题是 TiSpark 是什么,然后 TiSpark 的架构,除了 Raw Spark 之外,我们提供了一些什么样的不一样的东西,再然后是 Use Case,最后是项目现在的状态。首先说什么是 TiDB。你可以认为 TiDB 是现在比较火的 Spanner 的一个开源实现。它具备在线水平扩展、分布式 ACID Transaction、HA、Auto failover 等特性,是一个 NewSQL 数据库。然后什么是 TiKV,可能我们今天要说很多次了。TiKV 其实是 TiDB 这个产品底下的数据库存储引擎,更形象,更具体一点,这是一个架构图。大家可以看到,TiDB 做为一个完整的数据库来说,它是这样的一个架构,上层是 DB 层,DB 层是负责做 DB 相关的东西,比如说一部分的 Transaction,SQL 的解析,然后执行 Query Processing 相关的一些东西。底下是 KV 层,存储层。存储层就是存储数据,通过 Raft 协议来做 Replica 的,旁边还有 Placement Driver(简称 PD),如果对 Hadoop比较了解,你可以认为它有点像 NameNode,它会存储每一个 Region 分别存了哪些 Key,然后 Key Range 是什么。当然它在需要的时候也会做一些数据搬迁的调度,以及 Leader 的自动负载均衡等。最后 PD 提供了统一中央授时功能。所有这些组件,都是通过 gRPC 来进行通讯的。我们回到正题来说,什么叫 TiSpark。TiSpark 就是 Spark SQL on TiKV。为什么说是 on TiKV,而不是 on TiDB,因为我们让 Spark SQL 直接跑在分布式存储层上而绕过了 TiDB。这三个组件,TiDB / TiKV / TiSpark 一起,作为一个完整的平台,提供了 HTAP(Hybrid Transactional/Analytical Processing)的功能。再具体一点说 TiSpark 实现了什么:首先是比较复杂的计算下推,然后 Key Range Pruning,支持索引(因为它底下是一个真正的分布式数据库引擎,所以它可以支持索引),然后一部分的 Cost Based Optimization 基于代价的优化。CBO 这里有两部分,一部分是说,因为我们有索引,所以在这种情况下,大家知道会面临一个问题,比如说我有十个不同索引,我现在要选择哪一个索引对应我现在这个查询的谓词条件更有利。选择好的索引,会执行比较快,反之会慢。 另外一个是,刚才大家可能有听华为的 Hu Rong 老师介绍,他们在 Spark 上面做 Join Reorder,对于我们来说,也有类似的东西,需要做 Join Reorder 。这里底下有两个是 Planned 但还没有做。一个是回写,就是说现在 TiSpark 是一个只读的系统。另外我们考虑把常用的一些传统数据库的优化手段,也搬到我们这边来。现在开始说一下整个架构是什么样的。后面会有一个具体的解说,先看一下架构图。在 Spark Driver 上,需要接入 TiSpark 的接口,现在 TiSpark 也支持 JDBC。Worker / Executor 那边也需要一个这样的架构。 整个部署,采用 Spark 外接 JAR 的方式,并没有说需要到我整个把 Spark 部署全都换掉属于我们的版本,只需要提交一个 JAR 包就可以。每个 TiSpark 组件会与 TiKV 进行通讯,Driver 这边会和 Placement Driver 进行通讯,然后这边具体干了什么,后面会解释。在 Spark Driver 这边,因为这个架构上没有 TiDB 什么事,所以说 DB 本身干的事情,我们需要再干一遍,比如说 Schema 存在 TiKV 存储引擎里面,然后里面包括 Tables 的元信息,也就是告诉你数据库里面,分别有什么表,每个表里面分别有什么列,这些东西都属于 Schema 信息。因为我们没有直接连接 TiDB,所以说 Schema 信息需要我们自己去解析。比较重要的功能通过将 Spark SQL 产生的 LogicalPlan,Hook LogicalPlan,然后去做过滤,主要是: 哪一些谓词可以转化成索引相关的访问; 哪一些可以转化成 Key Range 相关的,还有哪一些其它计算可以下推,这些 Plan 节点我们会先过滤处理一遍。然后把 TiKV 可以算的部分推下去,TiKV 算不了的反推回 Spark; 在基于代价的优化部分 Join Reorder 只是在 Plan 状态; Data Location 是通过 Placement Driver 的交互得到的。Java 这边,会跟 Placement Driver 进行交互,说我要知道的是每个(Task)分别要发哪一台机器,然后分别要知晓哪一块的数据。 之后切分 Partition 的过程就稍微简单一点,按照机器分割区间。之后需要做 Encoding / Decoding:因为还是一样的,抛弃了数据库之后,所有的数据从二进制需要还原成有 Schema 的数据。一个大数据块读上来,我怎么切分 Row,每个 Row 怎么样还原成它对应的数据类型,这个就需要自己来做。计算下推,我需要把它下推的 Plan 转化成 Coprocessor 可以理解的信息。然后当作 Coprocessor 的一个请求,发送到 Coprocessor,这也是 TiKV-Client 这边做的两个东西。这些是怎么做的?因为 Spark 提供的两个所谓 Experimental 接口。这两个分别对应的是 Spark Strategy 和 Spark Optimizer,如果做过相关的工作你们可能会知道,你 Hook 了 SQL 引擎的优化器和物理计划生成部分。那两个东西一旦可以改写的话,其实你可以更改数据库的很多很多行为。当然这是有代价的。什么代价?这两个看名字,Experimental Methods,名字提示了什么,也就是在版本和版本之间,比如说 1.6 升到 2.1 不保证里面所有暴露出来的东西都还能工作。可以看到,一个依赖的函数或者类,如果变一些实现,比如说 LogicalPlan 这个类原来是三个参数,现在变成四个参数,那可能就崩了,会有这样的风险。我们是怎么样做规避的呢?这个项目其实是切成两半的,一半是 TiSpark,另一半是重很多的 TiKV-Client 。TiKV Java Client是负责解析对 TiKV 进行读取和数据解析,谓词处理等等,是一个完整的 TiKV 的独立的 Java 实现的接口。也就是说你有 Java 的系统,你需要操作 TiKV 你可以拿 TiKV Client 去做。底下项目就非常薄,你可以说是主体,就是真的叫 TiSpark 的这个项目,其实也就千多行代码。做的事情就是利用刚才说的两个 Hook 点把 Spark 的 LogicalPlan 导出来,我们自己做一次再变换之后,把剩下的东西交还给 Spark 来做的。这一层非常薄,所以我们不会太担心每个大版本升级的时候,我们需要做很多很多事情,去维护兼容性。刚才说的有几种可能比较抽象,现在来一个具体的例子,具体看这个东西怎么 Work,可以看一个具体的例子。这是一个查询,根据所给的学号和学院等条件计算学生平均值。这张表上,有两个索引,一个索引是主键索引,另外一个索引是在 Secondary Index ,建立在 School 上。lottery 是一个用户自定义函数,并不在 TiDB 和 TiKV 的支持范围之内。首先是说谓词怎么样被处理,这里有几种不同的谓词,比如关于学生 ID 的:大于等于 8000,小于 10100,以及有两个单独学号;然后是一个 school = ‘engineer’,还有一个 UDF 叫 lottery,单独挑选一些运气不好的学生。第一步,整个处理,假设说我们索引选中的是在 studentID 上的聚簇索引。studentID 相关的谓词可以转化为区间 [8000, 10100), 10323, 10327。然后是 school=‘engineer’,因为它没有被任何索引选择,所以是一个独立的条件。这两种不同的条件,一个是跟聚簇索引相关的,可以转化成 Key Range,另外一个是跟索引没有关系的独立的谓词。两者会经过不同的处理,聚簇索引相关的谓词转化成 Key Range,独立的谓词 school=‘engineer’ 会变成 Coprocessor 的 Reqeust,然后进行 gRPC 的编码,最后把请求发过去。聚簇索引相关谓词转化的 Key Range 会通过查询 Placement Driver 取得 Region 的分布信息,进行相应的区间切割。假设说有三个 Region。Region 1 是 [0, 5000),是一个闭开区间,然后 Region 2 是 [5000, 10000)。接着 Region 3 是 [10000, 15000)。对应我们上面的 Request 下推的区间信息你可以看到,谓词区间对应到两个 Region:Region 2 和 Region 3,Region1 的数据根本不用碰,Region 2 的数据会被切成 [8000, 10000),因为对应的数据区间只有 [8000, 10000)。然后剩下的 [10000, 10100) 会单独放到 Region 3 上面,剩下的就是编码 school=‘engineering’ 对应的 Coprocessor Request。最后将编码完成的请求发送到对应的 Region。 上面就是一个谓词处理的逻辑。多个索引是怎么选择的呢?是通过统计信息。TiDB 本身是有收集统计信息的, TiSpark 现在正在实现统计信息处理的功能。TiDB 的统计信息是一个等高直方图。例如我们刚才说的两个索引,索引一在 studentId 上,索引二是在 school 上。查询用到了 studentId 和 school 这两个列相关的条件,配合索引,去等高直方图进行估算,直方图可以告诉你,经过谓词过滤大概会有多少条记录返回。假设说使用第一个索引能返回的记录是 1000 条,使用第二个能返回的记录是 800 条,看起来说应该选择 800 条的索引,因为他的选择度可能更好一点。但是实际上,因为聚簇索引访问代价会比较低,因为一次索引访问就能取到数据而 Secondary Index 则需要访问两次才能取到数据,所以实际上,反而可能 1000 条的聚簇索引访问是更好的一个选择。这个只是一个例子,并不是说永远是聚簇索引更好。 然后还有两个优化,一个优化是覆盖索引,也就是说索引是可以建多列的,这个索引不一定是只有 school 这个列,我可以把一个表里面很多列都建成索引,这样有一些查询可以直接用索引本身的信息计算,而不需要回表读取就可以完成。比如,select count(*) from student where school=’engineer’整个一条查询就只用到 school 这个列,如果我的索引键就是 school,此外并不需要其他东西。所以我只要读到索引之后,我就可以得到 count(*) 是多少。类似于这样的覆盖索引的东西,也有优化。TiSpark 比较特殊的是,下层接入的是一个完整的数据库而数据库把控了数据入口,我每个 Update 每个 Insert 都可以看到。这给我们带来什么方便,就是说每个更新带来的历史数据变更可以主动收集。基于代价优化的其他一些功能例如 Join Reorder 还只是计划中,现在并没有实现。刚才有跟 Hu Rong 老师有讨论,暂时 Spark 2.2 所做的 CBO,并不能接入一个外部的统计信息,我们暂时还没想好,这块应该这么样接。 接下来是聚合下推,聚合下推可能稍微特殊一点,因为一般来说,Spark 下面的数据引擎,就是说现在 Spark 的 Data Source API 并不会做聚合下推这种事情。还是刚才的 SQL 查询:这个例子稍微有一点特殊,因为他是计算平均值,为什么特殊,因为没有办法直接在 TiKV 做 AVG 平均值计算,然后直接在 Spark 再做直接聚合计算,因此这种情况会有一个改写,将 AVG 拆解成 SUM 和 COUNT,然后会把他们分别下推到 Coprocessor,最后在 Spark 继续做聚合计算。TiSpark 项目除了改写 Plan 之外,还要负责结合做类型转换和 Schema 转换。因为 TiKV 这个项目,本身并不是为了 TiSpark 来设计的,所以整个 Schema 和类型转化的规则都是不一样的。Coprocessor 部分聚合 (Partial Aggregation) 的结果,数据的类型和 Spark 是完全不一样的,因此这边还会做一次 Schema 的桥接。之后其他的就是跟前面一样了,会把请求发到对应的 Region。现在来讲 TiSpark 和 TiDB/TiKV,因为是整个一个产品的不同组件,所以说 TiSpark 的存储,也就是 TiDB 的存储,TiKV 会针对 TiSpark 这个项目来做一些 OLAP 相关定的 Feature。比如说在 OLTP 的模式下我们使用的是 SI 隔离级别,就是 Snapshot Isolation。在 OLTP 这边,需要面对一个 Lock Resolving 问题和开销。如果要看的话可以看一下 Percolator Transaction 的论文。为了避免 Lock Resolving 带来的开销,我们使用了一个 Read Committed 的模式。如果需要的话,后面再加 SI 也并不是非常难,只是现在这个版本并不会这样做。之后还有 OLTP 和 OLAP 混跑,大家可能会觉得有很大问题,就是资源怎么样隔离。现在资源隔离是这样的:对于比较大的查询,在 KV 那层会倾向于用更少的线程。当然是说你如果是在空跑,这台机器上没有其他人在跑的话,其实还是会用所有的资源,但如果你有跟其他 OLTP 查询对比的话,你会发现虽然我是请求了很多但你可能未必会拿到很多。用户也可以手动来降低优先级,例如,我明天就要给老板出一个报表,一个小时候之后就要拿结果,我可以手动提高一个分级。 所有刚刚讲的这些,基本上都是 TiSpark 本身提供了一些什么东西。现在说在一个类似于 Big Picture 的语境之下,怎么样去看这个项目。除了 Raw Spark 的功能之外,我们提供了什么多的东西。最不一样的地方就是 SQL-On-Hadoop,基本上来说,你可以认为它并不控制存储,存储并不在你这里,你灌的数据,可能是通过 Flume/Kafka 某一个 Sink 灌进来,或通过 Sqoop 导过来,整个不管是 Hive,还是 Spark SQL,他并不知道数据进来。对于一个数据库来说,每一条数据插入,全是经过数据库本身的,所以每一条数据怎么样进来,怎么样存,整个这个产品是可以知道的。另外就是说相对于 SQL-On-Hadoop,我们做一个数据库,肯定会提供 Update 和 Delete 这是不用多说的。因为 TiKV 本身会提供一些额外计算的功能,所以我们可以把一些复杂的查询进行下推。现在只是说了两个,一个是谓词相关的 下推,还有一个是刚才说的聚合下推,其他还有 Order,Limit 这些东西,其实也可以往下放。接下来就属于脑洞阶段了,除了刚才说的已经“高瞻远瞩”的东西之外,脑洞一下,接下来还可以做一些什么(当然现在还没有做),这个已经是 GA 还要再往后的东西了。首先说存储,TiKV 的存储是可以给你提供一个全局有序,这可能是跟很多的 SQL-On-Hadoop 的存储是不一样的。Global Order 有什么好处,你可以做 Merge Join,一个 Map Stage 可以做完,而不是要做 Shuffle 和 Sort。Index lookup join 是一个可以尝试去做的。Improved CBO,我们数据库团队现在正在开发实时收集统计信息。 其他一些传统数据库才可能的优化,我们也可以尝试。这里就不展开多说了。 整个系统,一个展望就是 Spark SQL 下层接数据库存储引擎 TiKV ,我可以希望说 Big Data 的那些平台是不是可以和传统的数据库就合在一起。因为本身 TiDB 加 TiKV 就是一个分布式的数据库。然后可以做 Online Transaction,类似于像 Spanner 提供的那些功能之外,我们加上 Spark 之后,是不是可以把一些 Spark 相关的 Workload 也搬上来。然后是 Use Case:首先一个平台,可以做两种不同的 Workload,Analytical 或者 Transactional 都可以在同一个平台上支持,最大的好处你可以想象:没有 ETL。比如说我现在有一个数据库,我可能通 Sqoop 每小时来同步一次,但是这样有一个延迟。而使用 TiSpark 的话,你查到的数据就是你刚才 Transaction 落地的数据而没有延迟。另外整个东西加在一起的话,就是有一个好处:只需要一套系统。要做数据仓库,或者做一些离线的分析,现在我并不需要把数据从一个平台导入数据分析平台。现在只要一套系统就可以,这样能降低你的维护成本。另外一个延伸的典型用法是,你可以用 TiDB 作为将多个数据库同步到一起的解决方案。这个方案可以实时接入变更记录,比如 Binlog,实时同步到 TiDB,再使用 TiSpark 做数据分析,也可以用它将 ETL 之后的结果写到 HDFS 数仓进行归档整理。需要说明的是,由于 TiDB / TiKV 整体是偏重 OLTP,暂时使用的是行存且有一定的事务和版本开销,因此批量读的速度会比 HDFS + 列存如 Parquet 要慢,并不是一个直接替代原本 Hadoop 上基于 Spark SQL / Hive 或者 Impala 这些的数仓解决方案。但是对于大数据场景下,如果你需要一个可变数据的存储,或者需要比较严格的一致性,那么它是一个合适的平台。后续我们将写一篇文章详细介绍 TiSpark 的 Use Case,对 TiSpark 感兴趣的小伙伴,欢迎发邮件到 info@pingcap.com 与 …"}, {"url": "https://pingcap.com/weekly/2017-08-28-tidb-weekly/", "title": "Weekly update (August 21 ~ August 27, 2017)", "content": " Weekly update in TiDB Last week, we landed 55 PRs in the TiDB repositories.Added Support the ‘SHOW PLUGINS’ syntax with dummy implementation. Add a system variable to split to-be-deleted data into batches autmatically. Add the date literal. Add the framework of the X protocol, and commond line arguments. Fixed Fix a panic when the set statement meets a subquery. Set charset and collation for the union’s result. Fix show column comment, show create table auto-increment. Fix the bug in Date comparison. Fix the bug in index selection. Rewrite the index join plan generation to correct wrong index selection. Avoid ‘binary BINARY’ for a special field type. Correct overflow check on the MINUS function. Fix a bug when casting JSON to other types. Concatenates string literals which placed each other. Fix an issue that the flags of the ‘IFNULL’ Builtin function result is not consistent with MySQL. Improved Enlarge the batch size from 128M to 256M to reduce the network round-trip. Suport coalesce pushdown. Make auto analyze more conservative. Support isnull pushdown. Implement the MVCCStore interface using the leveldb backend. Calculate generated columns in CRUD. Refactor the following expression/builtin-function evaluation framework: TIMESTAMP DAYNAME DATE UTC_TIME MONTHNAME WEEKDAY, FROM_DAYS, QURTER LAST_DAY DAYOFWEEK, DAYOFMONTH, DAYOFYEAR FIND_IN_SET DATEDIFF CURDATE, SYSDATE, YEARWEEK YEAR, MONTH WEEK, WEEKOFYEAR NOW, UTC_TIMESTAMP, UTC_DATE TIMESTAMPDIFF COALESCE New Contributor (Thanks!) David Ding xiaojian Cai bailaohe Weekly update in TiKV Last week, We landed 21 PRs in the TiKV repositories.Added Use dedicated Rocksdb instance to store Raft log. Add builtin_cast-II for DAG/expression. Add builtin scalar function operator for DAG. Add arithmetic operations for DAG. Add builtin conditions for DAG. Add more RocksDB metrics. Support negative operator for decimal. Fixed Fix a data race for PD. Fix a heartbeat stream bug for PD. Fix a bug with reverse scan. Improved Refactor the Coprocessor thread pool to pass contexts. Improve tests. Add timeout for RPC calls. Remove timeout for streaming calls. Make max tasks configurable for the Coprocessor. Move the heartbeat approximate size to PD worker. "}, {"url": "https://pingcap.com/meetup/meetup-2017-08-25/", "title": "【Infra Meetup No.54】数据库计算存储分离架构分析", "content": " 上周六,PingCAP Infra Meetup 第 54 期,我们邀请到了知乎大 V 李凯(知乎 ID:郁白)为大家分享了《数据库计算存储分离架构分析》。在活动现场,郁白老师跟小伙伴们有一番深度的交流与思想碰撞。长话短说,小编带你一起回顾精彩现场。 精彩视频 视频 | Infra Meetup No.54:数据库计算存储分离架构分析精彩现场 PingCAP Infra Meetup 第 54 期的活动现场十分火爆,活动签到时间未开始,小伙伴们就早早来到现场占位置,我想说早来的小伙伴们还是很明智的。因为……后续到场的小伙伴只能酱婶儿滴扎堆在门口竖起耳朵听了,这场活动简直是一场郁白大神与粉丝的见面会。说了这么多,先上一张郁白老师的图吧~ 🙂技术干货节选 大数据下公有云面临的 5 个挑战 谈到存储架构分离,为什么现在会有 Aurora 架构?包括前一阵阿里的 PolarDB 推出来以后,他们也在分析为什么要做这个东西。郁白老师认为单就公有云来说,现在云数据面临的挑战有以下 5 个: 跨 AZ 的可用性与数据安全性。 现在都提多 AZ 部署,亚马逊在全球有 40 多个 AZ, 16 个 Region,基本上每一个 Region 之内的那些关键服务都是跨 3 个 AZ。你要考虑整个 AZ 意外宕机或者计划内维护要怎么处理,数据迁移恢复速度怎么样。以传统的 MySQL 为例,比如说一个机器坏了,可能这个机器上存了几十 T、上百 T 的数据,那么即使在万兆网卡的情况下,也要拷个几分钟或者几十分钟都有可能。那么有没有可能加快这个速度。 还有一个就是服务恢复的速度。可能大家广为诟病就是基于 MySQL Binlog 复制。在主机压力非常大的情况下,是有可能在切换到备机以后,这个备机恢复可能需要几分钟甚至几十分钟。关键因素是回放 Binlog 的效率,MySQL 即使最新版本也只能做到 Group Commit 内的并发回放。这是数据库 RTO 指标,能不能在秒级、分钟级把这个服务恢复起来,这是一个在设计系统的时候要考虑的关键问题。 读写分离与弹性扩展。 一般来说我们讲云上数据库基本上都是集中化的,一写多读的,那这里会涉及到读写分离,把主库上一致性要求不高的读流量分给备库,这种情况下读写分离的备库能不能弹性扩展?我们知道 MySQL 可以通过 Binlog 复制来扩展备机,但是扩展的过程中就意味着复制一份完整数据,就像我们刚才提到的数据恢复一样,他要把整个数据全部复制过去然后把 Binlog 接上,这个时间可能你要真做的话几十分钟就过去了。如果说你的业务真撑不住说我赶快要加备机,那这个东西怎么去解决? 资源的按需分配。 这点其实云计算上的云数据库一定程度上已经做到了,当然有些可能不一样,比如说有硬件独享的数据库就很难做到按需分配。像阿里可能会把 EBS 接到它的数据库虚拟机上,这样的话其实你接上了弹性化存储以后也基本上做到一个弹性的分配,要 1G 给 1G,再要 1G 再给 1G,不说一开始就把资源分配了,这是云上的一个弹性的东西。 高性能。 现在大家都要看跑分,除了跑分,还要看跑实际业务的时候到底行不行,有没有办法去优化。 生态兼容性。 比如说为什么 TiDB 一定要做 MySQL 的兼容?我觉得可能也是考虑这一点,现在开源领域最强的生态可能还是 MySQL,开源的数据库如果不做 MySQL 兼容,别人可能不一定会来用。 从以上这几点出发的话,我们就可以考虑一个云数据库到底怎么去发展。AWS Aurora 的架构特点及优势 郁白老师选择这几个具有代表性的数据库存储与计算架构做了重点讲解,他介绍到定义数据库服务器集群的架构决策的关键点在于集群共享发生的程度,它定义协调动作发生在什么层以及哪个层( PE 计算层和 SE 存储层 )将被复制或者共享。这不仅确定了系统在可扩展性和灵活性上的权衡,而且关系到每一种架构在现成的数据库服务器上的适用性。AWS Aurora 计算存储分离架构的优势主要体现在高可用、数据安全、弹性部署、性能方面。在介绍这个环节时,现场小伙伴提问不断,讨论非常激烈,强烈感受到思想碰撞在一起擦除的火花,郁白老师也针对大家的问题做了深度交流。计算存储分离架构的 4 个关键技术 郁白老师总结出计算存储分离架构的四个关键技术与大家一起探讨,接下来将一一解析这些技术的关键点。关键技术一:跨 AZ 协同复制关键技术二:Cache Coherence 与一致性读关键技术三:统一 Log Structured Storage关键技术四:数据分片存储以上就是郁白老师带给大家的部分精彩分享,干货满满,特别感谢郁白老师精心准备的内容,意犹未尽的小伙伴们可以观看完整版演讲视频,慢慢 Enjoy~ 也敬请期待我们下一期的内容 :)附:完整 PPT 链接 PingCAP Infra Meetup作为一个基础架构领域的前沿技术公司,PingCAP 希望能为国内真正关注技术本身的 Hackers 打造一个自由分享的平台。自 2016 年 3 月 5 日开始,我们定期在周六的上午举办 Infra Meetup,邀请业内大牛与大家深度探讨基础架构领域的前瞻性技术思考与经验。在这里,我们希望提供一个高水准的前沿技术讨论空间,让大家真正感受到自由的开源精神魅力。 "}, {"url": "https://pingcap.com/blog-cn/linearizability/", "title": "Linearizability 一致性验证", "content": " 上篇文章介绍了 TiDB 如何使用 Jepsen 来进行一致性验证,并且介绍了具体的测试案例,但是并没有对 Jepsen 背后的一致性验证算法做过多介绍。这篇文章将会深入 Jepsen 的核心库 knossos,介绍 knossos 库所涉及的 Linearizability(线性化)一致性验证算法。Linearizability 一致性模型 什么是一致性模型? 一致性模型确定了编写系统的程序员与系统之间的某种协议,如果程序员遵守了这种协议,那么这个系统就能提供某种一致性。常见的一致性模型有: Strict Consistency Linearizability (Atomic Consistency) Sequential Consistency Casual Consistency Serializability …… 需要注意的是这里的系统指并发系统,分布式系统只是其中的一类。什么是 Linearizability? 首先我们需要引入*历史*(history)的概念,*历史*是并发系统中由 invocation 事件和 response 事件组成的有限序列。 invocation: <x op(args*) A>,x 表示被执行对象的名称;op 表示操作名称,如读和写;args* 表示一系列参数值;A 表示进程的名称 response:<x term(res*) A>,term 表示结束(termination)状态;res* 表示一系列结果值 如果 invocation 和 response 的 x(对象)和 A(进程)相同,那么我们认为它们是对应操作,并且 complete(H)表示历史中的最多成对操作 当我们的历史 H 满足以下条件时我们把它称为*顺序化*(sequential)历史: H 中的第一个事件是 invocation 除了可能的最后一个事件外,每个 invocation 事件都紧跟着对应[^对应意味着对象和进程相同]的 response 事件;每个 response 事件都紧跟着对应的 invocation 事件 H|A 代表只含有进程A操作的子历史,H|x 代表只含有对象x操作的子历史 定义well-formed:如果每个进程子历史 H|A 都是顺序化的,那么这个历史 H 就是 well-formed。 如果一个*历史*不是顺序化的话那么就是并发的。历史 H 在操作上引出非自反的偏序关系$<_H$$e_0 <_H e_1$ if $res(e_0)$ precedes $inv(e_1)$ in $H$这里的 res 和 inv 分别对应 response 和 invocation。当历史 H 可以通过增加>=0个response 事件被延长时成为 H’ 并且满足以下两个条件时,则这个*历史*是线性化(linearizable)的。 L1: complete(H’) 与某个合法的顺序化历史 S 相等 L2: $<_H ⊆ <_S$ complete(H’)表示进程以完整的操作进行交互,L2 表示如果 op1 在 H 中先于 op2 存在(注意这里的先于强调实时发生的顺序 real-time order),那么在 S 中也是这样。我们把 S 称为 H 的线性化点(linearization)。下面我们通过 3 个小例子来解释一下以上 2 个条件。q 代表 FIFO 队列,A、B 代表两个进程 q Enq(x) A q Deq() B q Ok(x) B 满足 linearizable,虽然 Enq(x)并没有返回 Ok,但是我们可以通过增加这条返回语句使得上述语句与某个合法的顺序化历史相等 q Enq(x) A q Ok() A q Enq(y) B q Ok() B q Deq() A q Ok(y) A 如果满足 linearizable 那必然 Enq(x)先于 Enq(y),但是 Deq()是得到的却是 y,所以违反了 L2,因此这段历史不是线性化的 q Enq(y) A q Ok() A q Deq() A q Deq() B q Ok(y) A q Ok(y) B 不满足 linearizable 因为 Enq(y)只执行了一次,却被 Deq()了两次,不能与任何合法的顺序化历史相对应 Linearizability 的性质 局部性(Locality),当且仅当 H 中每个对象 x 都是线性化的,才能保证H是线性化的 非阻塞(Nonblocking),invocation 事件不用等待对应的 response 事件 验证 Linearizability 正确(correctness)的定义 一段历史 H 由两种对象组成,representation(REP)和 abstract(ABS)。abstract 是被实现的类型,而 representation 类型则是用于实现 ABS 的类型。这两种对象在以下条件下进行交互: 子历史 H|REP和H|ABS是well-formed 对于每个进程 P,在子历史 H|P 中,每一个 rep 操作都被 abs 操作所包含 对于某个实现中的所有历史 H 来说,如果 H|ABS 是线性化的,那么这个实现就是正确的。REP 值的子集中的合法表现由表达不变性(representation invariant)所表示:I: REP-> BOOL,一个合法表现的含义由抽象函数(abstract function)所表示:A: REP->ABS。对于一个正确的实现 p 来说,存在一个表达不变性 I,以及一个抽象函数 A,并且无论何时 p 从一个合法的表达值 r 到达另一个表达值 r’,抽象操作 a 把抽象值 A®变成 A(r’)。我们从最简单的队列(FIFO queue)入手。struct queue { int back; element *elements; }; bool Enq(queue *q, element x) { int i = INC(&q->back); // 原子自增并返回之前的值 STORE(&q->elements[i], x); // 假设内存足够 return true; } element Deq(queue *q) { while (1) { int end = READ(&q->back); // 原子读取 for (int i = 1; i < end; ++i) { element x = CAS(&q->elements[i], NULL); // 返回 CAS 之前的值 if (x != NULL) return x; } } } Enq 和 Deq 可以看做是 abstract operation,而 Enq 和 Deq 中的每条语句可以看做是 representation operation。对线性化的历史的验证可以被转换为对顺序化历史的验证,对于给定的线性化历史,我们把最终线性化点的对象的值称为线性值。因为给定的历史可能有超过一个线性化点,所以这个对象可能会有多个线性值。我们用 Lin(H) 表示所有线性值的集合,可以把它们看作是系统外部的观察者所看到的值。对于以下几个队列操作,对应的线性值分别有以下几种。 History Linearized values {[]} Enq(x) A {[], [x]} Enq(y) B {[], [x], [y], [x,y], [y,x]} Ok() B {[y], [x,y], [y,x]} Ok() A {[x,y], [y,x]} Deq() C {[x], [y], [x,y], [y,x]} Ok(x) C {[y]} 为了证明正确性,我们需要保证:For all $r$ in $Lin(H|REP)$, $I®$ holds and $A® ⊆ Lin(H|ABS)$其中 H|REP 和 H|ABS 都是线性化的,r 代表 H|REP 的线性值,并且$I® = (r.back ≥ 1)$ & $(∀ i. i ≥ r.back -> r.elements[i] = null)$ & $(lbound(r.elements) = 1)$其中 lbound 是最小的数组索引(队列从 1 开始)$A®$ = {$q | elements® = elements(q)$ & $<_r ⊆ <_q$}其中偏序关系$<_r$表示如果被插入元素 x 的赋值操作先于 y 的自增操作,则 $x <_r y,<_q$ 代表队列 q 的全序关系。换句话说,队列的表现值(representation value)就是队列中的元素,这些元素的排列顺序与 Enq 操作的顺序一致。下面这张图可以帮助你很好地理解上述公式的意思。第二列是线性化的表现值(linearized representation values),第三列是线性化的抽象值(linearized abstract values),可以看到每一行中第二列都是第三列的子集。Wing & Gong 线性化算法 介绍完了如何证明 linearizability,下面我们可以继续深入到 knossos 使用的两个核心算法之一——Wing & Gong Linearibility 算法(WGL)。 WGL 算法:对于给定的某个数据类型T,它的并发实现为 ConcObj,而它的顺序化要求为 SeqObj。对于给定的历史 H,我们在保证 H 的实时顺序 $<_H$ 的情况下尝试 H 的每一系列可能的顺序化操作,然后检查每个顺序化历史 $H_S$ 在 SeqObj 上执行时是否是线性化的。如果 H 的每一种可能都失败了,那么这个历史就不是线性化的。 我们定义历史是由一系列事件组成的:typedef struct ev { char item; char op; struct ev *match, *prev, *next; } event; 其中 iterm 是操作 op 的参数,name 是进行操作的进程的名字,prev 和 next 分别表示上一个和下一个事件,match 指向其对应的返回(res)事件。另外我们还需要区域以及 lift(unlift)这个概念。 区域(Section):由触发(inv)事件,对应的返回事件,以及它们中间包含的所有事件。 虚线同时可以看作是也是 match 指针。 lift:将某对操作从历史中移出unlift:将移出的某对操作放回 这个算法的核心是一个搜索(Search)函数,如果历史H是线性化的,那么那么他返回一个线性化点(即顺序化历史 S)。搜索使用一个栈来保存历史中已经线性化的部分,这个栈及栈中的元素是这样定义的:typedef struct { event *pi, *pr, *inv, *resp; char item, op, result; } elt_stack; typedef struct { elt_stack value[STACK_LENGTH]; int in; } stacktype; 其中 pi 和 pr 分别表示子历史中第一个没有被检查的区域;inv 和 resp 表示子历史中第一对操作;item、op 和 result 记录这对操作的信息。一个完整的搜索函数是这样的: 初始化栈 通过 current 操作的 pi 和 pr 定位当前的区域,否则返回线性化点 从当前区域开始,选择一个操作并且将它的信息存储在 current 中 对选择的操作进行顺序化模拟,调用 op 5. - A:如果 op 返回真,意味着目前被检查的所有操作能够组成线性化的子历史,所以把这个操作推入栈中,并将这个操作从历史中移出,然后回到 2 - B: ① 如果当前区域内还有一些未被选择的触发(inv)事件没有排在任何返回(res)事件之后,那么选择一个然后回到 4;② 当前区域的所有操作已经被尝试但是失败了,所以我们需要将操作出栈然后尝试其他的顺序,如果栈是空的,那么意味着历史不是线性化的,函数返回;否则,将顶层元素出栈,这个元素包含了之前区域的所有信息,以及被选择的操作,然后 undo 之前的 op,unlift 这个操作,最后,设置 current 为之前区域的指针,然后回到 5B① 注:4 中 op 操作取决于具体模型,如果被测试的是一个寄存器的话,那 op 可以是 read、write 和 cas,如果 read 和 cas 时读到的值和预期值不一致,则操作无法进行。 这就是整个 WGL 算法。这个算法很简单也很好理解,但是有两个明显的缺点: 一旦操作数量上升,整个算法会运行地很缓慢,因为可能会出现涉及大量回溯的操作 这个算法只能验证是否线性化,一旦线性化不成立,并不能给出具体违反线性化的出错点 对此 knossos 库的第二个算法使用了 WGL 算法的改进版本,与 WGL 中的栈存放操作信息不同的是它使用了树遍历和图搜索两种方法来使算法更高效,同时存在“记忆”机制来避免对相同的操作进行重复验证,并且如果所验证的历史不满足一致性,会给出具体出错的点。篇幅有限,如果你对这个算法感兴趣的话,文末有链接。最后的思考 这篇文章介绍了什么是 Linearizability、Linearizability 正确性的验证及其算法。这些算法在分布式系统中的应用只是一个很小的方面,算法本身是独立的,它只需要一个历史 H,至于这个历史是随机生成的还是某个应用在实际中产生的并不重要。你可以使用这些算法对任何并发系统进行验证,小到一个无锁队列、Set,大到某个分布式系统。TiDB 作为一个分布式数据库却能被抽象化为一个队列、寄存器来被用作测试这本身就是一个很有意思的地方,同时也很好地展现了这些算法自身的魅力。参考 Consistency ModelKnossosSequential ConsistencyLinearizabilityLinearizability versus SerializabilityWGL算法Testing for Linearizability"}, {"url": "https://pingcap.com/weekly/2017-08-21-tidb-weekly/", "title": "Weekly update (August 14 ~ August 20, 2017)", "content": " Weekly update in TiDB Last week, we landed 57 PRs in the TiDB repositories.Added Add the version information in diagnostic messages. Add the Close() method to RawKVClient. Add JSON in fieldTypeMergeRules. Add support to MySQL connector 6.06. Add Git branch name in tidb_version() and the starting log. Add the auto analyze feature for tables. Fixed DDL uses the correct method to check whether the context is done. Close the PD client in TiKV store and raw KV to prevent connection leak. Restore WrapCastAsReal and WrapCastAsDecimal if the argument is ClassInt. Notify the fetching goroutines to exit when IndexLookupExecutor closes. Fix the error in the return type for the ceil/floor function. Start GCWorker after the bootstrapping is finished. Add a limit to the number of multi-column index key parts. Disable the mysql.ClientMultiStatements capability Allow username to contain ‘@’. Improved Handle canceled error by Grpc remote. Remove all the stuff about the backgroud DDL worker. Use more effective terror comparison method. Union scan reuses PK when it is a handle. Use FieldType.Decimal to control the decimal length of double values to be shown in client. Support time constant pushdown in mocktikv. Return the unsupported error in the type infer stage. Refactor the following expression/builtin-function evaluation framework: CRC32 TIME HOUR, MINUTE, SECOND, MICROSECOND RAND, POW, SIGN, SQRT DIV TRUNCATE ANY_VALUE DNF NULLIF TIMESTAMPADD TO_SECONDS TO_DAYS CASE RADIANS OCT IS_IPV4, IS_IPV6, IS_IPV4_COMPAT, IS_IPV4_MAPP INET_ATON, INET_NTOA, INET6_ATON, INET6_NTOA TIME_FORMAT Weekly update in TiKV Last week, We landed 33 PRs in the TiKV repositories.Added Add hex/escaped converting for tikv-ctl. Implement the basic structure of builtin_cast and some functions for DAG. Add compare to new expression calculate framework. Support leader resignation for PD. Add Git branch information to the starting log. Support the mysql-time constant. Add Constant and Column for coprocessor. Add RocksDB event metrics. Fixed Declare config for each CF explicitly. Use millisecond resolution for the coarse Instant. Only collect properties for DBEntryType::Put. Allow coarse error. Improved Check approximate size before split check. Get snapshot in batches for coprocessor. Get snapshot in batches for endpoint. Use separated thread to flush metrics. Use histogram coarse timer. Upgrade Rocksdb to 5.6.2. Deprecate v1 snapshot. Reorganize the server start up process for PD. Broadcast when there is pending conf change. "}, {"url": "https://pingcap.com/blog/2017-08-15-multi-raft/", "title": "The Design and Implementation of Multi-raft", "content": " (Email: tl@pingcap.com) Placement Driver Raftstore Region RocksDB / Keys Prefix Peer Storage Peer Multi-raft Summary Placement Driver Placement Driver (PD), the global central controller of TiKV, stores the metadata information of the entire TiKV cluster, generates Global IDs, and is responsible for the scheduling of TiKV and the global TSO time service.PD is a critical central node. With the integration of etcd, it automatically supports the distributed scaling and failover as well as solves the problem of single point of failure. We will write another article to thoroughly introduce PD.In TiKV, the interaction with PD is placed in the pd directory. You can interact with PD with your self-defined RPC and the protocol is quite simple. In pd/mod.rs, we provide the Client trait to interact with PD and have implemented the RPC Client.The Client trait of PD is easy to understand, most of which are the set/get operations towards the metadata information of the cluster. But you need to pay extra attention to the operations below:bootstrap_cluster: When we start a TiKV service, we should firstly find out whether the TiKV cluster has been bootstrapped through is_cluster_bootstrapped. If not, then create the first region on this TiKV service.region_heartbeat: Region reports its related information to PD regularly for the subsequent scheduling. For example, if the number of peers reported to PD is smaller than the predefined number of replica, then PD adds a new Peer replica to this Region.store_heartbeat: Store reports its related information to PD regularly for the subsequent scheduling. For example, Store informs PD of the current disk size and the free space. If PD considers it inadequate, it will not migrate other Peers to this Store.ask_split/report_split: When a Region needs to split, it will inform PD through ask_split and PD then generates the ID of the newly-split Region. After split successfully, Region informs PD through report_split.By the way, we will make PD support gRPC protocol in the future, so the ClientAPI will have some changes.Back to the topRaftstore The goal of TiKV is to support 100 TB+ data and it is impossible for one Raft group to make it, we need to use multiple Raft groups, which is Multi-raft. In TiKV, the implementation of Multi-raft is completed in Raftstore and you can find the code in the raftstore/store directory.Region To support Multi-raft, we perform data sharding and make each Raft store a portion of data.Hash and Range are commonly used for data sharding. TiKV uses Range and the main reason is that Range can better aggregate keys with the same prefix, which is convenient for operations like scan. Besides, Range outperforms in split/merge than Hash. Usually, it only involves metadata modification and there is no need to move data around.The problem of Range is that a Region may probably become a performance hotspot due to frequent operations. But we can use PD to schedule these Regions onto better machines.To sum up, we use Range for data sharding in TiKV and split them into multiple Raft Groups, each of which is called a Region.Below is the protocol definition of Region’s protbuf:message RegionEpoch { optional uint64 conf_ver = 1 [(gogoproto.nullable) = false]; optional uint64 version = 2 [(gogoproto.nullable) = false]; } message Region { optional uint64 id = 1 [(gogoproto.nullable) = false]; optional bytes start_key = 2; optional bytes end_key = 3; optional RegionEpoch region_epoch = 4; repeated Peer peers = 5; } message Peer { optional uint64 id = 1 [(gogoproto.nullable) = false]; optional uint64 store_id = 2 [(gogoproto.nullable) = false]; } region_epoch: When a Region adds or deletes Peer or splits, we think that this Region’s epoch has changed. RegionEpoch’s conf_ver increases during ConfChange while version increases during split/merge.id: Region’s only indication and PD allocates it in a globally unique way.start_key, end_key: Stand for the range of this Region [start_key, end_key). To the very first region, start and end key are both empty, and TiKV handles it in a special way internally.peers: The node information included in the current Region. To a Raft Group, we usually have three replicas, each of which is a Peer. Peer’s id is also globally allocated by PD and store_id indicates the Store of this Peer.Back to the topRocksDB / Keys Prefix In terms of actual data storage, whether it’s Raft Metadata, Log or the data in State Machine, we store them inside a RocksDB instance. More information about RocksDB, please refer tohttps://github.com/facebook/rocksdb.We use different prefixes to differentiate data of Raft and State Machine. For detailed information, please refer to raftstore/store/keys.rs. As for the actual data of State Machine, we add “z” as the prefix and for other metadata stored locally, including Raft, we use the 0x01 prefix.I want to highlight the Key format of some important metadata and I’ll skip the first 0x01 prefix. 0x01: To store StoreIdent. Before initializing this Store, we store information like its Cluster ID and Store ID into this key. 0x02: To store some information of Raft. 0x02 is followed by the ID of this Raft Region (8-byte big endian) and a Suffix to identify different subtypes. 0x01: Used to store Raft Log, followed by Log Index (8-byte big endian) 0x02: Used to store RaftLocalState 0x03: Used to store RaftApplyState 0x03:Used to store some local metadata of Region. 0x03 is followed by the Raft Region ID and a Suffix to represent different subtypes. 0x01: Used to store RegionLocalState Types mentioned above are defined in protobuf:message RaftLocalState { eraftpb.HardState hard_state = 1; uint64 last_index = 2; } message RaftApplyState { uint64 applied_index = 1; RaftTruncatedState truncated_state = 2; } enum PeerState { Normal = 0; Applying = 1; Tombstone = 2; } message RegionLocalState { PeerState state = 1; metapb.Region region = 2; } RaftLocalState: Used to store HardState of the current Raft and the last Log Index.RaftApplyState: Used to store the last Log index that Raft applies and some truncated Log information.RegionLocalStaste: Used to store Region information and the corresponding Peer state on this Store. Normal indicates that this Peer is normal, Applying means this Peer hasn’t finished the apply snapshot operation and Tombstone shows that this Peer has been removed from Region and cannot join in Raft Group.Back to the topPeer Storage We use Raft through RawNode because one Region corresponds to one Raft Group. Peer in Region corresponds to one Raft replica. Therefore, we encapsulate operations towards RawNode in Peer.To use Raft, we need to define our storage and this can be implemented in the PeerStorage class of raftstore/store/peer_storage.rs.When creating PeerStorage, we need to get the previous RaftLocalStat, RaftApplyState and last_term of this Peer from RocksDB. These will be cached to memory for the subsequent quick access.Below requires extra attention:The value of both RAFT_INIT_LOG_TERM and RAFT_INIT_LOG_INDEX is 5 (as long as it’s larger than 1). In TiKV, there are several ways to create a Peer: Create actively: In general, for the first Peer replica of the first Region, we use this way and set its Log Term and Index as 5 during initialization. Create passively: When a Region adds a Peer replica and this ConfChange command has been applied, the Leader will send a Message to the Store of this newly-added Peer. When the Store receives this Message and confirms its legality, and finds that there is no corresponding Peer, it will create a corresponding Peer. However, at that time, this Peer is an uninitialized and any information of its Region is unknown to us, so we use 0 to initialize its Log Term and Index. Leader then will know this Follower has no data (there exists a Log notch from 0 to 5) and it will directly send snapshot to this Follower. Create when splitting: When a Region splits into two Regions, one of the Regions will …"}, {"url": "https://pingcap.com/blog-cn/tidb-jepsen/", "title": "当 TiDB 遇上 Jepsen", "content": " 本篇文章主要介绍 TiDB 是如何使用分布式一致性验证框架 Jepsen 进行一致性验证的。什么是 Jepsen Jepsen 是由 Kyle Kingsbury 采用函数式编程语言 Clojure 编写的验证分布式系统一致性的测试框架,作者使用它对许多著名的分布式系统(etcd, cockroachdb…)进行了“攻击”(一致性验证),并且帮助其中的部分系统找到了 bug。这里一系列的博客展示了作者的验证过程以及对于一致性验证的许多思考。Jepsen 如何工作 Jepsen 验证系统由 6 个节点组成,一个控制节点(control node),五个被控制节点(默认为 n1, n2, n3, n4, n5),控制节点将所有指令发送到某些或全部被控制节点,这些指令包括底层的 shell 命令到上层的 SQL 语句等等。Jepsen 提供了几个核心 API 用于验证分布式系统: DBDB 封装了所验证的分布式系统下载、部署、启动和关闭命令,核心函数由 setup 和 teardown 组成,在 TiDB 的 Jepsen 测试中,setup 负责下载 TiDB 并且依次启动 Placement Driver、TiKV 和 TiDB;teardown 负责关闭整个 TiDB 系统并且删除日志。 ClientClient 封装了每一个测试所需要提供的客户,每个 client 提供两个接口:setup 和 invoke,setup 负责对 TiDB 进行连接,而 invoke 则包含了测试中 client 对 TiDB 调用的 sql 语句,具体语句依测试而定。 CheckerChecker 用于对测试生成的历史进行验证,判断测试结果是否符合预期,历史的格式如下图所示: NemesisNemesis 用于对系统引入故障,比如常见的网络分区、网络延时、节点宕机,在 TiDB 的测试中,有以下几种 nemesis:parts:网络分区 majority-ring:每个节点都看到不同的 majority start-stop:对某些节点进行 SIGSTOP start-kill:对某些节点进行 SIGKILL 下图展示了 parts nemesis 引入测试中后某些语句执行时出现了 time-out 的错误。 GeneratorGenerator 是 Jepsen 中的事件发生器,它将 Client 和 Nemesis 的操作交织在一起,为整个测试生成具体的执行语句。 TiDB 中的 Jepsen 测试 TiDB 中的 Jepsen 测试有 3 个,分别是 bank、set 和 register 测试。Bank Test 银行测试用于验证快照隔离。这个测试模拟了一个银行系统中的各种转账,每个银行系统的初始可以是这样的:[1 10] [2 10] [3 10] [4 10] [5 10] 1-5 分别代表账户名称,而 10 代表账户余额。测试会随机生成转账信息:[1 2 5] 代表将金额 5 从账户 1 转入账户 2 这个操作。与此同时,测试会随机读取所有账户的存款信息,例如某一时刻账户的存款信息可能是这样的:[8 14 2 11 15] 下面是测试进行中的某次截图:在快照隔离下,所有的转账都必须保证每一时刻所有账户的总金额是相同的。TiDB 在即使引入了各种 nemesis 的情况下仍旧顺利地通过了测试。Set Test 这个测试从不同节点并发的将不同的数插入一张表中,并且进行一次最终的表读取操作,用于验证所有返回成功的插入值一定会出现在表中,然后所有返回失败的插入值一定不在表中,同时,因为 nemesis 的引入,对于那些返回 time-out 的插入值,它们可能出现也可能不会出现在表中,这属于正常情况。下面是测试进行中的某次截图:同样,TiDB 通过了测试。Register Test 这个测试很好理解,建一个表,然后插入一条值,然后我们把这个值看做是一个寄存器,然后在测试中并发地从各个节点对其进行 read、write 和 cas 操作。然后利用 Jepsen 产生的一系列操作历史(如上图)进行 Linearizability 一致性验证。这个算法是 Jepsen 的核心,也是 Jepsen 被业界所熟知的原因之一,所以花时间去深入学习了下,我会在另一篇文章具体介绍这个算法。写在最后 每次 TiDB 更新代码,我们都会内部触发 CI 来执行 Jepsen,通过 Jepsen 来保证 TiDB 的数据一致性。如果你对分布式测试,一致性验证感兴趣,欢迎参与开发。TiDB Jepsen:https://github.com/pingcap/jepsen/tree/master/tidb"}, {"url": "https://pingcap.com/weekly/2017-08-14-tidb-weekly/", "title": "Weekly update (August 07 ~ August 13, 2017)", "content": " Weekly update in TiDB Last week, we landed 78 PRs in the TiDB repositories.Added Enable pushing down the following operations to TiKV. the JSON function ifnull minus and multiply Use the Delete-in-Range feature to speed up the Drop Database/Table/Index operations. Support prioritizing statements. Fixed Fix the TimeDiff compatibility issue. Consider charset in Right/Left/Substr. Do not record metrics when running intenal SQL. Fix potential issue of schema validation check. Add desc order info in explain. Improved Refactor the row structure to reduce memory allocation. Refactor the following expressions/builtin-functions evaluation framework: Plus Multiply Minus lpad/rpad bin from_base64 char reverse ifnull instr aes_encrypt/aes_decrypt is_true/is_false locate last_insert_id compress/uncompress/uncompress_length sleep conv char_length md5/sha1/sha2 charactor_length elt ifnull if round/abs random_bytes unaryplus Adjust cost for the Sort operator. Change the row format from structure to Datum slice. Weekly update in TiKV Last week, We landed 28 PRs in the TiKV repositories.Added Add hex/escaped converting for tikv-ctl. Add custom instant for time utilities. Add rows properties. Add size properties. Add region approximate size. Support basic DAG expression evaluation for coprocessor. Support the delete range KV command. Add the diff command for tikv-ctl to check the difference between 2 databases. Fixed Fix a bug caused by using box_try for the coprocessor. Improved Speed up clearing meta. Reduce callback by batching RaftCmdRequest. Refactor the configuration. Refactor the DAG and old selection. Refactor the time utilities. "}, {"url": "https://pingcap.com/success-stories/tidb-in-yuanfudao/", "title": "How TiDB tackles fast data growth and complex queries for yuanfudao.com", "content": "Yuanfudao.com is an online tutoring service targeting the K-12 educational segment in China with the largest number of elementary and secondary school student users. It owns three applications, Yuantiku (猿题库), the online question bank, Xiaoyuansouti (小猿搜题), the application for question search by taking pictures, and yuanfudao.com, an online tutoring service.So far, the Yuanfudao APPs have more than 1.16 million paying users and provide live tutoring courses of English and Math Olympiad to the elementary users, as well as all the subjects for secondary school students. With yuanfudao.com, students from every corner of China can enjoy high-quality courses from top teachers at home.The enormous amount of data in the question bank, the audio and video learning materials, and all the user data and log call for a high level of storage and processing capacity of yuanfudao.com’s backend system.yuanfudao.com’s business scenario requires the following features from its backend system: The storage system should be able to scale out flexibly to serve the large data volume and rapid data growth. Be able to meet the complex queries and BI related requirements, and can perform real-time analysis based on indexes like cities and channels. The system must be highly available, can automatically failover and is easy to maintain. In the early stage of solution evaluation and selection, yuanfudao.com considered the standalone MySQL solution but then gave up the idea because of the following reasons: They perceived that with the fast development of their business, the data storage capacity and concurrency stress would soon hit the processing bottleneck of a standalone database. If adding a sharding solution to MySQL, the sharding key must be specified, which would not support cross-shard distributed transactions. Not to mention that the proxy solution is intrusive to the business tier and developers must know clearly the partitioning rules, which makes it unable to achieve transparency. Sharding is difficult to implement cross-shard aggregate queries, such as correlated query, subquery and group-by aggregation of the whole table. In these business scenarios, the query complexity is passed on to the application developers. Even though some middleware can implement simple join support, there is still no way to guarantee the correctness of these queries. The broadcasting solution cannot scale and the overhead would be huge when the cluster becomes larger. For a business with a relatively large data volume, the problem of locking table for DDL on traditional RDBMS would be serious with a quite long lock time. If using some third-party tools like gh-ost to implement non-blocking DDL, the extra space overhead would be large and manual intervention would still be needed to guarantee the data consistency. What might make things worse is that the system might jitter during the switch process. It is safe to say that the maintenance complexity will increase exponentially with more and more machines while the scaling complexity is directly passed on to DBA. In the end, the backend developers of yuanfudao.com decided to use a distributed storage solution and after researching quite a few community solutions, they found TiDB, a distributed relational database.TiDB is an open source distributed Hybrid Transactional/Analytical Processing (HTAP) database. It features horizontal scalability, strong consistency, and high availability. Users can regard TiDB as a standalone database with an infinite storage capacity. TiDB is nonintrusive to business and can elegantly replace the traditional sharding solutions such as database middleware and database sharding while at the same time maintaining the ACID properties of transactions. Instead of paying too much attention to the details of database scaling, developers are freed to focus on business development, which greatly improves the R&D productivity.As the complicated distributed transactions and data replication are supported by the underlying storage engine, developers just need to concentrate on the business logic and creating values.The following table outlines the difference between MySQL sharding solutions and TiDB: MySQL Sharding TiDB ACID Transaction No Yes Online Scalability No Yes Complex Query No Yes Failover Manual Auto MySQL Compatibility Low High (Comparison between TiDB and traditional MySQL sharding solutions)TiDB cluster consists of three components: TiDB Server, TiKV Server, and PD Server. The Overall Architecture of TiDB TiDB Server is responsible for processing SQL request. When the business grows, adding more TiDB Server nodes can improve the entire processing capacity and offer a higher throughput.TiKV is responsible for storing data. When the data volume grows, deploying more TiKV Server nodes can directly increase the data storage capacity.PD schedules among the TiKV nodes in Regions and migrates a portion of data to the newly-added node. Therefore, in the early stage, users can deploy a few service instances and add more TiKV or TiDB instances if needed, depending on the data volume.For the deployment in a production environment, yuanfudao.com chose an architecture of 2 TiDB + 3 TiKV + 3 PD for the condition of 5 million rows of data volume per day, hundreds of millions of records in the routing database and the peak QPS is about 1000. It is noted that the architecture scales as the business data volume grows.The client end of yuanfudao.com collects data about the audio and video quality of live streaming, such as packet loss, latency, and quality grading. Then the client end sends these data to the server and the latter stores all data in TiDB.Guo Changzhen, the R&D Vice President of yuanfudao.com, expresses his appreciation towards TiDB: “TiDB is an ambitious project and solves the scaling problem of MySQL from scratch. It also has the OLAP capacity in many scenarios, saving the cost of building and learning a data warehouse, which is quite popular in the business tier.” As a next step, yuanfudao.com plans to synchronize through Syncer, then merge and perform statistical analysis to other sharding businesses.There are many other similar use cases like yuanfudao.com. With the rapid development of the Internet, plenty of businesses are booming and TiDB can meet their needs with its flexible scaling capacity."}, {"url": "https://pingcap.com/weekly/2017-08-07-tidb-weekly/", "title": "Weekly update (July 31 ~ August 06, 2017)", "content": " Weekly update in TiDB Last week, we landed 54 PRs in the TiDB repositories.Added Support natural join. Add a switch for enabling cost-based optimizor. Assign low priority for SQL with full table scan and high priority for SQL with point get. Support N which is the shotcut of null. Support TIMESTAMP in the get_format function. Add a flag to enable TCP keep-alive. Support DISTINCTROW. Fixed Truncate the trailing spaces for “CHAR[(M)]” types Fix float point parsing with leading dot. Improved Refactor the row structure: to reduce memory allocation. Refactor the following expression/builtin-function evaluation framework: trim rtrim Check schema changing more precisely. Adjust the cost of index join. Weekly update in TiKV Last week, We landed 21 PRs in the TiKV repositories.Added Add priority for coprocessor thread pool. Add ceil_real function for coprocessor. Add remove function for JSON. Dynamically set label by PD API. Support delete member by id. Add more util functions. Fixed Stop the resolver thread explicitly. Improved Refactor the storage configuration field. Deny the http prefix for PD addresses. Refactor the properties collector. Improve the storage test. Use the MinOverlappingRatio compaction priority by default. "}, {"url": "https://pingcap.com/meetup/meetup-2017-08-05/", "title": "【Infra Meetup No.53】知乎数据平台实践", "content": " 今天的 Meetup,我们邀请到了知乎数据平台负责人王雨舟为大家做《知乎数据平台实践》的技术分享。 又是一个美好的周末,勤劳的小蜜蜂们早早出来参加活动了~🙂 今天的活动现场又是爆满~ 感觉要换地儿的节奏啊~今天 Meetup 的开场,我司联合创始人兼 CTO 黄东旭同学首先为大家分享了 TiDB 项目的最新进展。黄东旭同学好开心的样子,因为就在昨天,TiDB 正式发布 RC4 版 。开场过后,接下来由知乎数据平台负责人王雨舟(江湖人称宇宙哥)开始为大家做技术分享。宇宙哥真是 PingCAP 的真爱粉儿~ 穿着我司的文化衫亮相活动现场,超级有气场~以下是部分技术干货分享,Enjoy~宇宙哥在演讲开始先介绍了知乎大数据平台的整体架构情况并讲解了埋点流程及使用 Protobuf 做埋点标准化规范除此之外,宇宙哥还从以下几点来分析介绍 Druid在知乎的实践: 自定义多维分析功能和留存分析功能; 如何做到实时数据分析; 自定义指标、维度、报表、文件夹、Dashboard。 这张 PPT 中有眼熟的部分哦😏宇宙哥用“丝般顺滑”总结了自己现在使用 TiDB 的感受,并表达了对 TiSpark 的期待✌️分享结束后,显然大家都还没有尽兴,接下来是一段时长堪比分享环节的 QA。激烈的讨论后现场小伙伴跟宇宙哥都嗨了,还没有嗨够的小伙伴我们下次见~ PingCAP Infra Meetup作为一个基础架构领域的前沿技术公司,PingCAP 希望能为国内真正关注技术本身的 Hackers 打造一个自由分享的平台。自 2016 年 3 月 5 日开始,我们定期在周六的上午举办 Infra Meetup,邀请业内大牛与大家深度探讨基础架构领域的前瞻性技术思考与经验。在这里,我们希望提供一个高水准的前沿技术讨论空间,让大家真正感受到自由的开源精神魅力。 "}, {"url": "https://pingcap.com/weekly/2017-07-31-tidb-weekly/", "title": "Weekly update (July 24 ~ July 30, 2017)", "content": " Weekly update in TiDB Last week, we landed 50 PRs in the TiDB repositories.Added Add a debugging tool for transaction inspection. Support two JSON syntactic sugars. Support renaming multiple tables in a single statement. Fixed Fix a bug in the update statement when doing the alter table after statement. Fix signed integer overflow in the minus unary scalar function. Fix the content in the information_schema for unsigned columns. Fix inserting zero length data into a column with zero field length. Check the field length limitation in the alter table statement. Add the field length limitation for the index columns. The password builtin function should return empty string when meeting null argument. Check the table name with white space in the end. Improved Add more DDL test cases. Refactor the explain statement. Refactor the following expression/builtin-function evaluation framework: pi logicalAnd cot exp logicalXor bitAnd logicalOr bitOr bitXor leftShift rightShift bitNeg Extract configuration related code to the config package. Improve the unit test coverage: ast package Fix a bug of using undefined user variable. Make go vet happy. New Contributor (Thanks!) Jiaxing Liang Hu Ming Wei Fu Liao Qiang Weekly update in TiKV Last week, We landed 27 PRs in the TiKV repositories.Added Add the transaction debugging gRPC API. Add the ceil, abs functions for coprocessor. Add the compaction priority for RocksDB. Handle thenull datum for coprocessor. Fixed Decrease the load limit to 10000. Fix a bug when using offset in expressions for coprocessor. Fix trace_size computing. Let Travis decide which compiler to use automatically. Fix a message delay bug. Avoid unnecessary clones when sending Raft messages. Improved Log more detailed error when transaction fails. Refactor RocksDB options. Implement serde for enum and readable types. Use the FIFO queue for coprocessor work queue. Decrease default leader-schedule-limit to 64. Update distinct score calculation for different stores. Enhance the PD join function. New contributors ariesdevil bailaohe dantin "}, {"url": "https://pingcap.com/blog/2017-07-28-raftintikv/", "title": "A TiKV Source Code Walkthrough - Raft in TiKV", "content": " (Email: tl@pingcap.com)Table of content Architecture Raft Storage Config RawNode Architecture Below is TiKV’s overall architecture:Placement Driver: Placement Driver (PD) is responsible for the management scheduling of the whole cluster.Node: Node can be regarded as an actual physical machine and each Node is responsible for one or more Store.Store: Store uses RocksDB to implement actual data storage and usually one Store corresponds to one disk.Region: Region is the smallest unit of data movement and it refers to the actual data extent in Store. Each Region has multiple replicas, each of which is placed in different Stores and these replicas make up a Raft group.Back to the topRaft TiKV uses the Raft algorithm to implement the strong consistency of data in a distributed environment. For detailed information about Raft, please refer to the paper In Search of an Understandable Consensus Algorithm and the official website. Simply put, Raft is a model of replication log + State Machine. We can only write through a Leader and the Leader will replicate the command to its Followers in the form of log. When the majority of nodes in the cluster receive this log, this log has been committed and can be applied into the State Machine.TiKV’s Raft mainly migrates etcd Raft and supports all functions of Raft, including: Leader election Log replicationLog compaction Membership changesLeader transfer Linearizable / Lease read Note that how TiKV and etcd process membership change is different from what is in the Raft paper. TiKV’s membership change will take effect only when the log is applied. The main purpose is for a simple implementation. But it will be risky if we only have two nodes. Since we have to remove one node from inside and if a Follower has not received the log entry of ConfChange, the Leader will go down and be unrecoverable, then the whole cluster will be down. Therefore, it is recommended that users deploy 3 or more odd number of nodes.The Raft library is independent and users can directly embed it into their applications. What they need to do is to process storage and message sending. This article will briefly introduce how to use Raft and you can find the code under the directory of TiKV source code /src/raft.Storage First of all, we need to define our Storage, which is mainly used for storing relevant data of Raft. Below is the trait definition:pub trait Storage { fn initial_state(&self) -> Result<RaftState>; fn entries(&self, low: u64, high: u64, max_size: u64) -> Result<Vec<Entry>>; fn term(&self, idx: u64) -> Result<u64>; fn first_index(&self) -> Result<u64>; fn last_index(&self) -> Result<u64>; fn snapshot(&self) -> Result<Snapshot>; } We need to implement our Storage trait and I’ll elaborate on the implication of each interface:initial_state: Call this interface when initializing Raft Storage and it will return RaftState, whose definition is shown below:pub struct RaftState { pub hard_state: HardState, pub conf_state: ConfState, } HardState and ConfState is protobuf defined as follows:message HardState { optional unit64 term = 1; optional unit64 vote = 2; optional unit64 commit = 3; } message ConfState { repeated unit64 nodes = 1; } HardState stores the following information: the last saved term information of this Raft node which node was voted the log index that is already committed. ConfState saves all node ID information of the Raft cluster.When calling relevant logic of Raft from outside, users need to handle the persistence of RaftState.entries: Get the Raft log entry of the [low, high) interval and controls the maximum number of the returned entries through max_size.term, first_index and last_index **refers to getting the current term, the smallest and the last log index respectively.snapshot: Get a snapshot of the current Storage. Sometimes, the amount of the current Storage is large and it takes time to create a snapshot. Then we have to asynchronously create it in another thread, so that the current Raft thread will not be clocked. At this time, the system can return SnapshotTemporarilyUnavailable error so that Raft will know snapshot is being prepared and will try again after a while.Note that the above Storage interface is just for Raft. But actually we also use this Storage to store data like Raft log and so we need to provide other interfaces, such as MemStorage in Raft storage.rs for testing. You can refer to MemStorage to implement your Storage.Back to the topConfig Before using Raft, we need to know some relevant configuration of Raft. Below are the items that need extra attention in Config:pub struct Config { pub id: u64, pub election_tick: usize, pub heartbeat_tick: usize, pub applied: u64, pub max_size_per_msg: u64, pub max_inflight_msgs: usize, } id: The unique identification of the Raft node. Within a Raft cluster, id has to be unique. Inside TiKV, the global uniqueness of id is guaranteed through PD.election_tick: When a Follower hasn’t received the message sent by its Leader after the election_tick time, then there will be a new election and TiKV uses 50 as the default.heartbeat_tick: The Leader sends a heartbeat message to its Follower every hearbeat_tick. The default value is 10.applied: It is the log index that was last applied.max_size_per_msg: Limit the maximum message size to be sent each time. The default value is 1MB.max_inflight_msgs: Limit the maximum number of in-flight message in replication. The default value is 256.Here is the detailed implication of tick: TiKV’s Raft is timing-driven. Assume that we call the Raft tick once every 100ms and when we call the tick times of headtbeat_tick, the Leader will send heartbeats to its Follower.Back to the topRawNode We use Raft through RawNode and below is its constructor:pub fn new(config: &Config, sotre: T, peers: &[peer]) -> Result<RawNode<T>> We need to define Raft’s Config and then pass an implemented Storage. The peers parameter is just used for testing and it will not be passed. After creating the RawNode object, we can use Raft. Below are some functions that we pay attention to:tick: We use the tick function to drive Raft regularly. In TiKV, we call tick once every 100ms.propose: The Leader writes the command sent by client to the Raft log through the propose command and replicates to other nodes.propose_conf_change: Like propose, this function is just used for handling the ConfChange command.step: When the node receives the message sent by other nodes, this function actively calls the driven Raft.has_ready: Used to determine whether a node is ready.ready: Get the ready state of the current node. Before that, we will use has_ready to determine whether a RawNode is ready.apply_conf_change: When a log of ConfChange is applied successfully, we need to actively call this driven Raft.advance: Tell Raft that ready has been processed and it’s time to start successive iterations.As for RawNode, we should emphasize the ready concept and below is its definition:pub struct Ready { pub ss: Option<SoftState>, pub hs: Option<HardState>, pub entries: Vec<Entry>, pub snapshot: Snapshot, pub committed_entries: Vec<Entry>, pub messages: Vec<Message>, } ss: If SoftState has changes, such as adding or deleting a node, ss will not be empty.hs: If HardState has changes, such as re-voting or term increasing, hs will not be empty.entries: Needs to be stored in Storage before sending messages.snapshot: If snapshot is not empty, it needs to be stored in Storage.committed_entries: The Raft log that has been committed can be applied to State Machine.messages: Usually, the message sending to other nodes cannot be sent until entries are saved successfully. But to a Leader, it can send messages first before saving entries. This is the optimization method introduced in the Raft paper and is also what TiKV adopts.When the outside finds that a …"}, {"url": "https://pingcap.com/blog-cn/tispark/", "title": "TiSpark (Beta) 用户指南", "content": " TiSpark 是 PingCAP 推出的为了解决用户复杂 OLAP 需求的产品。借助 Spark 平台本身的优势,同时融合 TiKV 分布式集群的优势,和 TiDB 一起为用户一站式解决 HTAP (Hybrid Transactional/Analytical Processing)需求。 TiSpark 依赖 TiKV 集群和 PD 的存在。当然,TiSpark 也需要你搭建一个 Spark 集群。本文简单介绍如何部署和使用 TiSpark。本文假设你对 Spark 有基本认知。你可以参阅 Apache Spark 官网 了解 Spark 相关信息。一、概述 TiSpark 是将 Spark SQL 直接运行在 TiDB 存储引擎 TiKV 上的 OLAP 解决方案。TiSpark 架构图如下: TiSpark 深度整合了 Spark Catalyst 引擎, 可以对计算提供精确的控制,使 Spark 能够高效的读取 TiKV 中的数据,提供索引支持以实现高速的点查; 通过多种计算下推减少 Spark SQL 需要处理的数据大小,以加速查询;利用 TiDB 的内建的统计信息选择更优的查询计划。 从数据集群的角度看,TiSpark + TiDB 可以让用户无需进行脆弱和难以维护的 ETL,直接在同一个平台进行事务和分析两种工作,简化了系统架构和运维。 除此之外,用户借助 TiSpark 项目可以在 TiDB 上使用 Spark 生态圈提供的多种工具进行数据处理。例如使用 TiSpark 进行数据分析和 ETL;使用 TiKV 作为机器学习的数据源;借助调度系统产生定时报表等等。 二、环境准备 现有 TiSpark 版本支持 Spark 2.1,对于 Spark 2.0 及 Spark 2.2 还没有经过良好的测试验证。对于更低版本暂时无法支持。TiSpark 需要 JDK 1.8+ 以及 Scala 2.11(Spark2.0+ 默认 Scala 版本)。TiSpark 可以在 YARN,Mesos,Standalone 等任意 Spark 模式下运行。三 、推荐配置 3.1 部署 TiKV 和 TiSpark 集群 3.1.1 TiKV 集群部署配置 对于 TiKV 和 TiSpark 分开部署的场景,建议参考如下建议 硬件配置建议 普通场景可以参考 TiDB 和 TiKV 硬件配置建议,但是如果是偏重分析的场景,可以将 TiKV 节点增加到至少 64G 内存,如果是机械硬盘,则推荐 8 块。 TiKV 参数建议 [server] end-point-concurrency = 8 # 如果使用场景偏向分析,则可以考虑扩大这个参数 [raftstore] sync-log = false [rocksdb] max-background-compactions = 6 max-background-flushes = 2 [rocksdb.defaultcf] block-cache-size = "10GB" [rocksdb.writecf] block-cache-size = "4GB" [rocksdb.raftcf] block-cache-size = "1GB" [rocksdb.lockcf] block-cache-size = "1GB" [storage] scheduler-worker-pool-size = 4 3.1.2 Spark / TiSpark 集群独立部署配置 关于 Spark 的详细硬件推荐配置请参考官网,如下是根据 TiSpark 场景的简单阐述。Spark 推荐 32G 内存以上配额。请在配置中预留 25% 的内存给操作系统。Spark 推荐每台计算节点配备 CPU 累计 8 到 16 核以上。你可以初始设定分配所有 CPU 核给 Spark。Spark 的具体配置方式也请参考官方说明。下面给出的是根据 spark-env.sh 配置的范例:SPARK_EXECUTOR_MEMORY=32g SPARK_WORKER_MEMORY=32g SPARK_WORKER_CORES=8 3.1.3 TiSpark 与 TiKV 集群混合部署配置 对于 TiKV、TiSpark 混合部署场景,请在原有 TiKV 预留资源之外累加 Spark 所需部分并分配 25% 的内存作为系统本身占用。四、部署 TiSpark TiSpark 的 jar 包可以在这里下载。4.1 已有 Spark 集群的部署方式 在已有 Spark 集群上运行 TiSpark 无需重启集群。可以使用 Spark 的 –jars 参数将 TiSpark 作为依赖引入:spark-shell --jars $PATH/tispark-0.1.0.jar如果想将 TiSpark 作为默认组件部署,只需要将 TiSpark 的 jar 包放进 Spark 集群每个节点的 jars 路径并重启 Spark 集群:${SPARK_INSTALL_PATH}/jars这样无论你是使用 Spark-Submit 还是 Spark-Shell 都可以直接使用 TiSpark。4.2 没有 Spark 集群的部署方式 如果你没有使用中的 Spark 集群,我们推荐 Spark Standalone 方式部署。我们在这里简单介绍下 Standalone 部署方式。如果遇到问题,你可以去官网寻找帮助;也欢迎在我们的 GitHub 上提 issue。4.2.1 下载安装包并安装 你可以在这里下载 Apache Spark。对于 Standalone 模式且无需 Hadoop 支持,请选择 Spark 2.1.x 且带有 Hadoop 依赖的 Pre-build with Apache Hadoop 2.x 任意版本。如你有需要配合使用的 Hadoop 集群,请选择对应的 Hadoop 版本号。你也可以选择从源代码自行构建以配合官方 Hadoop 2.6 之前的版本。请注意目前 TiSpark 仅支持 Spark 2.1.x 版本。假设你已经有了 Spark 二进制文件,并且当前 PATH 为 SPARKPATH。请将 TiSpark jar 包拷贝到 ${SPARKPATH}/jars 目录下。4.2.2 启动 Master 在选中的 Spark Master 节点执行如下命令:cd $SPARKPATH ./sbin/start-master.sh 在这步完成以后,屏幕上会打印出一个 log 文件。检查 log 文件确认 Spark-Master 是否启动成功。 你可以打开 http://spark-master-hostname:8080 查看集群信息(如果你没有改动 Spark-Master 默认 Port Numebr)。在启动 Spark-Slave 的时候,你也可以通过这个面板来确认 Slave 是否已经加入集群。4.2.3 启动 Slave 类似地,可以用如下命令启动 Spark-Slave节点:./sbin/start-slave.sh spark://spark-master-hostname:7077 命令返回以后,你就可以通过刚才的面板查看这个 Slave 是否已经正确的加入了 Spark 集群。 在所有 Slave 节点重复刚才的命令。在确认所有的 Slave 都可以正确连接 Master,这样之后你就拥有了一个 Standalone 模式的 Spark 集群。五、一个使用范例 假设你已经按照上述步骤成功启动了 TiSpark 集群, 下面简单介绍如何使用 Spark SQL 来做 OLAP 分析。这里我们用名为 tpch 数据库中的 lineitem 表作为范例。在 Spark-Shell 里输入下面的命令, 假设你的 PD 节点位于 192.168.1.100,端口 2379:import org.apache.spark.sql.TiContext val ti = new TiContext(spark, List("192.168.1.100:2379") ti.tidbMapDatabase("tpch") 之后你可以直接调用 Spark SQLspark.sql("select count(*) from lineitem").show 结果为:+-------------+ | count(1) | +-------------+ | 600000000 | +-------------+ 六、FAQ Q. 是独立部署还是和现有 Spark/Hadoop 集群共用资源?A. 你可以利用现有 Spark 集群无需单独部署,但是如果现有集群繁忙,TiSpark 将无法达到理想速度。Q. 是否可以和 TiKV 混合部署?A. 如果 TiDB 以及 TiKV 负载较高且运行关键的线上任务,请考虑单独部署 TiSpark;并且考虑使用不同的网卡保证 OLTP 的网络资源不被侵占而影响线上业务。如果线上业务要求不高或者机器负载不大,可以考虑与 TiKV 混合部署。"}, {"url": "https://pingcap.com/blog/2017-07-24-tidbbestpractice/", "title": "TiDB Best Practices", "content": " From Li SHEN: shenli@pingcap.comSee the following blogs (Data Storage, Computing, Scheduling) for TiDB’s principles.Table of Content Preface Basic Concepts Raft Distributed Transactions Data Sharding Load Balancing SQL on KV Secondary Indexes Scenarios and Practices Deployment Importing Data Write Query Monitoring and Log Documentation Best Scenarios for TiDB Preface Database is a generic infrastructure system. It is important to, for one thing, consider various user scenarios during the development process, and for the other, modify the data parameters or the way to use according to actual situations in specific business scenarios.TiDB is a distributed database compatible with MySQL protocol and syntax. But with the internal implementation and supporting of distributed storage and transactions, the way of using TiDB is different from MySQL.Basic Concepts The best practices are closely related to its implementation principles. This article briefly introduces Raft, distributed transactions, data sharding, load balancing, the mapping solution from SQL to KV, implementation method of secondary indexing and distributed execution engine.Raft Raft is a consensus algorithm and ensures data replication with strong consistency. At the bottom layer, TiDB uses Raft to synchronize data. TiDB writes data to the majority of the replicas before returning the result of success. In this way, the system will definitely have the latest data even though a few replicas might get lost. For example, if there are three replicas, the system will not return the result of success until data has been written to two replicas. Whenever a replica is lost, at least one of the remaining two replicas have the latest data.To store three replicas, compared with the synchronization of Master-Slave, Raft is more efficient. The write latency of Raft depends on the two fastest replicas, instead of the slowest. Therefore, the implementation of geo-distributed and multiple active datacenters becomes possible by using the Raft synchronization. In the typical scenario of three datacenters distributing in two sites, to guarantee the data consistency, we just need to successfully write data into the local datacenter and the closer one, instead of writing to all three data-centers. However, this does not mean that cross-datacenter deployment can be implemented in any scenario. When the amount of data to be written is large, the bandwidth and latency between data-centers become the key factors. If the write speed exceeds the bandwidth or the latency is too high, the Raft synchronization mechanism still cannot work well.Back to the topDistributed Transactions TiDB provides complete distributed transactions and the model has some optimizations on the basis of Google Percolator. Here, I would just talk about two things: Optimistic LockTiDB’s transaction model uses the optimistic lock and will not detect conflicts until the commit phase. If there are conflicts, retry the transaction. But this model is inefficient if the conflict is severe because operations before retry are invalid and need to repeat. Assume that the database is used as a counter. High access concurrency might lead to severe conflicts, resulting in multiple retries or even timeouts. Therefore, in the scenario of severe conflicts, it is recommended to solve problems at the system architecture level, such as placing counter in Redis. Nonetheless, the optimistic lock model is efficient if the access conflict is not very severe. Transaction Size LimitsAs distributed transactions need to conduct two-phase commit and the bottom layer performs Raft replication, if a transaction is very large, the commit process would be quite slow and the following Raft replication flow is thus struck. To avoid this problem, we limit the transaction size: Each Key-Value entry is no more than 6MB The total number of Key-Value entry is no more than 300,000 rows The total size of Key-Value entry is no more than 100MB There aresimilar limits on Google Cloud Spanner. Back to the topData Sharding TiKV automatically shards bottom-layered data according to the Range of Key. Each Region is a range of Key, from a left-close-right-open interval, [StartKey, EndKey). When the amount of Key-Value in Region exceeds a certain value, it will automatically split.Load Balancing PD will automatically balance the load of the cluster according to the state of the entire TiKV cluster. The unit of scheduling is Region and the logic is the strategy configured by PD.SQL on Key-Value TiDB automatically maps the SQL structure into Key-Value structure. For more information, please refer to Computing. Simply put, TiDB has done two things: A row of data is mapped to a Key-Value pair. Key is prefixed with TableID and suffixed with row ID. An index is mapped as a Key-Value pair. Key is prefixed with TableID+IndexID and suffixed with the index value. As you can see, data and index in the same table have the same prefix, so that these Key-Values are at adjacent positions in the Key space of TiKV. Therefore, when the amount of data to be written is large and all is written to one table, the write hotspot is thus created. The situation gets worse when some index values of the continuous written data is also continuous (e.g. fields that increase with time, like update time), which will create a few write hotspots and become the bottleneck of the entire system. Likewise, if all data is read from a focused small range (e.g. the continuous tens or hundreds of thousands of rows of data), access hotspot of data will probably occur.Back to the topSecondary Indexes TiDB supports the complete secondary indexes which are also global indexes. Many queries can be optimized by index. Lots of MySQL experience is also applicable to TiDB, it is noted that TiDB has its unique features. Below are a few notes when using secondary indexes in TiDB. The more secondary indexes, the better?Secondary indexes can speed up query, but adding an index has side effects. In the last section, we’ve introduced the storage model of index. For each additional index, there will be one more Key-Value when inserting a piece of data. Therefore, the more indexes, the slower the writing speed and the more space it takes up. In addition, too many indexes will influence the runtime of the optimizer. And inappropriate index will mislead the optimizer. Thus, the more secondary indexes is not necessarily the better. Which columns should create indexes?As mentioned before, index is important but the number of indexes should be proper. We need to create appropriate indexes according to the characteristics of business. In principle, we need to create indexes for the columns needed in the query, the purpose of which is to improve the performance. Below are the conditions that need to create indexes: For columns with a high degree of differentiation, the number of filtered rows is remarkably reduced though index. If there are multiple query criteria, you can choose composite indexes. Note to put the columns with equivalent condition before composite index. For example, for a commonly-used query is select * from t where c1 = 10 and c2 = 100 and c3 > 10, you can create a composite index Index cidx (c1, c2, c3). In this way, you can use the query criterion to create an index prefix and then Scan. The difference between query through indexes and directly scan Table TiDB has implemented global indexes, so indexes and data of the Table are not necessarily on data sharding. When querying through indexes, it should firstly scan indexes to get the corresponding row ID and then use the row ID to get the data. Thus, this method involves two network requests and has a certain performance overhead.If the query involves lots of rows, scanning index proceeds concurrently. When the first batch of results is returned, getting the data of Table can then proceed. Therefore, this is a parallel + Pipeline model. Though the two accesses …"}, {"url": "https://pingcap.com/weekly/2017-07-24-tidb-weekly/", "title": "Weekly update (July 17 ~ July 23, 2017)", "content": " Weekly update in TiDB Last week, we landed 60 PRs in the TiDB repositories.Added Add a tidb_version function to get the tidb-server version information. Support the READ COMMITTED isolation level. Support the ENCLOSED BY clause in the Load Data statement. Support creating index using type and comment. Fixed Fix a bug when in json_unquote. Fix field name with comment. Fix the wrong offset when using the Primary Key column as the handle. Improved Refactor the optimizer: Refactoring projection elimination. Refactor the builtin function evaluation framework: substring_index log asin atan acos floor hex ceil unhex Improve the unit test coverage: table package schema.go kv package builtin_compare.go datum.go distsql package column.go expression.go scalar_function.go Fix a bug of using undefined user variable. Weekly update in TiKV Last week, We landed 19 PRs in the TiKV repositories.Added Add DAG executor for coprocessor. Add json_object and json_array for coprocessor. Add the abs function for the coprocessor. Add the u64 support for JSON type. Add the max_compaction_bytes support for RocksDB. Add the TSO warning metrics for PD. Fixed Enlarge gRPC send message length. Remove the unix socket from PD test. Fix a bug when shrinking buffer. Improved Use collected properties to optimize GC. Get RocksDB snapshot lazily. Introduce rate limit to make QPS more stable. Send the apply proposals in batches. Stop supporting the old V1 snapshot format any more and support using V2 only. "}, {"url": "https://pingcap.com/meetup/meetup-2017-07-22/", "title": "【Infra Meetup No.52】TiDB 自动化运维管理 —— TiDB-Operator》", "content": " 今天的 Meetup,由我司技术大拿邓栓同学为大家分享《TiDB 自动化运维管理 —— TiDB-Operator》。 今日的帝都带着一丝凉爽,如此好天气怎能辜负。小伙伴们一清早就来到互动现场,一起来吃“营养早午餐”。我司技术大拿邓栓同学激情满满的开始为大家做主题分享,主要从 TiDB-Operator 的功能介绍、整体架构、实现细节这几个纬度切入。邓栓同学开场介绍到:分布式系统由于自身的复杂性,其管理和运维通常是非常困难的事情,借助 TiDB-Operator 我们能够轻松地将 TiDB 集群部署到 Kubernetes 集群之上,并做到自动化运维管理,极大地降低了人力运维成本,现场小伙伴们听呆了~咦?what’wrong ? 黑灯瞎火嘛呢?其实是小伙伴们在一起很专注的看 demo 演示~活动最后,邓栓同学通过 demo 演示了 TiDB-operator bootstrap 一套完整的 TiDB 集群,然后在集群上面执行一个简单的操作就可以轻松实现扩容缩容,并且模拟物理节点挂掉时 TiDB-operator 对集群做自动恢复等各种自动化运维操作流程。以上为最新前方报道~ enjoy 😁讲师介绍:邓栓,PingCAP SRE 工程师,Kubernetes 爱好者,目前主要负责 TiDB 与各种云平台整合。Rust 中国社区联合创始人。 PingCAP Infra Meetup作为一个基础架构领域的前沿技术公司,PingCAP 希望能为国内真正关注技术本身的 Hackers 打造一个自由分享的平台。自 2016 年 3 月 5 日开始,我们定期在周六的上午举办 Infra Meetup,邀请业内大牛与大家深度探讨基础架构领域的前瞻性技术思考与经验。在这里,我们希望提供一个高水准的前沿技术讨论空间,让大家真正感受到自由的开源精神魅力。 "}, {"url": "https://pingcap.com/blog/2017-07-20-tidbinternal3/", "title": "TiDB Internal (III) - Scheduling", "content": " From Li SHEN: shenli@pingcap.comTable of Content Why scheduling The Requirements of Scheduling The Basic Operations of Scheduling Information Collecting The Policy of Scheduling The implementation of Scheduling Summary Why scheduling? From the first blog of TiDB internal, we know that TiKV cluster is the distributed KV storage engine of TiDB database. Data is replicated and managed in Regions and each Region has multiple Replicas distributed on different TiKV nodes. Among these replicas, Leader is in charge of read/write and Follower synchronizes the raft log sent by Leader. Now, please think about the following questions: How to guarantee that multiple Replicas of the same Region are distributed on different nodes? Further, what happens if starting multiple TiKV instances on one machine? When TiKV cluster is performing multi-site deployment for disaster recovery, how to guarantee that multiple Replicas of a Raft Group will not get lost if there is outage in one datacenter? How to move data of other nodes in TiKV cluster onto the newly-added node? What happens if a node fails? What does the whole cluster need to do? How to handle if the node fails only temporarily (e.g. restarting a service)? What about a long-time failure (e.g. disk failure or data loss)? Assume that each Raft Group is required to have N replicas. A single Raft Group might have insufficient Replicas (e.g. node failure, loss of replica) or too much Replicas (e.g. the once failed node functions again and automatically add to the cluster). How to schedule the number? As read/write is performed by Leader, what happens to the cluster if all Leaders gather on a few nodes? There is no need to get access to all Regions and the hotspot probably resides in a few Regions. In this case, what should we do? The cluster needs to migrate data during the process of load balancing. Will this kind of data migration consume substantial network bandwidth, disk IO and CPU and influence the online service? It is easy to solve the above questions one by one, but once mixed up, it becomes difficult. It seems that some questions just need to consider the internal situation of a single Raft Group, for example, whether to add replicas is determined by if the number is enough. But actually, where to add this replica needs a global view. The whole system is changing dynamically: situations like Region splitting, node joining, node failing and hotspot accessing changes occur constantly. The schedule system also needs to keep marching towards the best state. Without a component that can master, schedule and configure the global information, it is hard to meet these needs. Therefore, we need a central node to control and adjust the overall situation of the system. So here comes the Placement Driver (PD) module.Back to the topThe Requirements of Scheduling I want to categorize and sort out the previously listed questions. In general, there are two types: A distributed and highly available storage system must meet the following requirements: The right number of replicas. Replicas should be distributed on different machines. Replicas on other nodes can be migrated after adding nodes. When a node is offline, data on this node should be migrated. A good distributed system needs to have the following optimizations: A balanced distribution of Leaders in the cluster. A balanced storage capacity in each node. A balanced distribution of hotspot accessing. Control the speed of balancing in order not to impact the online service. Manage the node state, including manually online/offline nodes and automatically offline faulty nodes. If the first type of requirements are met, the system supports multi-replica disaster recovery, dynamic scalability, tolerance of node failure and automatic disaster recovery. If the second type of requirements are met, the load of the system becomes more balanced and easier to manage. To meet these needs, we need to, first of all, collect enough information, such as the state of each node, information of each Raft Group and the statistics of business access and operation. Then we should set some policies for PD to formulate a schedule plan to meet the previous requirements according to this information and the schedule policy.Back to the topThe Basic Operations of Scheduling The basic operations of schedule are the simplest. In other word, what we can do to meet the schedule policy. This is the essence of the whole scheduler. The previous scheduler requirements seem to be complicated, but can be generalized into 3 operations: Add a Replica. Delete a Replica. Transfer the role of Leader among different Replicas of a Raft Group. The Raft protocol happens to meet these requirements: the AddReplica, RemoveReplica and TransferLeader commands support the three basic operations.Back to the topInformation Collecting Schedule depends on the information gathering of the whole cluster. Simply put, we need to know the state of each TiKV node and each Region. TiKV cluster reports two kinds of information to PD: Each TiKV node regularly reports the overall information of nodes to PDThere are heartbeats between TiKV Store and PD. On the one hand, PD checks whether each Store is active or if there are newly-added Stores through heartbeats. On the other hand, heartbeats carry the state information of this Store, mainly including: total disk capacity free disk capacity the number of Regions data writing speed the number of sent/received Snapshot (Replicas synchronize data through Snapshots) whether it is overloaded label information (Label is a series of Tags that has hierarchical relationship) Leader of each Raft Group reports to PD regularlyLeader of each Raft Group and PD are connected with heartbeats, which report the state of this Region, including: the position of Leader the position of Followers the number of offline Replicas data reading/writing speed Through these two kinds of heartbeats, PD gathers the information of the whole cluster and then makes decisions. What’s more, PD makes more accurate decisions by getting extra information through the management interface. For example, when the heartbeat of a Store is interrupted, PD has no idea whether it is temporarily or permanently. PD can only waits for a period of time (30 minutes by default); if there is still no heartbeat, PD considers that the Store has been offline and it needs to move all Regions on the Store away. However, if an Operations staff manually offline a machine, he needs to tell PD through its management interface that the Store is unavailable. In this case, PD will immediately move all Regions on the Store away.Back to the topThe Policy of Scheduling After gathering information, PD needs some policies to draw up a concrete schedule plan. The number of Replica in a Region should be correctWhen PD finds that the number of Replica for a Region doesn’t meet the requirement through the heartbeat of a Region Leader, it modifies the number through the Add/Remove Replica operations. This might occur when: a node drops and loses all data, leading to the lack of Replica in some Regions. a dropped node functions again and automatically joins in the cluster. In this case, there is a redundant Replica and needs to be removed. the administrator has modified the replica policy and the configuration of max-replicas. Multiple Replicas of a Raft Group should not be in the same placePlease pay attention that it is the same place, not the same node. In general, PD can only guarantee that multiple Replicas would not be in the same node, so as to avoid the problem that many Replicas get lost when a node fails. In an actual deployment scenario, the following requirements may come out: Multiple nodes are deployed on the same physical machine. TiKV nodes distribute on multiple servers. It is expected that when a server powers down, the system is still available. TiKV nodes distribute on multiple IDCs. When a datacenter powers down, the system is …"}, {"url": "https://pingcap.com/blog-cn/pax/", "title": "PAX:一个 Cache 友好高效的行列混存方案", "content": " 今年,Spanner 终于发了另一篇 Paper 「Spanner: Becoming a SQL System」,里面提到 Spanner 使用了一种新的存储格式 - Ressi,用来支持 OLTP 和 OLAP。在 Ressi 里面,使用了 PAX 来组织数据。因为 TiDB 定位就是一个 HTAP 系统,所以我也一直在思考在 TiKV 这层如何更好的存储数据,用来满足 HTAP 的需要,既然 Spanner 使用了 PAX,那么就有研究的必要了。PAX 的论文可以看看 「Weaving Relations for Cache Performance」 或者 「Data Page Layouts for Relational Databases on Deep Memory Hierarchies」。NSM and DSM 在谈 PAX 之前,NSM 和 DSM 还是绕不开的话题,NSM 就是通常说的行存,对于现阶段很多偏重 OLTP 的数据,譬如 MySQL 等,都采用的这种方式存储的数据。而 DSM,则是通常的说的列存,几乎所有的 OLAP 系统,都采用的这种方式来存储的底层数据。NSM 会将 record 依次在磁盘 page 里面存放,每个 page 的末尾会存放 record 的 offset,便于快速的定位到实际的 record。如果我们每次需要得到一行 record,或者 scan 所有 records,这种格式非常的高效。但如果我们的查询,仅仅是要拿到 record 里面的一列数据,譬如 select name from R where age < 40,那么对于每次 age 的遍历,除了会将无用的其他数据一起读入,每次读取 record,都可能会引起 cache miss。不同于 NSM,DSM 将数据按照不同的 attributes 分别存放到不同的 page 里面。对于上面只需要单独根据某一个 attribute 进行查询的情况,我们会直接读出 page,遍历处理,这个对 cache 也是非常高效友好的。但是,如果一个查询会涉及到多个不同的 attributes,那么我们就可能需要多次 IO 来组合最终的 tuple。同时,对于写入,DSM 因为会将不同的 attributes 对应的数据写到不同的 page,也会造成较多的随机 IO。PAX 可以看到,NSM 和 DSM 都有各自的优劣,所以如何将它们的优点结合起来,就是现在很多 hybrid storage 包括 PAX 考虑的问题。PAX 全称是 Partition Attributes Across,它在 page 里面使用了一种 mini page 的方式,将 record 切到不同的 mini page 里面。假设有 n 个 attributes,PAX 就会将 page 分成 n 个 mini pages,然后将第一个 attribute 放在第一个 mini page 上面,第二个放在第二个 mini page,以此类推。在每个 page 的开头,会存放每个 mini page 的 offset,mini page 对于 Fixed-length attribute 的数据,会使用 F-minipage ,而对于 variable-length attribute 的数据,则会使用 V-minipage。对于 F-minipage 来说,最后会有一个 bit vector 来存放 null value。而对于 V-minipage 来说,最后会保存每个 value 在 mini page 里面的 offset。可以看到,PAX 的格式其实是 NSM 和 DSM 的一种折中,当要依据某一列进行 scan 的时候,我们可以方便的在 mini page 里面顺序扫描,充分利用 cache。而对于需要访问多 attributes 得到最终 tuple 的时候,我们也仅仅是需要在同一个 page 里面的 mini page 之间读取相关的数据。Data Manipulation Insert 当数据插入的时候,PAX 会首先生成一个新的 page,然后根据 attribute 的 value size 分配好不同的 mini page, 这里需要注意下 variable-length value,因为它们的长度是不固定的,PAX 会使用一些 hint 来得到一个平均的 size。插入一个 record 的时候,PAX 会将这个 record 里面的数据分别 copy 到不同的 mini page 上面。如果一个 record 还能插入到这个 page,但这个 record 里面某一个 attribute 的数据不能插入到对应的 mini page 了,PAX 会重新调整不同 mini page 的 boundary。如果一个 page 已经 full 了,那么 PAX 就会重新分配一个 page。Update 当数据更新的时候,PAX 会首先计算这个 record 需要更新的 attributes 在不同 mini page 里面的 offset,对于 variable-length value 来说,如果更新的数据大小超出了 mini page 可用空间,mini page 就会尝试向周围的 mini page 借一点空间。如果邻居也没有额外的空间了,那么这个 record 就会被移到新的 page 上面。Delete 当数据删除的时候,PAX 会在 page 最开始会维护一个 bitmap,用来标记删除的数据。当删除标记越来越多的时候,就可能会影响性能,因为会导致 mini page 里面出现很多 gap,并不能高效的利用 cache。所以 PAX 会定期去对文件重新组织。小结 PAX 其实是一个原理比较简单的东西,但它并没有成为一个业界主流的存储方案,应该有一些局限是我现在还不知道的。但既然 Spanner 敢用,证明在 HTAP 领域,PAX 也是一个可选择的方案,对我们后续 HTAP storage 的技术选型也有一定的指导作用。这里也就先记录一下,也希望能跟这方面有经验的同学多多交流下心得体会。"}, {"url": "https://pingcap.com/blog-cn/grpc-rs/", "title": "gRPC-rs:从 C 到 Rust", "content": " 介绍 在上篇文章中,我们讲到 TiKV 为了支持 gRPC,我们造了个轮子 gRPC-rs,这篇文章简要地介绍一下这个库。首先我们来聊聊什么是 gRPC。gRPC 是 Google 推出的基于 HTTP2 的开源 RPC 框架,希望通过它使得各种微服务之间拥有统一的 RPC 基础设施。它不仅支持常规的平台如 Linux,Windows,还支持移动设备和 IoT,现有十几种语言的实现,现在又多了一种语言 Rust。gRPC 之所以有如此多的语言支持,是因为它有一个 C 写的核心库(gRPC core),因此只要某个语言兼容 C ABI,那么就可以通过封装,写一个该语言的 gRPC 库。Rust 对 C 有良好的支持,gRPC-rs 就是对 gRPC core ABI 的 Rust 封装。Core 能异步处理 RPC 请求,在考虑到 Rust 中已有较为成熟的异步框架 Futures,我们决定将 API 设计成 Future 模式。gRPC-rs 架构图我们将根据架构图从底向上地讲一下,在上一篇文章中已经讨论过传输层和协议,在这就不再赘述。gRPC Core Core 中有几个比较重要的对象: Call 以及 4 种类型 RPC: Call 代表了一次 RPC,可以派生出四种类型 RPC, Unary: 这是最简单的一种 RPC 模式,即一问一答,客户端发送一个请求,服务端返回一个回复,该轮 RPC 结束。 Client streaming: 这类的 RPC 会创建一个客户端到服务端的流,客户端可以通过这个流,向服务端发送多个请求,而服务端只会返回一个回复。 Server streaming: 与上面的类似,不过它会创建一个服务端到客户端的流,服务端可以发送多个回复, Bidirectional streaming: 如果说上面两类是单工,那么这类就是双工了,客户端和服务端可以同时向对方发送消息。 值得一提的是由于 gRPC 基于 HTTP2,它利用了 HTTP2 多路复用特性,使得一个 TCP 连接上可以同时进行多个 RPC,一次 RPC 即为 HTTP2 中的一个 Stream。 Channel: 它是对底层链接的抽象,具体来说一个 Channel 就是一条连着远程服务器的 TCP 链接。 Server: 顾名思义,它就是 gRPC 服务端封装,可以在上面注册我们的服务。 Completion queue: 它是 gRPC 完成事件队列,事件可以是收到新的回复,可以是新来的请求。 简要介绍一下 Core 库的实现,Core 中有一个 Combiner 的概念,Combiner 中一个函数指针或称组合子(Combinator)队列。每个组合子都有特定的功能,通过不同的组合可以实现不同的功能。下面的伪码大概说明了 Combiner 的工作方式。class combiner { mpscq q; // multi-producer single-consumer queue can be made non-blocking state s; // is it empty or executing run(f) { if (q.push(f)) { // q.push returns true if it's the first thing while (q.pop(&f)) { // modulo some extra work to avoid races f(); } } } } Combiner 里面有一个 mpsc 的无锁队列 q,由于 q 只能有一个消费者,这就要求在同一时刻只能有一个线程去调用队列里面的各个函数。调用的入口是 run() 方法,在 run() 中各个函数会被序列地执行。当取完 q 时,该轮调用结束。假设一次 RPC 由六个函数组成,这样的设计使这组函数(RPC)可以在不同的线程上运行,这是异步化 RPC 的基础。Completion queue(以下简称 CQ)就是一个 Combiner,它暴露出了一个 next()借口,相当于 Combiner 的 run()。由于接口的简单,Core 内部不用开启额外线程,只要通过外部不断调用 next() 就能驱动整个 Core。所有的 HTTP2 处理,Client 的 RPC 请求和 Server 的 RPC 连接全是通过一个个组合子的不同组合而构成的。下面是一次 Unary 的代码。它由6个组合子组成,这些组合子作为一个 batch 再加上 Call 用于记录状态,两者构成了这次的 RPC。grpc_call_error grpcwarp_call_start_unary( grpc_call *call, grpcsharp_batch_context *tag) { grpc_op ops[6]; ops[0].op = GRPC_OP_SEND_INITIAL_METADATA; ... ops[1].op = GRPC_OP_SEND_MESSAGE; ... ops[2].op = GRPC_OP_SEND_CLOSE_FROM_CLIENT; ... ops[3].op = GRPC_OP_RECV_INITIAL_METADATA; ... ops[4].op = GRPC_OP_RECV_MESSAGE; ... ops[5].op = GRPC_OP_RECV_STATUS_ON_CLIENT; return grpcwrap_call_start_batch(call, ops, tag); } 用 Rust 封装 Core 介绍完 Core,现在说一下如何用 Rust 封装它。这一层封装并不会产生额外的开销,不像有的语言在调用 C 时会有类型的转换或者 runtime 会有较大开销,在 Rust 中开销微乎其微,这得益于 Rust 用 llvm 做编译器后端,它对 C 有良好的支持,Rust 调用 C ABI 就像调用一个普通的函数,可以做到 Zero-cost。同时用 Rust 封装 C ABI 是一件很简单的事情,简单到像黑魔法。比如封装 CQ next():C:grpc_event grpc_completion_queue_next(grpc_completion_queue *cq, gpr_timespec deadline, void *reserved); Rust:extern "C" { pub fn grpc_completion_queue_next(cq: *mut GrpcCompletionQueue, deadline: GprTimespec, reserved: *mut c_void) -> GrpcEvent; } 接着我们看看如何封装 C 的类型。继续以 next() 为例子:C:// CQ 指针 grpc_completion_queue *cq; // grpc_event 结构体 struct grpc_event { grpc_completion_type type; int success; void *tag; }; Rust:pub enum GrpcCompletionQueue {} #[repr(C)] pub struct GrpcEvent { pub event_type: GrpcCompletionType, pub success: c_int, pub tag: *mut c_void, } CQ 在 Core 的 ABI 中传递的形式是指针,Rust Wraper 无须知道 CQ 具体的内部结构。对于这种情况,Rust 推荐用无成员的枚举体表示,具体好处有两个,第一,由于没有成员,我们无法在 Rust 中构建该枚举体的实例,第二,Type safe,当传递了一个错误类型的指针时编译器会报错。#[repr(C)] 也是 Rust 的黑魔法之一。加上了这个标签的结构体,在内存中的布局和对齐就和 C 一样了,这样的结构体可以安全地传递给 C ABI。Futures in gRPC-rs 经过上一节的封装,我们已经得到了一个可用但是非常裸的 Rust gRPC 库了,grpc-sys。在实践中,我们不推荐直接用 grpc-sys,直接用它就像在 Rust 中写 C 一样,事倍功半,Rust 语言的诸多特性无法得到施展,例如泛型,Trait,Ownership 等,也无法融入 Rust 社区。上面说过 Core 能异步处理 RPC,那么如何用 Rust 来做更好的封装呢? Futures!它是一个成熟的异步编程库,同时有一个活跃的社区。 Futures 非常适用于 RPC 等一些 IO 操作频繁的场景。Futures 中也有组合子概念,和 Core 中的类似,但是使用上更加方便,也更加好理解。举一个栗子:use futures::{future, Future}; fn double(i: i64) -> i64 { i * 2 } let ans = future::ok(1) .map(double) .and_then(|i| Ok(40 + i)); println!("{:?}", ans.wait().unwrap()); 你觉得输出的答案是多少呢?没错就是 42。在 Core 那节说过不同的组合子组织在一起可以干不同的事,在 Future 中我们可以这么理解,一件事可以分成多个步骤,每个步骤由一个组合子完成。比如上例,map 完成了翻倍的动作,and_then 将输入加上 40。 现在来看看 gRPC-rs 封装的 API。// helloworld.proto service Greeter { // An unary RPC, sends a greeting rpc SayHello (HelloRequest) returns (HelloReply) {} } impl GreeterClient { pub fn say_hello_async(&self, req: HelloRequest) -> ClientUnaryReceiver<HelloReply> { self.client.unary_call_async(&METHOD_GREETER_SAY_HELLO, req, CallOption::default()) } ... } 以 helloworld.proto 为例,GreeterClient::say_hello_async() 向远程 Server 发送一个请求 (HelloRequest),Server 返回给一个结果 (HelloReply)。由于是异步操作,这个函数会立即返回,返回的 ClientUnaryReceiver 实现了 Future,当它完成时就会得到 HelloReply。在一般的异步编程中都会有 Callback,用于处理异步的返回值,在这个 RPC 中就是 HelloReply,在 Future 中可以用组合子来写,比如 and_then,再举一个栗子,现有一次完整的 RPC 逻辑,拿到回复后打印到日志。下面就是 gRPC-rs 的具体用法。// 同步 let resp = client.say_hello(req); println!("{:?}", resp); // 异步 let f = client.say_hello_async(req) .and_then(|resp| { println!("{:?}", resp); Ok(()) }); executer.spawn(f); // 类似 Combiner, // 用于异步执行 Future, // 常用的有 tokio-core。 Unary RPC gRPC-rs 根据 service 在 proto 文件中的定义生成对应的代码,包括 RPC 方法的定义(Method)、客户端和服务端代码,生成的代码中会使用 gRPC-rs 的 API。那么具体是怎么做的呢?这节还是以 helloworld.proto 为例,来讲讲客户端 Unary RPC 具体的实现。首先,SayHello 的 Method 记录了 RPC 类型,全称以及序列化反序列化函数。为什么要序列化反序列化函数呢?因为 Core 本身不涉及消息的序列化,这一部分交由封装层解决。在生成的客户端中可以会调用 gRPC-rs 的 API,根据 Method 的定义发起 RPC。// 生成的代码 const METHOD_GREETER_SAY_HELLO: Method<HelloRequest, HelloReply> = Method { ty: MethodType::Unary, name: "/helloworld.Greeter/SayHello", req_mar: Marshaller { ser: pb_ser, de: pb_de }, resp_mar: Marshaller { ser: pb_ser, de: pb_de }, }; impl GreeterClient { // An unary RPC, sends a greeting pub fn say_hello_async(&self, req: HelloRequest) -> ClientUnaryReceiver<HelloReply> { self.client.unary_call_async(&METHOD_GREETER_SAY_HELLO, req) } ... } // gRPC-rs 的 API。该函数立即返回,不会等待 RPC 完成。省略部分代码。 pub fn unary_async<P, Q>(channel: &Channel, method: &Method<P, Q>, req: P) -> ClientUnaryReceiver<Q> { let mut payload = vec![]; (method.req_ser())(&req, &mut payload); // 序列化消息 let call = channel.create_call(method, &opt); // 新建 Call let cq_f = unsafe { grpc_sys::grpcwrap_call_start_unary(call.call, // 发起 RPC payload, tag) }; ClientUnaryReceiver::new(call, cq_f, method.resp_de()) // 收到回复后再反序列化 } 写在最后 这篇简单介绍了 gRPC Core 的实现和 gRPC-rs 的封装,详细的用法,在这就不做过多介绍了,大家如果感兴趣可以查看 examples。 gRPC-rs 深入使用了 Future,里面有很多神奇的用法,比如 Futures in gRPC-rs 那节最后的 executer, gRPC-rs 利用 CQ 实现了一个能并发执行 Future 的 executer(类似 furtures-rs 中的 Executer),大幅减少 context switch,性能得到了显著提升。如果你对 gRPC 和 rust 都很感兴趣,欢迎参与开发,目前还有一些工作没完成,详情请点击 https://github.com/pingcap/grpc-rs参考资料:gRPC open-source universal RPC frameworkThe rust language implementation of gRPCHypertext Transfer Protocol Version 2 (HTTP/2) Zero-cost Futures in Rust[深入了解 gRPC:协议][上一篇文章]gRPC, Combiner ExplanationRust, Representing opaque structsRust repr(), alternative representationsgRPC - A solution for RPCs by GoogleTokio, A platform for writing fast networking code with Rust."}, {"url": "https://pingcap.com/weekly/2017-07-17-tidb-weekly/", "title": "Weekly update (July 10 ~ July 16, 2017)", "content": " Weekly update in TiDB Last week, we landed 51 PRs in the TiDB repositories.Added Support setting variables with ON and OFF. Support show stats_histgrams and show stats_buckets for debugging. Support the Scan API for the raw KV interface. Support the Show Charset statement. Support user name without quotes such as root@127.0.0.1. Fixed Fix a bug when explicitly inserting the null value into columns with the timestamp type. Do not check privileges for the information_schema database. Correct the error message for the authentication error. Fix a bug in the cast function with an unsigned type. Improved Refactor optimizer: Select Join operator by CBO framework automatically: #3623, #3737, #3761 Use statsProfile to estimate count and cardinality. Refactor the builtin function evaluation framework: left & right lower & upper concat_ws to_base64 md5 space replace substring/substr compare uuid bit_length log10 Move the type inference work from typeinfer to expression rewritter: aggregate expression, column & constant expression Close the connection after sending ERR_Packet. Improve the unit test coverage for parser packages. Weekly update in TiKV Last week, We landed 23 PRs in the TiKV repositories.Added Add json_modify, math function evaluators for the coprocessor. Pass the compression type to generate snapshot SST. Set 256 MB as the default region size. Add the raw Scan API. Fixed Ignore the command that removes the leader itself. Fix diff hint overflow. Rotate PD log by default. Fix the leap second problem in Go 1.9. Clean up stale metadata when start. Improved Reduce the lock scope for region heartbeat. Send the raft messages in batch. Refactor the coprocessor code directory. Enable the pipelined write. Remove unnecessary hash group keys. "}, {"url": "https://pingcap.com/blog-cn/reconstruct-built-in-function-report/", "title": "十分钟成为 Contributor 系列 | 重构内建函数进度报告", "content": " 6 月 22 日,TiDB 发布了一篇如何十分钟成为 TiDB Contributor 系列的第二篇文章,向大家介绍如何为 TiDB 重构 built-in 函数。截止到目前,得到了来自社区的积极支持与热情反馈,TiDB 参考社区 contributors 的建议,对计算框架进行了部分修改以降低社区同学参与的难度。本文完成以下2 项工作,希望帮助社区更好的参与进 TiDB 的项目中来: 对尚未重写的 built-in 函数进行陈列 对继上篇文章后,计算框架所进行的修改,进行详细介绍 一. 尚未重写的 built-in 函数陈列如下: 共计 165 个 在 expression 目录下运行 grep -rn "^tbaseBuiltinFunc$" -B 1 * | grep "Sig struct {" | awk -F "Sig" '{print $1}' | awk -F "builtin" '{print $3}' > ~/Desktop/func.txt 命令可以获得所有未实现的 built-in 函数 0 1 2 3 4 Coalesce Uncompress Log10 Default UnaryOp Greatest UncompressedLength Rand InetAton IsNull Least ValidatePasswordStrength Pow InetNtoa In Interval Database Round Inet6Aton Row CaseWhen FoundRows Conv Inet6Ntoa SetVar If CurrentUser CRC32 IsFreeLock GetVar IfNull User Sqrt IsIPv4 Values NullIf ConnectionID Arithmetic IsIPv4Prefixed BitCount AesDecrypt LastInsertID Acos IsIPv6 Reverse AesEncrypt Version Asin IsUsedLock Convert Compress Benchmark Atan MasterPosWait Substring Decode Charset Cot NameConst SubstringIndex DesDecrypt Coercibility Exp ReleaseAllLocks Locate DesEncrypt Collation PI UUID Hex Encode RowCount Radians UUIDShort UnHex Encrypt Regexp Truncate AndAnd Trim OldPassword Abs Sleep OrOr LTrim RandomBytes Ceil Lock LogicXor RTrim SHA1 Floor ReleaseLock BitOp Rpad SHA2 Log AnyValue IsTrueOp BitLength Char Format FromDays DayOfWeek Timestamp CharLength FromBase64 Hour DayOfYear AddTime FindInSet InsertFunc Minute Week ConvertTz Field Instr Second WeekDay MakeTime MakeSet LoadFile MicroSecond WeekOfYear PeriodAdd Oct Lpad Month Year PeriodDiff Quote Date MonthName YearWeek Quarter Bin DateDiff Now FromUnixTime SecToTime Elt TimeDiff DayName GetFormat SubTime ExportSet DateFormat DayOfMonth StrToDate TimeFormat UTCTim ToSeconds TimestampDiff DateArith Extract UnixTimestamp UTCTimestamp UTCDate Time CurrentTime ToDays TimestampAdd TimeToSec CurrentDate SysDate 二. 计算框架进行的修改: 此处依然使用 Length 函数( expression/builtin_string.go )为例进行说明,与前文采取相同目录结构:1. expression/builtin_string.go(1)lengthFunctionClass.getFunction() 方法: 简化类型推导实现getFunction 方法用来生成 built-in 函数对应的函数签名,在构造 ScalarFunction 时被调用func (c *lengthFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) { // 此处简化类型推导过程,对 newBaseBuiltinFuncWithTp() 实现进行修改,新的实现中,传入 Length 返回值类型 tpInt 表示返回值类型为 int,参数类型 tpString 表示返回值类型为 string bf, err := newBaseBuiltinFuncWithTp(args, ctx, tpInt, tpString) if err != nil { return nil, errors.Trace(err) } // 此处参考 MySQL 实现,设置返回值长度为 10(character length) // 对于 int/double/decimal/time/duration 类型返回值,已在 newBaseBuiltinFuncWithTp() 中默认调用 types.setBinChsClnFlag() 方法,此处无需再进行设置 bf.tp.Flen = 10 sig := &builtinLengthSig{baseIntBuiltinFunc{bf}} return sig.setSelf(sig), errors.Trace(c.verifyArgs(args)) } 注: 对于返回值类型为 string 的函数,需要,注意参考 MySQL 行为设置bf.tp.[charset | collate | flag] 查看 MySQL 行为可以通过在终端启动$ mysql -uroot --column-type-info,这样对于每一个查询语句,可以查看每一列详细的 metadata 对于返回值类型为 string 的函数,以 concat 为例,当存在类型为 string 且包含 binary flag 的参数时,其返回值也应设置 binary flag 对于返回值类型为 Time 的函数,需要注意,根据函数行为,设置bf.tp.Tp = [ TypeDate | TypeDatetime | TypeTimestamp ] , 若为 TypeDate/ TypeDatetime,还需注意推导 bf.tp.Decimal (即小数位数) 不确定性的函数: 0 1 2 3 4 5 Rand ConnectionID CurrentUser User Database RowCount Schema FoundRows LastInsertId Version Sleep UUID GetVar SetVar Values SessionUser SystemUser (2)实现 builtinLengthSig.evalInt() 方法:保持不变,此处请注意修改该函数的注释 (s/ eval/ evalXXX)2. expression/builtin_string_test.gofunc (s *testEvaluatorSuite) TestLength(c *C) { defer testleak.AfterTest(c)() cases := []struct { args interface{} expected int64 isNil bool getErr bool }{ ...... } for _, t := range cases { f, err := newFunctionForTest(s.ctx, ast.Length, primitiveValsToConstants([]interface{}{t.args})...) c.Assert(err, IsNil) d, err := f.Eval(nil) // 注意此处不再对 LENGTH 函数的返回值类型进行测试,相应测试被移动到 plan/typeinfer_test.go/TestInferType 函数中,(注意不是expression/typeinferer_test.go) if t.getErr { c.Assert(err, NotNil) } else { c.Assert(err, IsNil) if t.isNil { c.Assert(d.Kind(), Equals, types.KindNull) } else { c.Assert(d.GetInt64(), Equals, t.expected) } } } // 测试函数是否具有确定性 // 在 review 社区的 PRs 过程中发现,这个测试经常会被遗漏,烦请留意 f, err := funcs[ast.Length].getFunction([]Expression{Zero}, s.ctx) c.Assert(err, IsNil) c.Assert(f.isDeterministic(), IsTrue) } 3. executor/executor_test.go与上一篇文章保持不变,需要注意的是,为了保证可读性, TestStringBuiltin() 方法仅对 expression/builtin_string.go 文件中的 built-in 函数进行测试。如果 executor_test.go 文件中不存在对应的 TestXXXBuiltin() 方法,可以新建一个对应的测试函数。4. plan/typeinfer_test.gofunc (s *testPlanSuite) TestInferType(c *C) { .... tests := []struct { sql string tp byte chs string flag byte flen int decimal int }{ ... // 此处添加对 length 函数返回值类型的测试 // 此处注意,对于返回值类型、长度等受参数影响的函数,此处测试请尽量覆盖全面 {"length(c_char, c_char)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag, 10, 0}, ... } for _, tt := range tests { ... } } 注:当有多个 PR 同时在该文件中添加测试时,若有别的 contributor 的 PR 先于自己的 PR merge 进 master,有可能会发生冲突,此时在本地 merge 一下 master 分支,解决一下再 push 一下即可。成为 New Contributor 赠送限量版马克杯的活动还在继续中,任何一个新加入集体的小伙伴都将收到我们充满了诚意的礼物,很荣幸能够认识你,也很高兴能和你一起坚定地走得更远。成为 New Contributor 获赠限量版马克杯,马克杯获取流程如下: 提交 PR PR提交之后,请耐心等待维护者进行 Review。 目前一般在一到两个工作日内都会进行 Review,如果当前的 PR 堆积数量较多可能回复会比较慢。 代码提交后 CI 会执行我们内部的测试,你需要保证所有的单元测试是可以通过的。期间可能有其它的提交会与当前 PR 冲突,这时需要修复冲突。 维护者在 Review 过程中可能会提出一些修改意见。修改完成之后如果 reviewer 认为没问题了,你会收到 LGTM(looks good to me) 的回复。当收到两个及以上的 LGTM 后,该 PR 将会被合并。 合并 PR 后自动成为 Contributor,会收到来自 PingCAP Team 的感谢邮件,请查收邮件并填写领取表单 表单填写地址:http://cn.mikecrm.com/01wE8tX 后台 AI 核查 GitHub ID 及资料信息,确认无误后随即便快递寄出属于你的限量版马克杯 期待你分享自己参与开源项目的感想和经验,TiDB Contributor Club 将和你一起分享开源的力量 了解更多关于 TiDB 的资料请登陆我们的官方网站:https://pingcap.com加入 TiDB Contributor Club 请添加我们的 AI 微信:"}, {"url": "https://pingcap.com/blog/2017-07-11-tidbinternal1/", "title": "TiDB Internal (I) - Data Storage", "content": " From Li SHEN: shenli@pingcap.com Table of Content Foreword Storing data Key-Value RocksDB Raft Region MVCC Transaction Miscellaneous Foreword: Database, operating system and compiler are known as the three big systems and regarded as the footstone of the whole computer software. Among them, database supports the businesses and is closer to the application layer. After decades of development, progress keeps emerging in this field.Many people must have used databases of different kinds, but few have the experience of developing one, especially a distributed database. Knowing the principle and detail of implementing a database helps to advance one’s skill level, which is good for building other systems, and is also helpful to make better use of database.I believe the best way to work on a technology is to dive deeply into an open source project of the field. Database is no exception. There are many good open source projects in the field of a standalone database. Among them, MySQL and PostgreSQL are the most famous and many people must have read their source code. However, in terms of distributed database, there are not many good open source projects and TiDB is one of the few. Many people, especially technophiles, hope to participate in this project. However, due to the complexity of distributed database, lots of people find it hard to understand the whole project. Therefore, I plan to write several articles to illustrate the technical principle of TiDB, including the technique that users can see as well as numerous invisible ones behind the SQL interface.This is the first of our series of articles.Back to the topStoring data I’d like to begin with the most fundamental function of a database – storing data. There are lots of ways to store data and the easiest one is building a data structure in the memory to store data sent by users. For example, use an array to store data and add a new entry to the array when receiving a piece of data. This solution is simple, meets the basic needs and has good performance. But its drawback outweighs the advantages. The biggest problem is that as all data is stored in the memory, if the server stops or restarts, data would get lost.To achieve data persistence, we can store data in the non-volatile storage medium, disk for example. We create a file on disk and append a new record to the file when receiving data. This is a durable storage solution. But this is not enough. What if the disk is broken? To avoid the bad track of a disk, we can use RAID (Redundant Array of Independent Disks) for standalone redundant storage. However, what if the entire machine goes down? What if there is an outbreak of fire? RAID is no safe house. Another solution is to store data in the network or use hardware or software for storage and replication. But the problem is how to guarantee the consistency between replicas. Securing the intactness and correctness of data is the basic requirement, the following problems are far more demanding: Does the database support disaster recovery of multi-datacenter? Is the write speed fast enough? Is it convenient to read data when data is stored? How to update the stored data? How does it deal with the concurrent revision? How to revise multiple records atomically? All these problems are difficult to solve. But an excellent database storage system must be able to deal with each and every one of them.For this, we have developed TiKV. Now, I want to share with you the design philosophy and basic concept of TiKV.As we are talking about TiKV, I hope you can forget any concept about SQL and focus on how to implement TiKV, a huge distributed ordered Map that is of high performance and reliability.Back to the topKey-Value A data storage system should, first and foremost, determine the store model of data. In other words, in which format should the data be stored. TiKV chooses the Key-Value model and offers a solution to traverse orderly. To put it simply: you can see TiKV as a huge Map where Key and Value are the original Byte array. In this Map, Key is arranged in a comparison order according to the raw binary bit of the byte array.The following points need to be kept in mind: This is a huge Map of Key-Value pairs. In this Map, Key-Value pairs are ordered according to the Key’s binary sequence. We can Seek the position of a Key, and use the Next method to other Key-Value pairs, and these Key-Value pairs are all bigger than this one. You might wonder the relation between the storage model that I’m talking about and the table in SQL. Here, I want to highlight: they are irrelevant.RocksDB Any durable storage engine stores data on disk and TiKV is no exception. But TiKV doesn’t write data to disk directly. Instead, it stores data in RocksDB and then RocksDB is responsible for the data storage. The reason is that it costs a lot to develop a standalone storage engine, especially a high-performance standalone engine. You need to do all kinds of detailed optimization. Fortunately, we found that RocksDB is an excellent open source standalone storage engine that meets all of our requirements. Besides, as the Facebook team keeps optimizing it, we can enjoy a powerful and advancing standalone engine without investing much effort. But of course we contribute a few lines of code to RocksDB and we hope that this project would get better. In a word, you can regard RocksDB as a standalone Key-Value Map.Back to the topRaft Finding an effective, reliable and local storage solution is the important first step of this complex project. Now we are facing with a more difficult thing: how to secure the intactness and correctness of data when a single machine fails? A good way is to replicate data to multiple machines. Then, when one machine crashes, we have replicas on other machines. But it is noted that the replicate solution should be reliable, effective and can deal with the situation of an invalid replica. It sounds difficult but Raft makes it possible. Raft is a consensus algorithm and an equivalent to Paxos while Raft is easier to understand. Those who are interested in Raft can refer to this paper for more details. I want to point out that the Raft paper only presents a basic solution and the performance would be bad if strictly follow the paper. We have made numerous optimizations to implement Raft and for more detail, please refer to this blog written by our Chief Architect, Tang Liu.Raft is a consensus algorithm and offers three important functions: Leader election Membership change Log replication TiKV uses Raft to replicate data and each data change will be recorded as a Raft log. Through the log replication function of Raft, data is safely and reliably synchronized to multiple nodes of the Raft group.In summary, through the standalone RocksDB, we can store data on a disk rapidly; through Raft, we can replicate data to multiple machines in case of machine failure. Data is written through the interface of Raft instead of to RocksDB. Thanks to the implementation of Raft, we have a distributed Key-Value and no longer need to worry about machine failure.Back to the topRegion In this section, I want to introduce a very important concept: Region. It is the foundation to comprehend a series of mechanism.Before we begin, let’s forget about Raft and try to picture that all the data only has one replica. As I mentioned earlier, TiKV is seen as a huge but ordered Key-Value Map. To implement the horizontal scalability of storage, we need to distribute data among multiple machines. For a Key-Value system, there are two typical solutions to distribute data among multiple machines. One is to create Hash and select the corresponding storage node according to the Hash value; the other is to use Range and store a segment of serial Key in a storage node. TiKV chose the second solution and divided the whole Key-Value space into many segments. Each segment consists of a series of adjacent Key and we call such segment “Region”. …"}, {"url": "https://pingcap.com/blog/2017-07-11-tidbinternal2/", "title": "TiDB Internal (II) - Computing", "content": " From Li SHEN: shenli@pingcap.comTable of Content Mapping the Relational Model to the Key-Value Model Metadata Management Architecture of SQL on Key-Value SQL Computing Distributed SQL Operation Architecture of the SQL Layer Summary My last blog introduces the way that TiDB stores data, which is also the basic concepts of TiKV. In this article, I’ll elaborate on how TiDB uses the bottom layer Key-Value to store data, maps the relational model to the Key-Value model and performs SQL computing.Mapping the Relational Model to the Key-Value Model Let’s simplify the Relational Model to be just about Table and the SQL statements. What we need to think about is how to store Table and run the SQL statements on top of the Key-Value structure.Assuming we have a Table as follows:CREATE TABLE User { ID int, Name varchar(20), Role varchar(20), Age int, PRIMARY KEY (ID), Key idxAge (age) }; Given the huge differences between the SQL and Key-Value structures, how to map SQL to Key-Value conveniently and efficiently becomes vital. The article will, first of all, go through the requirements and characteristics of data computing, which is essential to determine whether a mapping solution is good or not.A Table contains three parts of data: Metadata about the table Rows in the Table Index data Note that metadata will not be discussed in this article.Data can be stored either in rows or in columns, both have their advantages and disadvantages. The primary goal for TiDB is online transactional processing (OLTP), which supports read, save, update, and delete a row of data quickly. Therefore, row store seems better.TiDB supports both the Primary Index and Secondary Index. The function of Index is for faster query, higher query performance, and the Constraints. There are two forms of query: Point query, which uses equivalent conditions such as Primary Key or Unique Key for a query, e.g. select name from user where id=1;, locating a certain row of data through index. Range query, e.g. select name from user where age > 30 and age < 35;, querying the data that the age is between 30 and 35 through idxAge. There are two types of Indexes: Unique Index and Non-unique Index, both of which are supported by TiDB. After analyzing the characteristics of the data to be stored, let’s move on to what we need to do to manipulate the data, including the Insert/Update/Delete/Select statements. The Insert statement writes Row into Key-Value and creates the index data. The Update statement updates Row and index data if necessary. The Delete statement deletes both Row and index. Among the four, the Select statement deals with the most complicated situation: Reading a row of data easily and quickly. In this case, each Row needs to have an ID (explicit or implicit). Continuously reading multiple rows of data, such as Select * from user;. Reading data through index, leveraging the index either in Point query or Range query. A globally ordered and distributed Key-Value engine satisfies the above needs. The feature of being globally ordered helps us solve quite a few problems. Take the following as two examples: To get a row of data quickly. Assume that we can create a certain or some Keys, when locating this row, we’d be able to use the Seek method provided by TiKV to quickly locate this row of data. To scan the whole table. If the table can be mapped to the Range of Key, then all data can be got by scanning from StartKey to EndKey. The way to manipulate Index data is similar. Back to the topNow let’s see how this works in TiDB.TiDB allocates a TableID to each table, an IndexID to each index, and a RowID to each row. If the table has an integer Primary Key, then the value will be used as the RowID. The TableID is unique in the whole cluster while the IndexID/RowID unique in the table. All of these ID are int64. Each row of data is encoded into a Key-Value pair according to the following rule:Key: tablePrefix_rowPrefix_tableID_rowID Value: [col1, col2, col3, col4] The tablePrefix/rowPrefix of the Key are specific string constants and used to differentiate other data in the Key-Value space. Index data is encoded into a Key-Value pair according to the following rule: Key: tablePrefix_idxPrefix_tableID_indexID_indexColumnsValue Value: rowIDThe above encoding rule applies to Unique Index while it cannot create a unique Key for Non-unique Index. The reason is that the tablePrefix_idxPrefix_tableID_indexID_ of an Index is the same. It’s possible that the ColumnsValue of multiple rows is also the same. Therefore, we’ve made some changes to encode the Non-unique Index:Key: tablePrefix_idxPrefix_tableID_indexID_ColumnsValue_rowID Value:null In this way, the unique Key of each row of data can be created. In the above rules, all xxPrefix of the Keys are string constants with the function of differentiating the namespace to avoid the conflict between different types of data.var( tablePrefix = []byte{'t'} recordPrefixSep = []byte("_r") indexPrefixSep = []byte("_i") ) Note that the Key encoding solution of either Row or Index has the same prefix. Specifically speaking, all Rows in a Table has the same prefix, so does data of Index. These data with the same prefix is arranged together in the Key space of TiKV. In other words, we just need to carefully design the encoding solution of the suffix, ensuing the comparison relation remains unchanged, then Row or Index data can be stored in TiKV orderly. The solution of maintaining the relation unchanged before and after encoding is called Memcomparable. As for any type of value, the comparison result of two objects before encoding is consistent with that of the byte array after encoding (Note: both Key and Value of TiKV are the primitive byte array). For more detailed information, please refer to the codec package of TiDB. When adopting this encoding solution, all Row data of a table will be arranged in the Key space of TiKV according to the RowID order. So will the data of a certain Index, according to the ColumnValue order of Index.Back to the topNow we take the previous requirements and TiDB’s mapping solution into consideration and verify the feasibility of the solution. Firstly, we transform Row and Index data into Key-Value data through the mapping solution and make sure that each row and each piece of index data has a unique Key. Secondly, we can easily create the corresponding Key of some row or some piece of index by using this mapping solution as it is good for both Point query and Range query. Lastly, when ensuring some Constraints in the table, we can create and check the existence of a certain Key to determine whether the corresponding Constraint has been satisfied. Up to now, we’ve already covered how to map Table onto Key-Value. Here is one more case with the same table structure. Assume that the table has three rows of data:1, "TiDB", "SQL Layer", 10 2, "TiKV", "KV Engine", 20 3, "PD", "Manager", 30 First, each row of data will be mapped as a Key-Value pair. As this table has an Int Primary Key, the value of RowID is the value of this Primary Key. Assume that the TableID of this table is 10, its Row data is:t_r_10_1 --> ["TiDB", "SQL Layer", 10] t_r_10_2 --> ["TiKV", "KV Engine", 20] t_r_10_3 --> ["PD", "Manager", 30] In addition to Primary Key, this table also has an Index. Assume that the ID of Index is 1, its data is:t_i_10_1_10_1 —> null t_i_10_1_20_2 --> null t_i_10_1_30_3 --> null The previous encoding rules help you to understand the above example. We hope that you can realize the reason why we chose this mapping solution and the purpose of doing so.Back to the topMetadata Management After explaining how data and index of a table is mapped to Key-Value, this section introduces the storage of metadata.Both Database and Table have metadata, which refers to its definition and various attributes. …"}, {"url": "https://pingcap.com/blog-cn/tidb-best-practice/", "title": "TiDB Best Practice", "content": " 本文档用于总结在使用 TiDB 时候的一些最佳实践,主要涉及 SQL 使用、OLAP/OLTP 优化技巧,特别是一些 TiDB 专有的优化开关。 建议先阅读讲解 TiDB 原理的三篇文章(讲存储,说计算,谈调度),再来看这篇文章。前言 数据库是一个通用的基础组件,在开发过程中会考虑到多种目标场景,在具体的业务场景中,需要根据业务的实际情况对数据的参数或者使用方式进行调整。TiDB 是一个兼容 MySQL 协议和语法的分布式数据库,但是由于其内部实现,特别是支持分布式存储以及分布式事务,使得一些使用方法和 MySQL 有所区别。基本概念 TiDB 的最佳实践与其实现原理密切相关,建议读者先了解一些基本的实现机制,包括 Raft、分布式事务、数据分片、负载均衡、SQL 到 KV 的映射方案、二级索引的实现方法、分布式执行引擎。下面会做一点简单的介绍,更详细的信息可以参考 PingCAP 公众号以及知乎专栏的一些文章。Raft Raft 是一种一致性协议,能提供强一致的数据复制保证,TiDB 最底层用 Raft 来同步数据。每次写入都要写入多数副本,才能对外返回成功,这样即使丢掉少数副本,也能保证系统中还有最新的数据。比如最大 3 副本的话,每次写入 2 副本才算成功,任何时候,只丢失一个副本的情况下,存活的两个副本中至少有一个具有最新的数据。相比 Master-Slave 方式的同步,同样是保存三副本,Raft 的方式更为高效,写入的延迟取决于最快的两个副本,而不是最慢的那个副本。所以使用 Raft 同步的情况下,异地多活成为可能。在典型的两地三中心场景下,每次写入只需要本数据中心以及离得近的一个数据中心写入成功就能保证数据的一致性,而并不需要三个数据中心都写成功。但是这并不意味着在任何场景都能构建跨机房部署的业务,当写入量比较大时候,机房之间的带宽和延迟成为关键因素,如果写入速度超过机房之间的带宽,或者是机房之间延迟过大,整个 Raft 同步机制依然无法很好的运转。分布式事务 TiDB 提供完整的分布式事务,事务模型是在 Google Percolator 的基础上做了一些优化。具体的实现大家可以参考这篇文章。这里只说两点: 乐观锁TiDB 的事务模型采用乐观锁,只有在真正提交的时候,才会做冲突检测,如果有冲突,则需要重试。这种模型在冲突严重的场景下,会比较低效,因为重试之前的操作都是无效的,需要重复做。举一个比较极端的例子,就是把数据库当做计数器用,如果访问的并发度比较高,那么一定会有严重的冲突,导致大量的重试甚至是超时。但是如果访问冲突并不十分严重,那么乐观锁模型具备较高的效率。所以在冲突严重的场景下,推荐在系统架构层面解决问题,比如将计数器放在 Redis 中。 事务大小限制由于分布式事务要做两阶段提交,并且底层还需要做 Raft 复制,如果一个事务非常大,会使得提交过程非常慢,并且会卡住下面的 Raft 复制流程。为了避免系统出现被卡住的情况,我们对事务的大小做了限制: 单条 KV entry 不超过 6MB KV entry 的总条数不超过 30W KV entry 的总大小不超过 100MB 在 Google 的 Cloud Spanner 上面,也有类似的限制。 数据分片 TiKV 自动将底层数据按照 Key 的 Range 进行分片。每个 Region 是一个 Key 的范围,从 StartKey 到 EndKey 的左闭右开区间。Region 中的 Key-Value 总量超过一定值,就会自动分裂。这部分用户不需要担心。负载均衡 PD 会根据整个 TiKV 集群的状态,对集群的负载进行调度。调度是以 Region 为单位,以 PD 配置的策略为调度逻辑,自动完成。SQL on KV TiDB 自动将 SQL 结构映射为 KV 结构。具体的可以参考这篇文档。简单来说,TiDB 做了两件事: 一行数据映射为一个 KV,Key 以 TableID 构造前缀,以行 ID 为后缀 一条索引映射为一个 KV,Key 以 TableID+IndexID 构造前缀,以索引值构造后缀 可以看到,对于一个表中的数据或者索引,会具有相同的前缀,这样在 TiKV 的 Key 空间内,这些 Key-Value 会在相邻的位置。那么当写入量很大,并且集中在一个表上面时,就会造成写入的热点,特别是连续写入的数据中某些索引值也是连续的(比如 update time 这种按时间递增的字段),会再很少的几个 Region 上形成写入热点,成为整个系统的瓶颈。同样,如果所有的数据读取操作也都集中在很小的一个范围内 (比如在连续的几万或者十几万行数据上),那么可能造成数据的访问热点。Secondary Index TiDB 支持完整的二级索引,并且是全局索引,很多查询可以通过索引来优化。如果利用好二级索引,对业务非常重要,很多 MySQL 上的经验在 TiDB 这里依然适用,不过 TiDB 还有一些自己的特点,需要注意,这一节主要讨论在 TiDB 上使用二级索引的一些注意事项。 二级索引是否越多越好 二级索引能加速查询,但是要注意新增一个索引是有副作用的,在上一节中我们介绍了索引的存储模型,那么每增加一个索引,在插入一条数据的时候,就要新增一个 Key-Value,所以索引越多,写入越慢,并且空间占用越大。另外过多的索引也会影响优化器运行时间,并且不合适的索引会误导优化器。所以索引并不是越多越好。 对哪些列建索引比较合适上面提到,索引很重要但不是越多越好,我们需要根据具体的业务特点创建合适的索引。原则上我们需要对查询中需要用到的列创建索引,目的是提高性能。下面几种情况适合创建索引: 区分度比较大的列,通过索引能显著地减少过滤后的行数 有多个查询条件时,可以选择组合索引,注意需要把等值条件的列放在组合索引的前面 这里举一个例子,假设常用的查询是 select * from t where c1 = 10 and c2 = 100 and c3 > 10, 那么可以考虑建立组合索引 Index cidx (c1, c2, c3),这样可以用查询条件构造出一个索引前缀进行 Scan。 通过索引查询和直接扫描 Table 的区别TiDB 实现了全局索引,所以索引和 Table 中的数据并不一定在一个数据分片上,通过索引查询的时候,需要先扫描索引,得到对应的行 ID,然后通过行 ID 去取数据,所以可能会涉及到两次网络请求,会有一定的性能开销。如果查询涉及到大量的行,那么扫描索引是并发进行,只要第一批结果已经返回,就可以开始去取 Table 的数据,所以这里是一个并行 + Pipeline 的模式,虽然有两次访问的开销,但是延迟并不会很大。有两种情况不会涉及到两次访问的问题: 索引中的列已经满足了查询需求。比如 Table t 上面的列 c 有索引,查询是 select c from t where c > 10;,这个时候,只需要访问索引,就可以拿到所需要的全部数据。这种情况我们称之为覆盖索引(Covering Index)。所以如果很关注查询性能,可以将部分不需要过滤但是需要在查询结果中返回的列放入索引中,构造成组合索引,比如这个例子: select c1, c2 from t where c1 > 10;,要优化这个查询可以创建组合索引 Index c12 (c1, c2)。 表的 Primary Key 是整数类型。在这种情况下,TiDB 会将 Primary Key 的值当做行 ID,所以如果查询条件是在 PK 上面,那么可以直接构造出行 ID 的范围,直接扫描 Table 数据,获取结果。 查询并发度数据分散在很多 Region 上,所以 TiDB 在做查询的时候会并发进行,默认的并发度比较保守,因为过高的并发度会消耗大量的系统资源,且对于 OLTP 类型的查询,往往不会涉及到大量的数据,较低的并发度已经可以满足需求。对于 OLAP 类型的 Query,往往需要较高的并发度。所以 TiDB 支持通过 System Variable 来调整查询并发度。 tidb_distsql_scan_concurrency在进行扫描数据的时候的并发度,这里包括扫描 Table 以及索引数据。 tidb_index_lookup_size如果是需要访问索引获取行 ID 之后再访问 Table 数据,那么每次会把一批行 ID 作为一次请求去访问 Table 数据,这个参数可以设置 Batch 的大小,较大的 Batch 会使得延迟增加,较小的 Batch 可能会造成更多的查询次数。这个参数的合适大小与查询涉及的数据量有关。一般不需要调整。 tidb_index_lookup_concurrency如果是需要访问索引获取行 ID 之后再访问 Table 数据,每次通过行 ID 获取数据时候的并发度通过这个参数调节。 通过索引保证结果顺序索引除了可以用来过滤数据之外,还能用来对数据排序,首先按照索引的顺序获取行 ID,然后再按照行 ID 的返回顺序返回行的内容,这样可以保证返回结果按照索引列有序。前面提到了扫索引和获取 Row 之间是并行 + Pipeline 模式,如果要求按照索引的顺序返回 Row,那么这两次查询之间的并发度设置的太高并不会降低延迟,所以默认的并发度比较保守。可以通过 tidb_index_serial_scan_concurrency 变量进行并发度调整。 逆序索引目前 TiDB 支持对索引进行逆序 Scan,但是速度要比顺序 Scan 慢 5 倍左右,所以尽量避免对索引的逆序 Scan。 场景与实践 上一节我们讨论了一些 TiDB 基本的实现机制及其对使用带来的影响,本节我们从具体的使用场景出发,谈一些更为具体的操作实践。我们以从部署到支撑业务这条链路为序,进行讨论。部署 在部署之前请务必阅读 TiDB 部署建议以及对硬件的需求。推荐通过 TiDB-Ansible 部署 TiDB 集群,这个工具可以部署、停止、销毁、升级整个集群,非常方便易用。具体的使用文档在这里。非常不推荐手动部署,后期的维护和升级会很麻烦。导入数据 如果有 Unique Key 并且业务端可以保证数据中没有冲突,可以在 Session 内打开这个开关: SET @@session.tidb_skip_constraint_check=1;另外为了提高写入性能,可以对 TiKV 的参数进行调优,具体的文档在这里。请特别注意这个参数:[raftstore] # 默认为 true,表示强制将数据刷到磁盘上。如果是非金融安全级别的业务场景,建议设置成 false, # 以便获得更高的性能。 sync-log = true 写入 上面提到了 TiDB 对单个事务的大小有限制,这层限制是在 KV 层面,反映在 SQL 层面的话,简单来说一行数据会映射为一个 KV entry,每多一个索引,也会增加一个 KV entry,所以这个限制反映在 SQL 层面是: 单行数据不大于 6MB 总的行数*(1 + 索引个数) < 30W 一次提交的全部数据小于 100MB 注意:无论是大小限制还是行数限制,还要考虑 TiDB 做编码以及事务额外 Key 的开销,在使用的时候,建议每个事务的行数不超过 200 行,且单行数据小于 100k,否则可能性能不佳。 建议无论是 Insert,Update 还是 Delete 语句,都通过分 Batch 或者是加 Limit 的方式限制。在删除大量数据的时候,建议使用 Delete * from t where xx limit 5000; 这样的方案,通过循环来删除,用 Affected Rows == 0 作为循环结束条件,这样避免遇到事务大小的限制。如果一次删除的数据量非常大,这种循环的方式会越来越慢,因为每次删除都是从前向后遍历,前面的删除之后,短时间内会残留不少删除标记(后续会被 gc 掉),影响后面的 Delete 语句。如果有可能,建议把 Where 条件细化。举个例子,假设要删除 2017-05-26 当天的所有数据,那么可以这样做:for i from 0 to 23: while affected_rows > 0: delete * from t where insert_time >= i:00:00 and insert_time < (i+1):00:00 limit 5000; affected_rows = select affected_rows() 上面是一段伪代码,意思就是要把大块的数据拆成小块删除,以避免删除过程中前面的 Delete 语句影响后面的 Delete 语句。查询 看业务的查询需求以及具体的语句,可以参考这篇文档 可以通过 SET 语句控制 SQL 执行的并发度,另外通过 Hint 控制 Join 物理算子选择。另外 MySQL 标准的索引选择 Hint 语法,也可以用,通过 Use Index/Ignore Index hint 控制优化器选择索引。如果是个 OLTP 和 OLAP 混合类型的业务,可以把 TP 请求和 AP 请求发送到不同的 tidb-server 上,这样能够减小 AP 业务对于 TP 业务的影响。 承载 AP 业务的 tidb-server 推荐使用高配的机器,比如 CPU 核数比较多,内存比较大。监控 & 日志 Metrics 系统是了解系统状态的最佳方法,建议所有的用户都部署监控系统。TiDB 使用 Grafana+Prometheus 监控系统状态,如果使用 TiDB-Ansible 部署集群,那么会自动部署和配置监控系统。监控系统中的监控项很多,大部分是给 TiDB 开发者查看的内容,如果没有对源代码比较深入的了解,并没有必要了解这些监控项。我们会精简出一些和业务相关或者是系统关键组件状态相关的监控项,放在一个独立的面板中,供用户使用。除了监控之外,查看日志也是了解系统状态的常用方法。TiDB 的三个组件 tidb-server/tikv-server/pd-server 都有一个 --log-file 的参数,如果启动的时候设置了这个参数,那么日志会保存着参数所设置的文件的位置,另外会自动的按天对 Log 文件做归档。如果没有设置 --log-file 参数,日志会输出在 stderr 中。文档 了解一个系统或者解决使用中的问题最好的方法是阅读文档,明白实现原理,TiDB 有大量的官方文档,希望大家在遇到问题的时候能先尝试通过文档或者搜索 Issue list 寻找解决方案。官方文档在这里。如果希望阅读英文文档,可以看这里。其中的 FAQ 和故障诊断章节建议大家仔细阅读。另外 TiDB 还有一些不错的工具,也有配套的文档,具体的见各项工具的 GitHub 页面。除了文档之外,还有很多不错的文章介绍 TiDB 的各项技术细节内幕,大家可以关注下面这些文章发布渠道: 公众号:微信搜索 PingCAP 知乎专栏:TiDB 的后花园 官方博客 TiDB 的最佳适用场景 简单来说,TiDB 适合具备下面这些特点的场景: 数据量大,单机保存不下 不希望做 Sharding 或者懒得做 Sharding 访问模式上没有明显的热点 需要事务、需要强一致、需要灾备 "}, {"url": "https://pingcap.com/weekly/2017-07-04-tidb-weekly/", "title": "Weekly update (June 26 ~ July 02, 2017)", "content": " Weekly update in TiDB Last week, we landed 33 PRs in the TiDB repositories.Added Support priority options in the select statement. Add the GetOwnerID interface in OwnerManager. Add some columns in mysql.db: Make it compatible with MySQL. Add the IsolationLevel option in the coprocessor request to TiKV. Add the priority option in Key-Value request to TiKV. Support the RenameTable statement without the To keyword. Fixed Fix a bug in the update statement like update T set a = 8, b = a. Consider the timezone information when using current_timestamp as the default value. Break the campaigning owner loop when closing a DDL worker. Check the validity of table name in the CreateTable statement. Handle the null argument in substr function. Disable concurrent pre-write when meeting the SkipConstrainCheck option. Handle binary data in the HEX function and the unhex function. Return ErrNoDB (No database selected) when no database is used and the table name is without database qualifier. Improved Refactor optimiser: Prune ordered column paths. Prepare for using the new CBO framework. Flatten the row operations. Log critical statements. Code clean up. New contributor sempr JackDrogon Zhang JianWeekly update in TiKV Last week, We landed 12 PRs in the TiKV repositories.Added Use the bi-directional stream for PD region heartbeat. Add the selection executor for coprocessor. Support the read committed isolation level for transactions. Add the modify function for JSON document. Fixed Use Equal to check parsed timestamp. Fix the heartbeat tests. Improved Generate snapshot concurrently. Skip handling read only commands in the Raft apply worker. Upgrade Rust Protobuf to the 1.4 version. "}, {"url": "https://pingcap.com/meetup/meetup-2017-07-01/", "title": "【Infra Meetup No.51】百度统一分布式计算框架 Bigflow (内附 PPT 下载链接)", "content": " 今天的 Meetup,我们邀请到了滴滴地图事业部专家工程师王聪老师,为大家分享《百度统一分布式计算框架 Bigflow 》。 讲师介绍:王聪,滴滴地图事业部专家工程师,前百度基础架构部工程师,主要工作方向为分布式计算与流式计算,在百度负责计算表示层 Bigflow 与流式计算引擎 Flink。活动现场听得很专注的小伙伴们,桑拿天也阻止不了大家的学习热情。王聪老师首先展示了分布式计算在百度的发展例程,他介绍百度在 2003 年建立了自己的分布式搜索系统。08 年引入 hadoop,09 年底搭建了大规模的机器学习平台,当时用的是 MPI。10 年百度自研了两套流式计算引擎,主要用来完成点击流与展现流的 join。基于多引擎并存、跨引擎成本高、升级困难这几个痛点,最终开发了一款叫做 Bigflow 的计算框架,Bigflow 希望用户使用我们提供的 API 写代码,Bigflow 将作业进行计划的优化和翻译,并提交到计算引擎之上。对于这样的思路,有一种说法“计算机领域的任何问题,都可以通过增加一个额外的中间层来解决”。在这里 Bigflow 就是架在用户与引擎之间的中间层。以下是新鲜出炉的 PPT 节选,尽情享用~附:完整 PPT 链接 PingCAP Infra Meetup作为一个基础架构领域的前沿技术公司,PingCAP 希望能为国内真正关注技术本身的 Hackers 打造一个自由分享的平台。自 2016 年 3 月 5 日开始,我们定期在周六的上午举办 Infra Meetup,邀请业内大牛与大家深度探讨基础架构领域的前瞻性技术思考与经验。在这里,我们希望提供一个高水准的前沿技术讨论空间,让大家真正感受到自由的开源精神魅力。 "}, {"url": "https://pingcap.com/blog/2017-06-27-refactor-builtin/", "title": "Refactoring the Built-in Functions in TiDB", "content": " In order to accelerate expression evaluation, we recently refactored its framework. This tutorial will show you how to use the new computational framework to rewrite or add a built-in function in TiDB.Table of Content The overall process Example Take a look at builtin_string.go Refine the existing TestLength() method Test the implementation of LENGTH at the SQL level Before refactoring… After refactoring… Appendix The overall process Select any function to your interest from the expression directory, assuming the function is named XX. Override the XXFunctionClass.getFunction() method:This method refers to MySQL rules, inferring the return value type according to the parameter of the built-in function.Different function signatures will be generated based on the number & type of the parameters, and the return value type of the function. See detailed description of the function signature in the appendix at the end of this article. Implement the evalYY() method on all the function signatures corresponding to the built-in function. YY represents the return value type of the function signature. Add tests in the expression directory, refine tests about the implementation of the given function in the TestXX() method. In the executor directory, add tests at the SQL level. Run make dev and ensure that all the test cases pass. Example: Let’s look at the PR of overriding the LENGTH () function for detailed explanation:Take a look at expression/builtin_string.go: First, let’s take a look at the expression/builtin_string.go file: Implement the lengthFunctionClass.getFunction() method. This method mainly accomplishes two tasks:1). Infer the return value type of the LEGNTH function according to MySQL rules.2). Generate function signature based on the number & type of parameters, and return value type of the LENGTH function. Because the LENGTH function only has one number & type of parameters, and return value type, we don’t need to define a type for the new function signature. Instead, we modified the existing builtinLengthSig, so that it could be composite with baseIntBuiltinFunc, which means that the return value type in the given function signature is int.type builtinLengthSig struct { baseIntBuiltinFunc } func (c *lengthFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) { //Infer the return value type of `LEGNTH` function according to MySQL rules tp := types.NewFieldType(mysql.TypeLonglong) tp.Flen = 10 types.SetBinChsClnFlag(tp) //Generate function signature based on the number & type of parameters, and return value type. Note that after refactoring, instead of the `newBaseBuiltinFunc` method, the `newBaseBuiltinFuncWithTp` method is used here. //In the `newBaseBuiltinFuncWithTp` function declaration, `args` represents the function's parameters, `tp` represents the return value type of the function, and `argsTp` represents the correct types of all parameters in the function signature. // The number of parameters for `LENGTH` is 1, the parameter type is string, and the return value type is int. Therefore, `tp` here stands for the return value type of the function and `tpString` is used to identify the correct type of parameter. For a function with multiple parameters, when calling `newBaseBuiltinFuncWithTp`, we need to input the correct types of all parameters. bf, err := newBaseBuiltinFuncWithTp(args, tp, ctx, tpString) if err != nil { return nil, errors.Trace(err) } sig := &builtinLengthSig{baseIntBuiltinFunc{bf}} return sig.setSelf(sig), errors.Trace(c.verifyArgs(args)) } Implement the builtinLengthSig.evalInt() method:func (b *builtinLengthSig) evalInt(row []types.Datum) (int64, bool, error) { // For the `builtinLengthSig` function signature, the parameter type is decided as string, so we can directly call the `b.args[0].EvalString()` method to calculate the parameter: val, isNull, err := b.args[0].EvalString(row, b.ctx.GetSessionVars().StmtCtx) if isNull || err != nil { return 0, isNull, errors.Trace(err) } return int64(len([]byte(val))), false, nil } Back to the topRefine the existing TestLength() method: Moving on to expression/builtin_string_test.go, let’s refine the existing TestLength() method:func (s *testEvaluatorSuite) TestLength(c *C) { defer testleak.AfterTest(c)() // This line is used to monitor goroutine leak. // You can use the following cases to test the `LENGTH` function // Note: in addition to normal cases, it is best to add some abnormal cases, such as the input args is nil, or the function has different types of parameters. cases := []struct { args interface{} expected int64 isNil bool getErr bool }{ {"abc", 3, false, false}, {"你好", 6, false, false}, {1, 1, false, false}, ... } for _, t := range cases { f, err := newFunctionForTest(s.ctx, ast.Length, primitiveValsToConstants([]interface{}{t.args})...) c.Assert(err, IsNil) // The following lines test the return value type of the `LENGTH` function: tp := f.GetType() c.Assert(tp.Tp, Equals, mysql.TypeLonglong) c.Assert(tp.Charset, Equals, charset.CharsetBin) c.Assert(tp.Collate, Equals, charset.CollationBin) c.Assert(tp.Flag, Equals, uint(mysql.BinaryFlag)) c.Assert(tp.Flen, Equals, 10) // The following lines test the evaluation result of LENGTH function: d, err := f.Eval(nil) if t.getErr { c.Assert(err, NotNil) } else { c.Assert(err, IsNil) if t.isNil { c.Assert(d.Kind(), Equals, types.KindNull) } else { c.Assert(d.GetInt64(), Equals, t.expected) } } } // The following lines test whether the function has determinacy: f, err := funcs[ast.Length].getFunction([]Expression{Zero}, s.ctx) c.Assert(err, IsNil) c.Assert(f.isDeterministic(), IsTrue) } Back to the topTest the implementation of LENGTH at the SQL level Finally let’s look at executor/executor_test.go and test the implementation of LENGTH at the SQL level:// Tests for string built-in functions can be added in the following method: func (s *testSuite) TestStringBuiltin(c *C) { defer func() { s.cleanEnv(c) testleak.AfterTest(c)() }() tk := testkit.NewTestKit(c, s.store) tk.MustExec("use test") // for length // It’s best that these tests can also cover different scenarios: tk.MustExec("drop table if exists t") tk.MustExec("create table t(a int, b double, c datetime, d time, e char(20), f bit(10))") tk.MustExec(`insert into t values(1, 1.1, "2017-01-01 12:01:01", "12:01:01", "abcdef", 0b10101)`) result := tk.MustQuery("select length(a), length(b), length(c), length(d), length(e), length(f), length(null) from t") result.Check(testkit.Rows("1 3 19 8 6 2 <nil>")) } Before refactoring… TiDB abstracts the expression through the Expression interface (defined in the expression/expression.go file) and defines the eval method to evaluate the expression:type Expression interface{ ... eval(row []types.Datum) (types.Datum, error) ... } Expressions that implement the Expression interface include: Scalar Function Column Constant The case below shows the framework of expression evaluation before refactoring:create table t ( c1 int, c2 varchar(20), c3 double ) select * from t where c1 + CONCAT( c2, c3 < “1.1” ) About the where condition in the select statement shown above:In the compiling phase. TiDB will build an expression tree as shown in the graph below:In the executing phase, the eval method of the root node is called, and the expression is evaluated by the following traversal expression tree.The evaluate the < expression, take the types of the two parameters into account, and convert the values of the two parameters into required data types according to certain rules. In the expression tree above, the parameter types are double and varchar. According to the evaluation rules of MySQL, these two parameters need to be compared using the float type. Therefore, “1.1” should be converted to double type, and then be evaluated.Similarly, for …"}, {"url": "https://pingcap.com/weekly/2017-06-26-tidb-weekly/", "title": "Weekly update (June 19 ~ June 25, 2017)", "content": " Weekly update in TiDB Last week, we landed 35 PRs in the TiDB repositories.Added JSON type: Tiny cleanup. Fix a bug in JSON path_expr. Fix a bug in unquote. Make json_unquote compatiable with MySQL Code cleanup. Fixed Fix failed test cases on the ppc64le platform Fix a bug when naming table with the auto_increment column. Use UTC time to compose index key for timestamp column. Consider fsp for MySQLDuration type in some scenarios. Reset transaction when error occurs during retrying. Fix a bug about adding index after adding column with default value. Suport time format ‘YY-MM-DD HH:MM’. Fix the issue of parsing datetime 00-00-00. Improved Refactor the expression evaluation: Rewrite concat with new expression framework. Remove the inferType inerface of functionClass. Rewrite the length built-in function with the new expression framework. Wrap arguments when building new built-in functions. Rewrite the makedate built-in function with the new expression framework. Change the result format of the aggregation operator. Refactor range related code: #3489, #3496 Code style cleanup:#3502, #3505 Handle out-of-range data in the load local file command. Remove the TiDBSkipDDLWait variable. New contributor dreamqusterWeekly update in TiKV Last week, We landed 24 PRs in the TiKV repositories.Added Use individual thread to handle high priority command. Support JSON type. Support the json_type, unquote, extract, json_merge functions for JSON. Add the TOPN, limit executors for coprocessor. Fixed Handling GC command in tombstone tests. Print readable message if the RocksDB configuration parsing fails. Improved Split different JSON modules into independent files. Revise leader lease time log. Remove sever thread and directly send Raft messages to the gRPC thread. Remove unnecessary read_quorum and uuid fields. "}, {"url": "https://pingcap.com/blog-cn/flame-graph/", "title": "工欲性能调优,必先利其器(2)- 火焰图", "content": " 在前一篇文章,我们简单提到了 perf,实际 perf 能做的事情远远不止这么少,这里就要好好介绍一下,我们在 TiKV 性能调优上面用的最多的工具 - 火焰图。火焰图,也就是 FlameGraph,是超级大牛 Brendan Gregg 捣鼓出来的东西,主要就是将 profile 工具生成的数据进行可视化处理,方便开发人员查看。我第一次知道火焰图,应该是来自 OpenResty 的章亦春介绍,大家可以详细去看看这篇文章动态追踪技术漫谈。之前,我的所有工作在很长一段时间几乎都是基于 Go 的,而 Go 原生提供了很多相关的 profile 工具,以及可视化方法,所以我没怎么用过火焰图。但开始用 Rust 开发 TiKV 之后,我就立刻傻眼了,Rust 可没有官方的工具来做这些事情,怎么搞?自然,我们就开始使用火焰图了。使用火焰图非常的简单,我们仅仅需要将代码 clone 下来就可以了,我通常喜欢将相关脚本扔到 /opt/FlameGraph 下面,后面也会用这个目录举例说明。一个简单安装的例子:wget https://github.com/brendangregg/FlameGraph/archive/master.zip unzip master.zip sudo mv FlameGraph-master/ /opt/FlameGraph CPU 对于 TiKV 来说,性能问题最开始关注的就是 CPU,毕竟这个是一个非常直观的东西。当我们发现 TiKV CPU 压力很大的时候,通常会对 TiKV 进行 perf,如下:perf record -F 99 -p tikv_pid -g -- sleep 60 perf script > out.perf 上面,我们对一个 TiKV 使用 99 HZ 的频繁采样 60 s,然后生成对应的采样文件。然后我们生成火焰图:/opt/FlameGraph/stackcollapse-perf.pl out.perf > out.folded /opt/FlameGraph/flamegraph.pl out.folded > cpu.svg 上面就是生成的一个 TiKV 火焰图,我们会发现 gRPC 线程主要开销在 c gRPC core 上面,而这个也是现在 c gRPC core 大家普遍反映的一个问题,就是太费 CPU,但我相信凭借 Google gRPC team 的实力,这问题应该能够搞定。另外,在 gRPC 线程上面,我们可以发现,protobuf 的编解码也占用了很多 CPU,这个也是现阶段 rust protobuf 库的一个问题,性能比较差,但幸好后面的办法有一个优化,我们准备马上采用。另外,还需要注意,raftstore 线程主要的开销在于 RocksDB 的 Get 和 Write,对于 TiKV 来说,如果 raftstore 线程出现了瓶颈,那么整个 Raft 流程都会被拖慢,所以自然这个线程就是我们的重点优化对象。可以看到,Get 的开销其实就是我们拿到 Raft 的 committed entries,然后扔给 apply Raft log 线程去异步 apply,所以自然这一步 Get 自然能扔到 apply worker 去处理。另外,对于 Write,鉴于 Raft log 的格式,我们可以非常方便的使用 RocksDB 一个 insert_with_hint 特性来优化,或者将 Write 也放到另一个线程去 async 处理。可以看到,我们通过火焰图,能够非常方便的发现 CPU 大部分时间开销都消耗在哪里,也就知道如何优化了。这里在说一下,大家通常喜欢将目光定在 CPU 消耗大头的地方,但有时候一些小的不起眼的地方,也需要引起大家的注意。这里并不是这些小地方会占用多少 CPU,而是要问为啥会在火焰图里面出现,因为按照正常逻辑是不可能的。我们通过观察 CPU 火焰图这些不起眼的小地方,至少发现了几处代码 bug。Memory 通常大家用的最多的是 CPU 火焰图,毕竟这个最直观,但火焰图可不仅仅只有 CPU 的。我们还需要关注除了 CPU 之外的其他指标。有一段时间,我对 TiKV 的内存持续上涨问题一直很头疼,虽然 TiKV 有 OOM,但总没有很好的办法来定位到底是哪里出了问题。于是也就研究了一下 memory 火焰图。要 profile TiKV 的 memory 火焰图,其实我们就需要监控 TiKV 的 malloc 分配,只要有 malloc,就表明这时候 TiKV 在进行内存分配。因为 TiKV 是自己内部使用了 jemalloc,并没有用系统的 malloc,所以我们不能直接用 perf 来探查系统的 malloc 函数。幸运的是,perf 能支持动态添加探针,我们将 TiKV 的 malloc 加入:perf probe -x /deploy/bin/tikv-server -a malloc 然后采样生成火焰图:perf record -e probe_tikv:malloc -F 99 -p tikv_pid -g -- sleep 10 perf script > out.perf /opt/FlameGraph/stackcollapse-perf.pl out.perf > out.folded /opt/FlameGraph/flamegraph.pl --colors=mem out.folded > mem.svg 上面是生成的一个 malloc 火焰图,我们可以看到,大部分的内存开销仍然是在 RocksDB 上面。通过 malloc 火焰图,我们曾发现过 RocksDB 的 ReadOption 在非常频繁的调用分配,后面准备考虑直接在 stack 上面分配,不过这个其实对性能到没啥太大影响 😓 。除了 malloc,我们也可以 probe minor page fault 和 major page fault,因为用 pidstat 观察发现 TiKV 很少有 major page fault,所以我们只 probe 了 minor,如下:perf record -e minor-faults -F 99 -p $1 -g -- sleep 10 perf script > out.perf /opt/FlameGraph/stackcollapse-perf.pl out.perf > out.folded /opt/FlameGraph/flamegraph.pl --colors=mem out.folded > minflt.svg Off CPU 有时候,我们还会面临一个问题。系统的性能上不去,但 CPU 也很闲,这种的很大可能都是在等 IO ,或者 lock 这些的了,所以我们需要看到底 CPU 等在什么地方。对于 perf 来说,我们可以使用如下方式采样 off CPU。perf record -e sched:sched_stat_sleep -e sched:sched_switch -e sched:sched_process_exit -p tikv_pid -g -o perf.data.raw sleep 10 perf inject -v -s -i perf.data.raw -o perf.data 但不幸的是,上面的代码在 Ubuntu 或者 CentOS 上面通常都会失败,主要是现在最新的系统为了性能考虑,并没有支持 sched statistics。 对于 Ubuntu,貌似只能重新编译内核,而对于 CentOS,只需要安装 kernel debuginfo,然后在打开 sched statistics 就可以了,如下:dnf install kernel-debug kernel-debug-devel kernel-debug-debuginfo echo 1 | sudo tee /proc/sys/kernel/sched_schedstats 然后生成 off cpu 火焰图:perf script -F comm,pid,tid,cpu,time,period,event,ip,sym,dso,trace | awk ' NF > 4 { exec = $1; period_ms = int($5 / 1000000) } NF > 1 && NF <= 4 && period_ms > 0 { print $2 } NF < 2 && period_ms > 0 { printf "%sn%dnn", exec, period_ms }' | /opt/FlameGraph/stackcollapse.pl | /opt/FlameGraph/flamegraph.pl --countname=ms --title="Off-CPU Time Flame Graph" --colors=io > offcpu.svg 上面就是 TiKV 一次 off CPU 的火焰图,可以发现只要是 server event loop 和 time monitor 两个线程 off CPU 比较长,server event loop 是等待外部的网络请求,因为我在 perf 的时候并没有进行压力测试,所以 wait 是正常的。而 time monitor 则是 sleep 一段时间,然后检查时间是不是出现了 jump back,因为有长时间的 sleep,所以也是正常的。上面我说到,对于 Ubuntu 用户,貌似只能重新编译内核,打开 sched statistics,如果不想折腾,我们可以通过 systemtap 来搞定。systemtap 是另外一种 profile 工具,其实应该算另一门语言了。我们可以直接使用 OpenResty 的 systemtap 工具,来生成 off CPU 火焰图,如下:wget https://raw.githubusercontent.com/openresty/openresty-systemtap-toolkit/master/sample-bt-off-cpu chmod +x sample-bt-off-cpu ./sample-bt-off-cpu -t 10 -p 13491 -u > out.stap /opt/FlameGraph/stackcollapse-stap.pl out.stap > out.folded /opt/FlameGraph/flamegraph.pl --colors=io out.folded > offcpu.svg 可以看到,使用 systemptap 的方式跟 perf 没啥不一样,但 systemtap 更加复杂,毕竟它可以算是一门语言。而 FlameGraph 里面也自带了 systemaptap 相关的火焰图生成工具。Diff 火焰图 除了通常的几种火焰图,我们其实还可以将两个火焰图进行 diff,生成一个 diff 火焰图,如下:/opt/difffolded.pl out.folded1 out.folded2 | ./flamegraph.pl > diff2.svg 但现在我仅仅只会生成,还没有详细对其研究过,这里就不做过多说明了。总结 上面简单介绍了我们在 TiKV 里面如何使用火焰图来排查问题,现阶段主要还是通过 CPU 火焰图发现了不少问题,但我相信对于其他火焰图的使用研究,后续还是会很有帮助的。"}, {"url": "https://pingcap.com/blog-cn/reconstruct-built-in-function/", "title": "十分钟成为 Contributor 系列 | 为 TiDB 重构 built-in 函数", "content": " 这是十分钟成为 TiDB Contributor 系列的第二篇文章,让大家可以无门槛参与大型开源项目,感谢社区为 TiDB 带来的贡献,也希望参与 TiDB Community 能为你的生活带来更多有意义的时刻。为了加速表达式计算速度,最近我们对表达式的计算框架进行了重构,这篇教程为大家分享如何利用新的计算框架为 TiDB 重写或新增 built-in 函数。对于部分背景知识请参考这篇文章,本文将首先介绍利用新的表达式计算框架重构 built-in 函数实现的流程,然后以一个函数作为示例进行详细说明,最后介绍重构前后表达式计算框架的区别。重构 built-in 函数整体流程 在 TiDB 源码 expression 目录下选择任一感兴趣的函数,假设函数名为 XX 重写 XXFunctionClass.getFunction() 方法 该方法参照 MySQL 规则,根据 built-in 函数的参数类型推导函数的返回值类型 根据参数的个数、类型、以及函数的返回值类型生成不同的函数签名,关于函数签名的详细介绍见文末附录 实现该 built-in 函数对应的所有函数签名的 evalYY() 方法,此处 YY 表示该函数签名的返回值类型 添加测试: 在 expression 目录下,完善已有的 TestXX() 方法中关于该函数实现的测试 在 executor 目录下,添加 SQL 层面的测试 运行 make dev,确保所有的 test cast 都能跑过 示例 这里以重写 LENGTH() 函数的 PR 为例,进行详细说明首先看 expression/builtin_string.go:(1)实现 lengthFunctionClass.getFunction() 方法该方法主要完成两方面工作: 参照 MySQL 规则推导 LEGNTH 的返回值类型 根据 LENGTH 函数的参数个数、类型及返回值类型生成函数签名。由于 LENGTH 的参数个数、类型及返回值类型只存在确定的一种情况,因此此处没有定义新的函数签名类型,而是修改已有的 builtinLengthSig,使其组合了 baseIntBuiltinFunc(表示该函数签名返回值类型为 int) type builtinLengthSig struct { baseIntBuiltinFunc } func (c *lengthFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) { // 参照 MySQL 规则,对 LENGTH 函数返回值类型进行推导 tp := types.NewFieldType(mysql.TypeLonglong) tp.Flen = 10 types.SetBinChsClnFlag(tp) // 根据参数个数、类型及返回值类型生成对应的函数签名,注意此处与重构前不同,使用的是 newBaseBuiltinFuncWithTp 方法,而非 newBaseBuiltinFunc 方法 // newBaseBuiltinFuncWithTp 的函数声明中,args 表示函数的参数,tp 表示函数的返回值类型,argsTp 表示该函数签名中所有参数对应的正确类型 // 因为 LENGTH 的参数个数为1,参数类型为 string,返回值类型为 int,因此此处传入 tp 表示函数的返回值类型,传入 tpString 用来标识参数的正确类型。对于多个参数的函数,调用 newBaseBuiltinFuncWithTp 时,需要传入所有参数的正确类型 bf, err := newBaseBuiltinFuncWithTp(args, tp, ctx, tpString) if err != nil { return nil, errors.Trace(err) } sig := &builtinLengthSig{baseIntBuiltinFunc{bf}} return sig.setSelf(sig), errors.Trace(c.verifyArgs(args)) } (2) 实现 builtinLengthSig.evalInt() 方法func (b *builtinLengthSig) evalInt(row []types.Datum) (int64, bool, error) { // 对于函数签名 builtinLengthSig,其参数类型已确定为 string 类型,因此直接调用 b.args[0].EvalString() 方法计算参数 val, isNull, err := b.args[0].EvalString(row, b.ctx.GetSessionVars().StmtCtx) if isNull || err != nil { return 0, isNull, errors.Trace(err) } return int64(len([]byte(val))), false, nil } 然后看 expression/builtin_string_test.go,对已有的 TestLength() 方法进行完善:func (s *testEvaluatorSuite) TestLength(c *C) { defer testleak.AfterTest(c)() // 监测 goroutine 泄漏的工具,可以直接照搬 // cases 的测试用例对 length 方法实现进行测试 // 此处注意,除了正常 case 之外,最好能添加一些异常的 case,如输入值为 nil,或者是多种类型的参数 cases := []struct { args interface{} expected int64 isNil bool getErr bool }{ {"abc", 3, false, false}, {"你好", 6, false, false}, {1, 1, false, false}, ... } for _, t := range cases { f, err := newFunctionForTest(s.ctx, ast.Length, primitiveValsToConstants([]interface{}{t.args})...) c.Assert(err, IsNil) // 以下对 LENGTH 函数的返回值类型进行测试 tp := f.GetType() c.Assert(tp.Tp, Equals, mysql.TypeLonglong) c.Assert(tp.Charset, Equals, charset.CharsetBin) c.Assert(tp.Collate, Equals, charset.CollationBin) c.Assert(tp.Flag, Equals, uint(mysql.BinaryFlag)) c.Assert(tp.Flen, Equals, 10) // 以下对 LENGTH 函数的计算结果进行测试 d, err := f.Eval(nil) if t.getErr { c.Assert(err, NotNil) } else { c.Assert(err, IsNil) if t.isNil { c.Assert(d.Kind(), Equals, types.KindNull) } else { c.Assert(d.GetInt64(), Equals, t.expected) } } } // 以下测试函数是否是具有确定性 f, err := funcs[ast.Length].getFunction([]Expression{Zero}, s.ctx) c.Assert(err, IsNil) c.Assert(f.isDeterministic(), IsTrue) } 最后看 executor/executor_test.go,对 LENGTH 的实现进行 SQL 层面的测试:// 关于 string built-in 函数的测试可以在这个方法中添加 func (s *testSuite) TestStringBuiltin(c *C) { defer func() { s.cleanEnv(c) testleak.AfterTest(c)() }() tk := testkit.NewTestKit(c, s.store) tk.MustExec("use test") // for length // 此处的测试最好也能覆盖多种不同的情况 tk.MustExec("drop table if exists t") tk.MustExec("create table t(a int, b double, c datetime, d time, e char(20), f bit(10))") tk.MustExec(`insert into t values(1, 1.1, "2017-01-01 12:01:01", "12:01:01", "abcdef", 0b10101)`) result := tk.MustQuery("select length(a), length(b), length(c), length(d), length(e), length(f), length(null) from t") result.Check(testkit.Rows("1 3 19 8 6 2 <nil>")) } 重构前的表达式计算框架 TiDB 通过 Expression 接口(在 expression/expression.go 文件中定义)对表达式进行抽象,并定义 eval 方法对表达式进行计算:type Expression interface{ ... eval(row []types.Datum) (types.Datum, error) ... } 实现 Expression 接口的表达式包括: Scalar Function:标量函数表达式 Column:列表达式 Constant:常量表达式 下面以一个例子说明重构前的表达式计算框架。例如:create table t ( c1 int, c2 varchar(20), c3 double ) select * from t where c1 + CONCAT( c2, c3 < “1.1” ) 对于上述 select 语句 where 条件中的表达式: 在编译阶段,TiDB 将构建出如下图所示的表达式树:在执行阶段,调用根节点的 eval 方法,通过后续遍历表达式树对表达式进行计算。对于表达式 ‘<’,计算时需要考虑两个参数的类型,并根据一定的规则,将两个参数的值转化为所需的数据类型后进行计算。上图表达式树中的 ‘<’,其参数类型分别为 double 和 varchar,根据 MySQL 的计算规则,此时需要使用浮点类型的计算规则对两个参数进行比较,因此需要将参数 “1.1” 转化为 double 类型,而后再进行计算。同样的,对于上图表达式树中的表达式 CONCAT,计算前需要将其参数分别转化为 string 类型;对于表达式 ‘+’,计算前需要将其参数分别转化为 double 类型。因此,在重构前的表达式计算框架中,对于参与运算的每一组数据,计算时都需要大量的判断分支重复地对参数的数据类型进行判断,若参数类型不符合表达式的运算规则,则需要将其转换为对应的数据类型。此外,由 Expression.eval() 方法定义可知,在运算过程中,需要通过 Datum 结构不断地对中间结果进行包装和解包,由此也会带来一定的时间和空间开销。为了解决这两点问题,我们对表达式计算框架进行重构。##重构后的表达式计算框架 重构后的表达式计算框架,一方面,在编译阶段利用已有的表达式类型信息,生成参数类型“符合运算规则”的表达式,从而保证在运算阶段中无需再对类型增加分支判断;另一方面,运算过程中只涉及原始类型数据,从而避免 Datum 带来的时间和空间开销。继续以上文提到的查询为例,在编译阶段,生成的表达式树如下图所示,对于不符合函数参数类型的表达式,为其加上一层 cast 函数进行类型转换;这样,在执行阶段,对于每一个 ScalarFunction,可以保证其所有的参数类型一定是符合该表达式运算规则的数据类型,无需在执行过程中再对参数类型进行检查和转换。附录 对于一个 built-in 函数,由于其参数个数、类型以及返回值类型的不同,可能会生成多个函数签名分别用来处理不同的情况。对于大多数 built-in 函数,其每个参数类型及返回值类型均确定,此时只需要生成一个函数签名。 对于较为复杂的返回值类型推导规则,可以参考 CONCAT 函数的实现和测试。可以利用 MySQLWorkbench 工具运行查询语句 select funcName(arg0, arg1, ...) 观察 MySQL 的 built-in 函数在传入不同参数时的返回值数据类型。 在 TiDB 表达式的运算过程中,只涉及 6 种运算类型(目前正在实现对 JSON 类型的支持),分别是 int (int64) real (float64) decimal string Time Duration 通过 WrapWithCastAsXX() 方法可以将一个表达式转换为对应的类型。 对于一个函数签名,其返回值类型已经确定,所以定义时需要组合与该类型对应的 baseXXBuiltinFunc,并实现 evalXX() 方法。(XX 不超过上述 6 种类型的范围) —————————- 我是 AI 的分割线 —————————————-回顾三月启动的《十分钟成为 TiDB Contributor 系列 | 添加內建函数》活动,在短短的时间内,我们收到了来自社区贡献的超过 200 条新建內建函数,这之中有很多是来自大型互联网公司的资深数据库工程师,也不乏在学校或是刚毕业在刻苦钻研分布式系统和分布式数据库的学生。TiDB Contributor Club 将大家聚集起来,我们互相分享、讨论,一起成长。感谢你的参与和贡献,在开源的道路上我们将义无反顾地走下去,和你一起。成为 New Contributor 赠送限量版马克杯的活动还在继续中,任何一个新加入集体的小伙伴都将收到我们充满了诚意的礼物,很荣幸能够认识你,也很高兴能和你一起坚定地走得更远。成为 New Contributor 获赠限量版马克杯,马克杯获取流程如下: 提交 PR PR提交之后,请耐心等待维护者进行 Review。 目前一般在一到两个工作日内都会进行 Review,如果当前的 PR 堆积数量较多可能回复会比较慢。 代码提交后 CI 会执行我们内部的测试,你需要保证所有的单元测试是可以通过的。期间可能有其它的提交会与当前 PR 冲突,这时需要修复冲突。 维护者在 Review 过程中可能会提出一些修改意见。修改完成之后如果 reviewer 认为没问题了,你会收到 LGTM(looks good to me) 的回复。当收到两个及以上的 LGTM 后,该 PR 将会被合并。 合并 PR 后自动成为 Contributor,会收到来自 PingCAP Team 的感谢邮件,请查收邮件并填写领取表单 表单填写地址:http://cn.mikecrm.com/01wE8tX 后台 AI 核查 GitHub ID 及资料信息,确认无误后随即便快递寄出属于你的限量版马克杯 期待你分享自己参与开源项目的感想和经验,TiDB Contributor Club 将和你一起分享开源的力量 了解更多关于 TiDB 的资料请登陆我们的官方网站:https://pingcap.com加入 TiDB Contributor Club 请添加我们的 AI 微信:"}, {"url": "https://pingcap.com/weekly/2017-06-20-tidb-weekly/", "title": "Weekly update (June 12 ~ June 18, 2017)", "content": " Weekly update in TiDB Last week, we landed 30 PRs in the TiDB repositories.Added Refactor the optimizer: Refactor ranger/statistic: calculate the range and row count of non pk column. JSON type: Support generated column:](https://github.com/pingcap/tidb/pull/3431) Support the JSON type in the cast expression. Generated column: Support basic generated column. Prevent modifying generated column. Add GeneratedExpr in ColumnInfo. Support using clause in join statement. Use GetTSAsync api from pd-client. Support SubTime. Fixed Fix a bug in alter table statement. Fix a bug in cast. Fix a bug about parsing Duration literal. Fix a divide zero bug in statistic. Fix a protobuf unmarshal related bug in coprocessor. Fix a bug about auto_increment column conflict after renaming table. Improved Add some columns in mysql.user: compatiable with MySQL. Use multiple grpc connnections for each store: improve performance. Refactor expression evaluation: Consider unsigned flag in cast expression. Speed up DDL process: Revoke the etcd-session when ddl worker is closed. Weekly update in TiKV Last week, We landed 14 PRs in the TiKV repositories.Added Coprocessor supports index scan executor. Add MySQL JSON type. Support comparison for mySQL JSON type. * Fixed Fix a bug caused by GC with stale command. Improved Increase initialized window size to 2MB for gRPC stream. Using prefix_same_as_start to optimize seek for Write CF. Use multiple connections to speed up Raft message sending. Update Dockerfile, see 1915 and 1919. New contributor AkihiroSuda "}, {"url": "https://pingcap.com/blog-cn/grpc/", "title": "深入了解 gRPC:协议", "content": " 经过很长一段时间的开发,TiDB 终于发了 RC3。RC3 版本对于 TiKV 来说最重要的功能就是支持了 gRPC,也就意味着后面大家可以非常方便的使用自己喜欢的语言对接 TiKV 了。gRPC 是基于 HTTP/2 协议的,要深刻理解 gRPC,理解下 HTTP/2 是必要的,这里先简单介绍一下 HTTP/2 相关的知识,然后再介绍下 gRPC 是如何基于 HTTP/2 构建的。HTTP/1.x HTTP 协议可以算是现阶段 Web 上面最通用的协议了,在之前很长一段时间,很多应用都是基于 HTTP/1.x 协议,HTTP/1.x 协议是一个文本协议,可读性非常好,但其实并不高效,笔者主要碰到过几个问题:Parser 如果要解析一个完整的 HTTP 请求,首先我们需要能正确的读出 HTTP header。HTTP header 各个 fields 使用 rn 分隔,然后跟 body 之间使用 rnrn 分隔。解析完 header 之后,我们才能从 header 里面的 content-length 拿到 body 的 size,从而读取 body。这套流程其实并不高效,因为我们需要读取多次,才能将一个完整的 HTTP 请求给解析出来,虽然在代码实现上面,有很多优化方式,譬如: 一次将一大块数据读取到 buffer 里面避免多次 IO read 读取的时候直接匹配 rn 的方式流式解析 但上面的方式对于高性能服务来说,终归还是会有开销。其实最主要的问题在于,HTTP/1.x 的协议是 文本协议,是给人看的,对机器不友好,如果要对机器友好,二进制协议才是更好的选择。如果大家对解析 HTTP/1.x 很感兴趣,可以研究下 http-parser,一个非常高效小巧的 C library,见过不少框架都是集成了这个库来处理 HTTP/1.x 的。Request/Response HTTP/1.x 另一个问题就在于它的交互模式,一个连接每次只能一问一答,也就是client 发送了 request 之后,必须等到 response,才能继续发送下一次请求。这套机制是非常简单,但会造成网络连接利用率不高。如果需要同时进行大量的交互,client 需要跟 server 建立多条连接,但连接的建立也是有开销的,所以为了性能,通常这些连接都是长连接一直保活的,虽然对于 server 来说同时处理百万连接也没啥太大的挑战,但终归效率不高。Push 用 HTTP/1.x 做过推送的同学,大概就知道有多么的痛苦,因为 HTTP/1.x 并没有推送机制。所以通常两种做法: Long polling 方式,也就是直接给 server 挂一个连接,等待一段时间(譬如 1 分钟),如果 server 有返回或者超时,则再次重新 poll。 Web-socket,通过 upgrade 机制显式地将这条 HTTP 连接变成裸的 TCP,进行双向交互。 相比 Long polling,笔者还是更喜欢 web-socket 一点,毕竟更加高效,只是 web-socket 后面的交互并不是传统意义上面的 HTTP 了。Hello HTTP/2 虽然 HTTP/1.x 协议可能仍然是当今互联网运用最广泛的协议,但随着 Web 服务规模的不断扩大,HTTP/1.x 越发显得捉襟见肘,我们急需另一套更好的协议来构建我们的服务,于是就有了 HTTP/2。HTTP/2 是一个二进制协议,这也就意味着它的可读性几乎为 0,但幸运的是,我们还是有很多工具,譬如 Wireshark, 能够将其解析出来。在了解 HTTP/2 之前,需要知道一些通用术语: Stream: 一个双向流,一条连接可以有多个 streams。 Message: 也就是逻辑上面的 request,response。 Frame::数据传输的最小单位。每个 Frame 都属于一个特定的 stream 或者整个连接。一个 message 可能由多个 frame 组成。 Frame Format Frame 是 HTTP/2 里面最小的数据传输单位,一个 Frame 定义如下(直接从官网 copy 的):+-----------------------------------------------+ | Length (24) | +---------------+---------------+---------------+ | Type (8) | Flags (8) | +-+-------------+---------------+-------------------------------+ |R| Stream Identifier (31) | +=+=============================================================+ | Frame Payload (0...) ... +---------------------------------------------------------------+ Length:也就是 Frame 的长度,默认最大长度是 16KB,如果要发送更大的 Frame,需要显式地设置 max frame size。 Type:Frame 的类型,譬如有 DATA,HEADERS,PRIORITY 等。 Flag 和 R:保留位,可以先不管。 Stream Identifier:标识所属的 stream,如果为 0,则表示这个 frame 属于整条连接。 Frame Payload:根据不同 Type 有不同的格式。可以看到,Frame 的格式定义还是非常的简单,按照官方协议,可以非常方便的写一个出来。Multiplexing HTTP/2 通过 stream 支持了连接的多路复用,提高了连接的利用率。Stream 有很多重要特性: 一条连接可以包含多个 streams,多个 streams 发送的数据互相不影响。 Stream 可以被 client 和 server 单方面或者共享使用。 Stream 可以被任意一段关闭。 Stream 会确定好发送 frame 的顺序,另一端会按照接受到的顺序来处理。 Stream 用一个唯一 ID 来标识。 这里在说一下 Stream ID,如果是 client 创建的 stream,ID 就是奇数,如果是 server 创建的,ID 就是偶数。ID 0x00 和 0x01 都有特定的使用场景,不会用到。Stream ID 不可能被重复使用,如果一条连接上面 ID 分配完了,client 会新建一条连接。而 server 则会给 client 发送一个 GOAWAY frame 强制让 client 新建一条连接。为了更大的提高一条连接上面的 stream 并发,可以考虑调大 SETTINGS_MAX_CONCURRENT_STREAMS,在 TiKV 里面,我们就遇到过这个值比较小,整体吞吐上不去的问题。这里还需要注意,虽然一条连接上面能够处理更多的请求了,但一条连接远远是不够的。一条连接通常只有一个线程来处理,所以并不能充分利用服务器多核的优势。同时,每个请求编解码还是有开销的,所以用一条连接还是会出现瓶颈。在 TiKV 有一个版本中,我们就过分相信一条连接跑多 streams 这种方式没有问题,就让 client 只用一条连接跟 TiKV 交互,结果发现性能完全没法用,不光处理连接的线程 CPU 跑满,整体的性能也上不去,后来我们换成了多条连接,情况才好转。Priority 因为一条连接允许多个 streams 在上面发送 frame,那么在一些场景下面,我们还是希望 stream 有优先级,方便对端为不同的请求分配不同的资源。譬如对于一个 Web 站点来说,优先加载重要的资源,而对于一些不那么重要的图片啥的,则使用低的优先级。我们还可以设置 Stream Dependencies,形成一棵 streams priority tree。假设 Stream A 是 parent,Stream B 和 C 都是它的孩子,B 的 weight 是 4,C 的 weight 是 12,假设现在 A 能分配到所有的资源,那么后面 B 能分配到的资源只有 C 的 1/3。Flow Control HTTP/2 也支持流控,如果 sender 端发送数据太快,receiver 端可能因为太忙,或者压力太大,或者只想给特定的 stream 分配资源,receiver 端就可能不想处理这些数据。譬如,如果 client 给 server 请求了一个视屏,但这时候用户暂停观看了,client 就可能告诉 server 别在发送数据了。虽然 TCP 也有 flow control,但它仅仅只对一个连接有效果。HTTP/2 在一条连接上面会有多个 streams,有时候,我们仅仅只想对一些 stream 进行控制,所以 HTTP/2 单独提供了流控机制。Flow control 有如下特性: Flow control 是单向的。Receiver 可以选择给 stream 或者整个连接设置 window size。 Flow control 是基于信任的。Receiver 只是会给 sender 建议它的初始连接和 stream 的 flow control window size。 Flow control 不可能被禁止掉。当 HTTP/2 连接建立起来之后,client 和 server 会交换 SETTINGS frames,用来设置 flow control window size。 Flow control 是 hop-by-hop,并不是 end-to-end 的,也就是我们可以用一个中间人来进行 flow control。 这里需要注意,HTTP/2 默认的 window size 是 64 KB,实际这个值太小了,在 TiKV 里面我们直接设置成 1 GB。HPACK 在一个 HTTP 请求里面,我们通常在 header 上面携带很多改请求的元信息,用来描述要传输的资源以及它的相关属性。在 HTTP/1.x 时代,我们采用纯文本协议,并且使用 rn 来分隔,如果我们要传输的元数据很多,就会导致 header 非常的庞大。另外,多数时候,在一条连接上面的多数请求,其实 header 差不了多少,譬如我们第一个请求可能 GET /a.txt,后面紧接着是 GET /b.txt,两个请求唯一的区别就是 URL path 不一样,但我们仍然要将其他所有的 fields 完全发一遍。HTTP/2 为了结果这个问题,使用了 HPACK。虽然 HPACK 的 RFC 文档 看起来比较恐怖,但其实原理非常的简单易懂。HPACK 提供了一个静态和动态的 table,静态 table 定义了通用的 HTTP header fields,譬如 method,path 等。发送请求的时候,只要指定 field 在静态 table 里面的索引,双方就知道要发送的 field 是什么了。对于动态 table,初始化为空,如果两边交互之后,发现有新的 field,就添加到动态 table 上面,这样后面的请求就可以跟静态 table 一样,只需要带上相关的 index 就可以了。同时,为了减少数据传输的大小,使用 Huffman 进行编码。这里就不再详细说明 HPACK 和 Huffman 如何编码了。小结 上面只是大概列举了一些 HTTP/2 的特性,还有一些,譬如 push,以及不同的 frame 定义等都没有提及,大家感兴趣,可以自行参考 HTTP/2 RFC 文档。Hello gRPC gRPC 是 Google 基于 HTTP/2 以及 protobuf 的,要了解 gRPC 协议,只需要知道 gRPC 是如何在 HTTP/2 上面传输就可以了。gRPC 通常有四种模式,unary,client streaming,server streaming 以及 bidirectional streaming,对于底层 HTTP/2 来说,它们都是 stream,并且仍然是一套 request + response 模型。Request gRPC 的 request 通常包含 Request-Headers, 0 或者多个 Length-Prefixed-Message 以及 EOS。Request-Headers 直接使用的 HTTP/2 headers,在 HEADERS 和 CONTINUATION frame 里面派发。定义的 header 主要有 Call-Definition 以及 Custom-Metadata。Call-Definition 里面包括 Method(其实就是用的 HTTP/2 的 POST),Content-Type 等。而 Custom-Metadata 则是应用层自定义的任意 key-value,key 不建议使用 grpc- 开头,因为这是为 gRPC 后续自己保留的。Length-Prefixed-Message 主要在 DATA frame 里面派发,它有一个 Compressed flag 用来表示改 message 是否压缩,如果为 1,表示该 message 采用了压缩,而压缩算法定义在 header 里面的 Message-Encoding 里面。然后后面跟着四字节的 message length 以及实际的 message。EOS(end-of-stream) 会在最后的 DATA frame 里面带上了 END_STREAM 这个 flag。用来表示 stream 不会在发送任何数据,可以关闭了。Response Response 主要包含 Response-Headers,0 或者多个 Length-Prefixed-Message 以及 Trailers。如果遇到了错误,也可以直接返回 Trailers-Only。Response-Headers 主要包括 HTTP-Status,Content-Type 以及 Custom-Metadata 等。Trailers-Only 也有 HTTP-Status ,Content-Type 和 Trailers。Trailers 包括了 Status 以及 0 或者多个 Custom-Metadata。HTTP-Status 就是我们通常的 HTTP 200,301,400 这些,很通用就不再解释。Status 也就是 gRPC 的 status, 而 Status-Message 则是 gRPC 的 message。Status-Message 采用了 Percent-Encoded 的编码方式,具体参考这里。如果在最后收到的 HEADERS frame 里面,带上了 Trailers,并且有 END_STREAM 这个 flag,那么就意味着 response 的 EOS。Protobuf gRPC 的 service 接口是基于 protobuf 定义的,我们可以非常方便的将 service 与 HTTP/2 关联起来。 Path : /Service-Name/{method name} Service-Name : ?( {proto package name} "." ) {service name} Message-Type : {fully qualified proto message name} Content-Type : “application/grpc+proto” 后记 上面只是对 gRPC 协议的简单理解,可以看到,gRPC 的基石就是 HTTP/2,然后在上面使用 protobuf 协议定义好 service RPC。虽然看起来很简单,但如果一门语言没有 HTTP/2,protobuf 等支持,要支持 gRPC 就是一件非常困难的事情了。悲催的是,Rust 刚好没有 HTTP/2 支持,也仅仅有一个可用的 protobuf 实现。为了支持 gRPC,我们 team 付出了很大的努力,也走了很多弯路,从最初使用纯 Rust 的 rust-grpc 项目,到后来自己基于 c-grpc 封装了 grpc-rs,还是有很多可以说的,后面在慢慢道来。如果你对 gRPC 和 rust 都很感兴趣,欢迎参与开发。gRPC-rs: https://github.com/pingcap/grpc-rs"}, {"url": "https://pingcap.com/blog-cn/series-B-funding/", "title": "来自 PingCAP CEO 的信:说在 B 轮融资完成之际", "content": "平时技术说得多,今天说点走心的。从决定出来创业到现在,刚好两年多一点,如果把 PingCAP 比喻成一个孩子的话, 刚是过了蹒跚学步的时期,前方有更大更美好的世界等我们去探索。这两年时间,在一片质疑声之中 ,TiDB 还算顽强的从无到有成长了起来。其实这一切的初心也很简单,最开始只不过是几个不愿妥协的分布式系统工程师对心目中’完美’的数据库的探索。很欣喜的看到 TiDB 的日渐成熟,周边工具和社区渐渐壮大,我感到由衷的自豪,在这个过程中,也一次又一次的挑战着技术和各自能力的边界,很庆幸能和自己的产品一起成长。坚持做正确的事,哪怕这看起来是一条更困难的路。TiDB 从诞生的第一天起便决定开源,虽然更多的是商业上的考量,不过里面也有一点点读书人兼济天下的情怀和对传统 Hacker 精神的贯彻。在我们之前,很多人认为分布式 OLTP 和 OLAP 融合几乎是不可能的事情,也有无数的人,其中不乏亲朋好友,劝我们说在国内做这个事情几乎难于登天,而且没有成功的先例。不过我们还是相信一个朴素道理,有价值的技术一定会有它的舞台,另外,任何事情如果没有尝试就打退堂鼓也不是我们的风格。如果没有成功的先例,那就一起来创造先例,做开创者是我们每个人的梦想。说实话,从技术上来说,这个领域是一个非常前沿的领域,大多数时候我们面前是无人区,也很幸运,目前看来技术上和预想的没有出现大的偏差,整个产品和团队也在稳步的前进。整个团队也从一开始的 3 个人,到今天 63 个志同道合的伙伴结伴前行,又一次很幸运,能凑齐这么一个具有很强战斗力和国际视野的团队,挑战计算机领域最困难和最前沿的课题之一,前方还有无数个迷人的问题等待着被解决,有时候也只能摸索着前进,不过这正是这个事情有意思的地方。谢谢你们,和你们一同工作,是我的荣幸。到今天,我们很自豪的宣布,已经有数十家客户将 TiDB 使用在各自的生产环境中解决问题,感谢我们早期的铁杆用户和可爱的社区开发者,是你们让 TiDB 一点点的变得更加稳定成熟,随着社区的不断变大,TiDB 正以惊人的速度正向迭代,这就是开源的力量。最后,PingCAP 也刚顺利的完成了 1500 万美金的 B 轮融资,感谢这轮的领投方华创资本,以及跟投方经纬中国,云启资本,峰瑞资本,险峰华兴。我们的征途是星辰大海,感谢有你们的一路支持。刘奇、黄东旭、崔秋PingCAP2017-6-13"}, {"url": "https://pingcap.com/weekly/2017-06-12-tidb-weekly/", "title": "Weekly update (June 06 ~ June 11, 2017)", "content": " Weekly update in TiDB Last week, we landed 52 PRs in the TiDB repositories.Added Refactor the optimizer: Add an statsProfile interface to propagate statistic information among plans. Implement the statsProfile interface for the Join plan. JSON type: Suport json_set, json_insert, json_replace and json_merge. Support the JSON type in the cast expression. Use gRPC between TiDB and TiKV. Refactor the Analyze executor. Add the SubDuration function in util package. Support the generated column grammar. Fixed Create a session when the current session with etcd expires. Fix a bug about padding zeros for binary data. Fix a bug about type inference. Fix a but about data access race. Avoid allocating too much memory in the top-n operator. Add timeout when getting TimeStamp. Make the behavior of read-only transactions using the SelectForUpdate statement consistent with MySQL. Improved Refactor expression evaluation: Add builtinAddTimeSig Correct cast function implementation. Clean up code and prepare to add test cases. Implement wrap expression with the cast expression. Speed up DDL process: Extract interfaces for OwnerManger and SchemaSyncer. Add mock implementation for unit test. Add TTL for DDL related keys on etcd. Code style clean up. Weekly update in TiKV Last week, We landed 25 PRs in the TiKV repositories.Added Add the bloom filter for Lock CF meltable. Introduce gRPC, see 1892, 1894, 1896, 1903 Use SST based bloom filter by default. Remove the bloom filter for Raft CF. Provide the GetTSAsync API. Fixed Delete idle snapshot only on GC. Notify the blocked goroutines when get stream error. Fix a bug in get_txn_commit_info for concurrent prewrite. Check the leader again when fail to create TSO stream. Fix a data race problem in PD client. Improved Optimize the Raft log entry fetching. Capture the SIGHUP and close gracefully. Avoid allocating lots of memory in topn function. Use SST snapshot format by default to speed up Raft snapshot applying. "}, {"url": "https://pingcap.com/blog-cn/deployment-by-ansible/", "title": "使用 Ansible 安装部署 TiDB", "content": " 背景知识 TiDB 作为一个分布式数据库,在多个节点分别配置安装服务会相当繁琐,为了简化操作以及方便管理,使用自动化工具来批量部署成为了一个很好的选择。Ansible 是基于 Python 研发的自动化运维工具,糅合了众多老牌运维工具的优点实现了批量操作系统配置、批量程序的部署、批量运行命令等功能,而且使用简单,仅需在管理工作站上安装 Ansible 程序配置被管控主机的 IP 信息,被管控的主机无客户端。基于以上原因,我们选用自动化工具 Ansible 来批量的安装配置以及部署 TiDB。下面我们来介绍如何使用 Ansible 来部署 TiDB。TiDB 安装环境配置如下 操作系统使用 CentOS7.2 或者更高版本,文件系统使用 EXT4。 说明:低版本的操作系统(例如 CentOS6.6 )和 XFS 文件系统会有一些内核 Bug,会影响性能,我们不推荐使用。 IP Services 192.168.1.101 PD Prometheus Grafana Pushgateway Node_exporter 192.168.1.102 PD TiDB Node_exporter 192.168.1.103 PD TiDB Node_exporter 192.168.1.104 TiKV Node_exporter 192.168.1.105 Tikv Node_exporter 192.168.1.106 TiKV Node_exporter 我们选择使用 3 个 PD、2 个 TiDB、3 个 TiKV,这里简单说一下为什么这样部署。 对于 PD 。PD 本身是一个分布式系统,由多个节点构成一个整体,并且同时有且只有一个主节点对外提供服务。各个节点之间通过选举算法来确定主节点,选举算法要求节点个数是奇数个 (2n+1) ,1 个节点的风险比较高,所以我们选择使用 3 个节点。 对于 TiKV 。TiDB 底层使用分布式存储,我们推荐使用奇数 (2n+1) 个备份,挂掉 n 个备份之后数据仍然可用。使用 1 备份或者 2 备份的话,有一个节点挂掉就会造成一部分数据不可用,所以我们选择使用 3 个节点、设置 3 个备份 (默认值)。 对于 TiDB 。我们的 TiDB 是无状态的,现有集群的 TiDB 服务压力大的话,可以在其他节点直接增加 TiDB 服务,无需多余的配置。我们选择使用两个 TiDB,可以做 HA 和负载均衡。 当然如果只是测试集群的话,完全可以使用一个 PD 、一个 TiDB 、三个 TiKV (少于三个的话需要修改备份数量) 下载 TiDB 安装包并解压 #创建目录用来存放 ansible 安装包 mkdir /root/workspace #切换目录 cd /root/workspace #下载安装包 wget https://github.com/pingcap/tidb-ansible/archive/master.zip #解压压缩包到当前目录下 unzip master.zip #查看安装包结构,主要内容说明如下 cd tidb-ansible-master && ls 部分内容含义ansible.cfg: ansible 配置文件 inventory.ini: 组和主机的相关配置 conf: TiDB 相关配置模版 group_vars: 相关变量配置 scripts: grafana 监控 json 模版 local_prepare.yml: 用来下载相关安装包 bootstrap.yml: 初始化集群各个节点 deploy.yml: 在各个节点安装 TiDB 相应服务 roles: ansible tasks 的集合 start.yml: 启动所有服务 stop.yml: 停止所有服务 unsafe_cleanup_data.yml: 清除数据 unsafe_cleanup.yml: 销毁集群 修改配置文件 主要配置集群节点的分布情况,以及安装路径。会在 tidb_servers 组中的机器上安装 TiDB 服务(其他类似),默认会将所有服务安装到变量 deploy_dir 路径下。#将要安装 TiDB 服务的节点 [tidb_servers] 192.168.1.102 192.168.1.103 #将要安装 TiKV 服务的节点 [tikv_servers] 192.168.1.104 192.168.1.105 192.168.1.106 #将要安装 PD 服务的节点 [pd_servers] 192.168.1.101 192.168.1.102 192.168.1.103 #将要安装 Promethues 服务的节点 # Monitoring Part [monitoring_servers] 192.168.1.101 #将要安装 Grafana 服务的节点 [grafana_servers] 192.168.1.101 #将要安装 Node_exporter 服务的节点 [monitored_servers:children] tidb_servers tikv_servers pd_servers [all:vars] #服务安装路径,每个节点均相同,根据实际情况配置 deploy_dir = /home/tidb/deploy ## Connection #方式一:使用 root 用户安装 # ssh via root: # ansible_user = root # ansible_become = true # ansible_become_user = tidb #方式二:使用普通用户安装(需要有 sudo 权限) # ssh via normal user ansible_user = tidb #集群的名称,自定义即可 cluster_name = test-cluster # misc enable_elk = False enable_firewalld = False enable_ntpd = False # binlog trigger #是否开启 pump,pump 生成 TiDB 的 binlog #如果有从此 TiDB 集群同步数据的需求,可以改为 True 开启 enable_binlog = False 安装过程可以分为 root 用户安装和普通用户安装两种方式。有 root 用户当然是最好的,修改系统参数、创建目录等不会涉及到权限不够的问题,能够直接安装完成。 但是有些环境不会直接给 root 权限,这种场景就需要通过普通用户来安装。为了配置简便,我们建议所有节点都使用相同的普通用户;为了满足权限要求,我们还需要给这个普通用户 sudo 权限。 下面介绍两种安装方式的详细过程,安装完成之后需要手动启动服务。1. 使用 root 用户安装 下载 Binary 包到 downloads 目录下,并解压拷贝到 resources/bin 下,之后的安装过程就是使用的 resources/bin 下的二进制程序 ansible-playbook -i inventory.ini local_prepare.yml 初始化集群各个节点。会检查 inventory.ini 配置文件、Python 版本、网络状态、操作系统版本等,并修改一些内核参数,创建相应的目录。 修改配置文件如下 ## Connection # ssh via root: ansible_user = root # ansible_become = true ansible_become_user = tidb # ssh via normal user # ansible_user = tidb 执行初始化命令 ansible-playbook -i inventory.ini bootstrap.yml -k #ansible-playboo命令说明请见附录 安装服务。该步骤会在服务器上安装相应的服务,并自动设置好配置文件和所需脚本。 修改配置文件如下 ## Connection # ssh via root: ansible_user = root ansible_become = true ansible_become_user = tidb # ssh via normal user # ansible_user = tidb 执行安装命令 ansible-playbook -i inventory.ini deploy.yml -k 2. 使用普通用户安装 下载 Binary 包到中控机 ansible-playbook -i inventory.ini local_prepare.yml 初始化集群各个节点。 修改配置文件如下 ## Connection # ssh via root: # ansible_user = root # ansible_become = true # ansible_become_user = tidb # ssh via normal user ansible_user = tidb 执行初始化命令 ansible-playbook -i inventory.ini bootstrap.yml -k -K 安装服务 ansible-playbook -i inventory.ini deploy.yml -k -K 启停服务 启动所有服务 ansible-playbook -i inventory.ini start.yml -k 停止所有服务 ansible-playbook -i inventory.ini stop.yml 附录 ansible-playbook -i inventory.ini xxx.yml -k -K-k 执行之后需要输入 ssh 连接用户的密码,如果做了中控机到所有节点的互信,则不需要此参数-K 执行之后需要输入 sudo 所需的密码,如果使用 root 用户或者 sudo 无需密码,则不需要此参数 "}, {"url": "https://pingcap.com/blog-cn/tidb-internal-3/", "title": "三篇文章了解 TiDB 技术内幕 - 谈调度", "content": " 为什么要进行调度 先回忆一下第一篇文章提到的一些信息,TiKV 集群是 TiDB 数据库的分布式 KV 存储引擎,数据以 Region 为单位进行复制和管理,每个 Region 会有多个 Replica(副本),这些 Replica 会分布在不同的 TiKV 节点上,其中 Leader 负责读/写,Follower 负责同步 Leader 发来的 raft log。了解了这些信息后,请思考下面这些问题: 如何保证同一个 Region 的多个 Replica 分布在不同的节点上?更进一步,如果在一台机器上启动多个 TiKV 实例,会有什么问题? TiKV 集群进行跨机房部署用于容灾的时候,如何保证一个机房掉线,不会丢失 Raft Group 的多个 Replica? 添加一个节点进入 TiKV 集群之后,如何将集群中其他节点上的数据搬过来? 当一个节点掉线时,会出现什么问题?整个集群需要做什么事情?如果节点只是短暂掉线(重启服务),那么如何处理?如果节点是长时间掉线(磁盘故障,数据全部丢失),需要如何处理? 假设集群需要每个 Raft Group 有 N 个副本,那么对于单个 Raft Group 来说,Replica 数量可能会不够多(例如节点掉线,失去副本),也可能会过于多(例如掉线的节点又回复正常,自动加入集群)。那么如何调节 Replica 个数? 读/写都是通过 Leader 进行,如果 Leader 只集中在少量节点上,会对集群有什么影响? 并不是所有的 Region 都被频繁的访问,可能访问热点只在少数几个 Region,这个时候我们需要做什么? 集群在做负载均衡的时候,往往需要搬迁数据,这种数据的迁移会不会占用大量的网络带宽、磁盘 IO 以及 CPU?进而影响在线服务? 这些问题单独拿出可能都能找到简单的解决方案,但是混杂在一起,就不太好解决。有的问题貌似只需要考虑单个 Raft Group 内部的情况,比如根据副本数量是否足够多来决定是否需要添加副本。但是实际上这个副本添加在哪里,是需要考虑全局的信息。整个系统也是在动态变化,Region 分裂、节点加入、节点失效、访问热点变化等情况会不断发生,整个调度系统也需要在动态中不断向最优状态前进,如果没有一个掌握全局信息,可以对全局进行调度,并且可以配置的组件,就很难满足这些需求。因此我们需要一个中心节点,来对系统的整体状况进行把控和调整,所以有了 PD 这个模块。调度的需求 上面罗列了一大堆问题,我们先进行分类和整理。总体来看,问题有两大类:作为一个分布式高可用存储系统,必须满足的需求,包括四种: 副本数量不能多也不能少 副本需要分布在不同的机器上 新加节点后,可以将其他节点上的副本迁移过来 节点下线后,需要将该节点的数据迁移走 作为一个良好的分布式系统,需要优化的地方,包括: 维持整个集群的 Leader 分布均匀 维持每个节点的储存容量均匀 维持访问热点分布均匀 控制 Balance 的速度,避免影响在线服务 管理节点状态,包括手动上线/下线节点,以及自动下线失效节点 满足第一类需求后,整个系统将具备多副本容错、动态扩容/缩容、容忍节点掉线以及自动错误恢复的功能。满足第二类需求后,可以使得整体系统的负载更加均匀、且可以方便的管理。为了满足这些需求,首先我们需要收集足够的信息,比如每个节点的状态、每个 Raft Group 的信息、业务访问操作的统计等;其次需要设置一些策略,PD 根据这些信息以及调度的策略,制定出尽量满足前面所述需求的调度计划;最后需要一些基本的操作,来完成调度计划。调度的基本操作 我们先来介绍最简单的一点,也就是调度的基本操作,也就是为了满足调度的策略,我们有哪些功能可以用。这是整个调度的基础,了解了手里有什么样的锤子,才知道用什么样的姿势去砸钉子。上述调度需求看似复杂,但是整理下来最终落地的无非是下面三件事: 增加一个 Replica 删除一个 Replica 将 Leader 角色在一个 Raft Group 的不同 Replica 之间 transfer 刚好 Raft 协议能够满足这三种需求,通过 AddReplica、RemoveReplica、TransferLeader 这三个命令,可以支撑上述三种基本操作。信息收集 调度依赖于整个集群信息的收集,简单来说,我们需要知道每个 TiKV 节点的状态以及每个 Region 的状态。TiKV 集群会向 PD 汇报两类消息:每个 TiKV 节点会定期向 PD 汇报节点的整体信息TiKV 节点(Store)与 PD 之间存在心跳包,一方面 PD 通过心跳包检测每个 Store 是否存活,以及是否有新加入的 Store;另一方面,心跳包中也会携带这个 Store 的状态信息,主要包括: 总磁盘容量 可用磁盘容量 承载的 Region 数量 数据写入速度 发送/接受的 Snapshot 数量(Replica 之间可能会通过 Snapshot 同步数据) 是否过载 标签信息(标签是具备层级关系的一系列 Tag) 每个 Raft Group 的 Leader 会定期向 PD 汇报信息每个 Raft Group 的 Leader 和 PD 之间存在心跳包,用于汇报这个 Region 的状态,主要包括下面几点信息: Leader 的位置 Followers 的位置 掉线 Replica 的个数 数据写入/读取的速度 PD 不断的通过这两类心跳消息收集整个集群的信息,再以这些信息作为决策的依据。除此之外,PD 还可以通过管理接口接受额外的信息,用来做更准确的决策。比如当某个 Store 的心跳包中断的时候,PD 并不能判断这个节点是临时失效还是永久失效,只能经过一段时间的等待(默认是 30 分钟),如果一直没有心跳包,就认为是 Store 已经下线,再决定需要将这个 Store 上面的 Region 都调度走。但是有的时候,是运维人员主动将某台机器下线,这个时候,可以通过 PD 的管理接口通知 PD 该 Store 不可用,PD 就可以马上判断需要将这个 Store 上面的 Region 都调度走。调度的策略 PD 收集了这些信息后,还需要一些策略来制定具体的调度计划。一个 Region 的 Replica 数量正确当 PD 通过某个 Region Leader 的心跳包发现这个 Region 的 Replica 数量不满足要求时,需要通过 Add/Remove Replica 操作调整 Replica 数量。出现这种情况的可能原因是: 某个节点掉线,上面的数据全部丢失,导致一些 Region 的 Replica 数量不足 某个掉线节点又恢复服务,自动接入集群,这样之前已经补足了 Replica 的 Region 的 Replica 数量多过,需要删除某个 Replica 管理员调整了副本策略,修改了 max-replicas 的配置 一个 Raft Group 中的多个 Replica 不在同一个位置注意第二点,『一个 Raft Group 中的多个 Replica 不在同一个位置』,这里用的是『同一个位置』而不是『同一个节点』。在一般情况下,PD 只会保证多个 Replica 不落在一个节点上,以避免单个节点失效导致多个 Replica 丢失。在实际部署中,还可能出现下面这些需求: 多个节点部署在同一台物理机器上 TiKV 节点分布在多个机架上,希望单个机架掉电时,也能保证系统可用性 TiKV 节点分布在多个 IDC 中,希望单个机房掉电时,也能保证系统可用 这些需求本质上都是某一个节点具备共同的位置属性,构成一个最小的容错单元,我们希望这个单元内部不会存在一个 Region 的多个 Replica。这个时候,可以给节点配置 lables 并且通过在 PD 上配置 location-labels 来指明哪些 lable 是位置标识,需要在 Replica 分配的时候尽量保证不会有一个 Region 的多个 Replica 所在结点有相同的位置标识。副本在 Store 之间的分布均匀分配前面说过,每个副本中存储的数据容量上限是固定的,所以我们维持每个节点上面,副本数量的均衡,会使得总体的负载更均衡。Leader 数量在 Store 之间均匀分配Raft 协议要读取和写入都通过 Leader 进行,所以计算的负载主要在 Leader 上面,PD 会尽可能将 Leader 在节点间分散开。访问热点数量在 Store 之间均匀分配每个 Store 以及 Region Leader 在上报信息时携带了当前访问负载的信息,比如 Key 的读取/写入速度。PD 会检测出访问热点,且将其在节点之间分散开。各个 Store 的存储空间占用大致相等每个 Store 启动的时候都会指定一个 Capacity 参数,表明这个 Store 的存储空间上限,PD 在做调度的时候,会考虑节点的存储空间剩余量。控制调度速度,避免影响在线服务调度操作需要耗费 CPU、内存、磁盘 IO 以及网络带宽,我们需要避免对线上服务造成太大影响。PD 会对当前正在进行的操作数量进行控制,默认的速度控制是比较保守的,如果希望加快调度(比如已经停服务升级,增加新节点,希望尽快调度),那么可以通过 pd-ctl 手动加快调度速度。支持手动下线节点当通过 pd-ctl 手动下线节点后,PD 会在一定的速率控制下,将节点上的数据调度走。当调度完成后,就会将这个节点置为下线状态。调度的实现 了解了上面这些信息后,接下来我们看一下整个调度的流程。PD 不断的通过 Store 或者 Leader 的心跳包收集信息,获得整个集群的详细数据,并且根据这些信息以及调度策略生成调度操作序列,每次收到 Region Leader 发来的心跳包时,PD 都会检查是否有对这个 Region 待进行的操作,通过心跳包的回复消息,将需要进行的操作返回给 Region Leader,并在后面的心跳包中监测执行结果。注意这里的操作只是给 Region Leader 的建议,并不保证一定能得到执行,具体是否会执行以及什么时候执行,由 Region Leader 自己根据当前自身状态来定。总结 本篇文章讲的东西,大家可能平时很少会在其他文章中看到,每一个设计都有背后的考量,希望大家能了解到一个分布式存储系统在做调度的时候,需要考虑哪些东西,如何将策略、实现进行解耦,更灵活的支持策略的扩展。至此三篇文章已经讲完,希望大家能够对整个 TiDB 的基本概念和实现原理有了解,后续我们还会写更多的文章,从架构以及代码级别介绍 TiDB 的更多内幕。如果大家有问题,欢迎发邮件到 shenli@pingcap.com 进行交流。"}, {"url": "https://pingcap.com/weekly/2017-06-05-tidb-weekly/", "title": "Weekly update (May 22 ~ June 05, 2017)", "content": " Weekly update in TiDB Last two weeks, we landed 53 PRs in the TiDB repositories.Added Support using After and First to specify column position in the Alter Table Statement. Support the password builtin function. Support the inet6_ntoa builtin function. Support the Extract and Unquote function for Json. Support json_{set/insert/replace} and json_merge for Json. Support batched Index Lookup Join. Fixed Fix a goroutine leak problem. Fix a bug in double read executor. Fix a bug for type inferrer of Bit literal value. Fix a bug about context cancellation. Improved Refactor expression evaluation: Refactor the cast function. Add the GetTypeClass() interface in Expression. Update stored password in mysql.user table to make it consistent with MySQL. Speed up the DDL process: Use etcd to synchronise schema version instead of waiting two leases. Enable DDL speed up. Add the references_priv column in mysql.user. Close DDL worker gracefully when shutting down the TiDB server. Weekly update in TiKV Last two weeks, We landed 33 PRs in the TiKV repositories.Added Introduce gRPC, see 1850, 1865, 1868, 1879. Report the written keys to PD for better scheduler. Balance the hot regions by peer and leader together. Record the cluster bootstrap time. Add the state for operators. Add the metrics for balance. Add the disaster recovery tool for PD. Output the allocation statistics when receiving SIGUSR1. Add the direct IO configuration for RocksDB. Fixed Check the cluster ID when re-connecting to PD. Reuse the timer to avoid spawning thread frequently. Remove the realtime signal handler. Prevent accessing nil store when recovering cluster. Check the environment TZ setting. Use the forward mode for scanning data in GC command. Check the last apply index to determine handing snapshot. Improved Increase the region size from 64 MB to 96 MB. Split total region peer cache. Use FlatMap instead of HashMap to improve performance. Modify the default compression in RocksDB. "}, {"url": "https://pingcap.com/meetup/meetup-2017-06-03/", "title": "【Infra Meetup No.49】TiDB Best Practice", "content": " 今日的 Meetup,我司 Engineering VP 申砾同学亲自上阵,为大家分享了《TiDB Best Practice 》,好多使用经验及背后技术实现原理都是首次揭秘(当然,包括彩蛋)。 本期讲师:申砾,PingCAP Engineering VP,前网易有道词典服务器端核心开发,前奇虎 360 新闻推荐系统 / 地图基础数据与检索系统 Tech Lead。TiDB 是一个分布式数据库,支持 MySQL 协议以及语法,在一些场景中都可以无缝替换 MySQL,以获得分布式的好处。但是分布式数据库有其自身的特点,想要在业务中用好需要遵循一些实践原则。本次分享申砾同学首先介绍了 TiDB 的一些关键部分的实现原理,理解这些内部实现有利于理解 TiDB 的外在表现。然后与大家讨论了应用数据库时的典型操作的最佳实践以及要注意的事项,并对 TiDB 的适用场景进行了讲解。PPT 很干,一点水都挤不出来…随便放几张你们感受下┑( ̄Д  ̄)┍最后,申砾同学还分享了 TiDB 最近的一些项目进展,并首次公开披露 PingCAP 最新动向:独立研发的 TiDB 专用的 Spark Connector 即将上线。Spark 是当下最流行的大数据分析系统,拥有活跃的社区。PingCAP 希望能够将 TiDB 与 Spark 相结合,通过 Spark 对 TiDB 中存储的数据做实时分析,以融入这个生态。为了保证这个连接过程尽可能的高效,所以除了基本的 JDBC Connector 之外,便有了 TiDB 专用的 Spark Connector。附:完整 PPT 链接彩蛋来啦 视频:Demo of Spark on TiDB即将上线,敬请期待~ PingCAP Infra Meetup作为一个基础架构领域的前沿技术公司,PingCAP 希望能为国内真正关注技术本身的 Hackers 打造一个自由分享的平台。自 2016 年 3 月 5 日开始,我们定期在周六的上午举办 Infra Meetup,邀请业内大牛与大家深度探讨基础架构领域的前瞻性技术思考与经验。在这里,我们希望提供一个高水准的前沿技术讨论空间,让大家真正感受到自由的开源精神魅力。 "}, {"url": "https://pingcap.com/blog-cn/iostat-perf-strace/", "title": "工欲性能调优,必先利其器(1)", "content": " 使用 iostat 定位磁盘问题 在一个性能测试集群,我们选择了 AWS c3.4xlarge 机型,主要是为了在一台机器的两块盘上面分别跑 TiKV。在测试一段时间之后,我们发现有一台 TiKV 响应很慢,但是 RocksDB 并没有相关的 Stall 日志,而且慢查询也没有。于是我登上 AWS 机器,使用 iostat -d -x -m 5 命令查看,得到如下输出:Device: rrqm/s wrqm/s r/s w/s rMB/s wMB/s avgrq-sz avgqu-sz await r_await w_await svctm %util xvda 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 xvdb 8.00 12898.00 543.00 579.00 31.66 70.15 185.84 51.93 54.39 7.03 98.79 0.60 66.80 xvdc 0.00 0.00 206.00 1190.00 10.58 148.62 233.56 106.67 70.90 13.83 80.78 0.56 78.40 上面发现,两个盘 xvdb 和 xvdc 在 wrqm/s 上面差距太大,当然后面一些指标也有明显的差距,这里就不在详细的解释 iostat 的输出。只是需要注意,大家通常将目光注意到 util 上面,但有时候光有 util 是反应不了问题的。于是我继续用 fio 进行测试,fio -ioengine=libaio -bs=4k -direct=1 -thread -rw=write -size=10G -filename=test -name="PingCAP max throughput" -iodepth=4 -runtime=60发现两个盘的写入有 2 倍的差距,xvdb 的写入竟然只有不到 70 MB,而 xvdc 有 150 MB,所以自然两个 TiKV 一个快,一个慢了。对于磁盘来说,通常我们使用的就是 iostat 来进行排查,另外也可以考虑使用 pidstat,iotop 等工具。使用 perf 定位性能问题 RC3 最重要的一个功能就是引入 gRPC,但这个对于 rust 来说难度太大。最开始,我们使用的是 rust-grpc 库,但这个库并没有经过生产环境的验证,我们还是胆大的引入了,只是事后证明,这个冒险的决定还是傻逼了,一些试用的用户跟我们反映 TiKV 时不时 coredump,所以我们立刻决定直接封装 c gRPC。因为现在大部分语言 gRPC 实现都是基于 c gRPC 的,所以我们完全不用担心这个库的稳定性。在第一个版本的实现中,我们发现,rust 封装的 c gRPC 比 C Plus Plus 的版本差了几倍的性能,于是我用 perf stat 来分别跑 C Plus Plus 和 rust 的benchmark,得到类似如下的输出:Performance counter stats for 'python2.7 tools/run_tests/run_performance_tests.py -r generic_async_streaming_ping_pong -l c++': 216989.551636 task-clock (msec) # 2.004 CPUs utilized 3,659,896 context-switches # 0.017 M/sec 5,078 cpu-migrations # 0.023 K/sec 4,104,965 page-faults # 0.019 M/sec 729,530,805,665 cycles # 3.362 GHz <not supported> stalled-cycles-frontend <not supported> stalled-cycles-backend 557,766,492,733 instructions # 0.76 insns per cycle 121,205,705,283 branches # 558.579 M/sec 3,095,509,087 branch-misses # 2.55% of all branches 108.267282719 seconds time elapsed 上面是 C Plus Plus 的结果,然后在 rust 测试的时候,我们发现 context-switch 是 C Plus Plus 的 10 倍,也就是我们进行了太多次的线程切换。刚好我们第一个版本的实现是用 rust futures 的 park 和 unpark task 机制,不停的在 gRPC 自己的 Event Loop 线程和逻辑线程之前切换,但 C Plus Plus 则是直接在一个 Event Loop 线程处理的。于是我们立刻改成类似 C Plus Plus 架构,没有了 task 的开销,然后性能一下子跟 C Plus Plus 的不相伯仲了。当然,perf 能做到的还远远不仅于此,我们通常会使用火焰图工具,关于火焰图,网上已经有太多的介绍,我们也通过它来发现了很多性能问题,这个后面可以专门来说一下。使用 strace 动态追踪 因为我们有一个记录线程 CPU 的统计,通常在 Grafana 展示的时候都是按照线程名字来 group 的,并没有按照线程 ID。但我们也可以强制发送 SIGUSR1 信号给 TiKV 在 log 里面 dump 相关的统计信息。在测试 TiKV 的时候,我发现 pd worker 这个 thread 出现了很多不同线程 ID 的 label,也就是说,这个线程在不停的创建和删除。要动态追踪到这个情况,使用 strace -f 是一个不错的方式,我同时观察 TiKV 自己的输出 log,发现当 TiKV 在处理分裂逻辑,给 PD worker 发送 message 的时候,就有一个新的线程创建出来。然后在查找对应的代码,发现我们每次在发消息的时候都创建了一个 tokio-timer,而这个每次都会新创建一个线程。有时候,也可以使用 strace -c 来动态的追踪一段时间的系统调用。在第一版本的 rust gRPC 中,我们为了解决 future task 导致的频繁线程切换,使用 gRPC 自己的 alarm 来唤醒 Event Loop,但发现这种实现会产生大量的信号调用,因为 gRPC 的 alarm 会发送一个实时信号用来唤醒 epoll,后面通过火焰图也发现了 Event Loop 很多 CPU 消耗在 alarm 这边,所以也在开始改进。这里需要注意,strace 对性能影响比较大,但对于内部性能测试影响还不大,不到万不得已,不建议长时间用于生产环境。小结 上面仅仅是三个最近用工具发现的问题,当然还远远不止于此,后续也会慢慢补上。其实对于性能调优来说,工具只是一个辅助工具,最重要的是要有一颗对问题敏锐的心,不然即使工具发现了问题,因为不敏锐直接就忽略了。我之前就是不敏锐栽过太多的坑,所以现在为了刻意提升自己这块的能力,直接给自己下了死规定,就是怀疑一切能能怀疑的东西,认为所有东西都是有问题的。即使真的是正常的,也需要找到充足的理由去验证。"}, {"url": "https://pingcap.com/blog/2017-05-27-rust-in-tikv/", "title": "Rust in TiKV", "content": " This is the speech Siddon Tang gave at the 1st Rust Meetup in Beijing on April 16, 2017.(Email: tl@pingcap.com)Table of Content What’s TiKV We need a language with… Why not C++? Why not Go? So we turned to Rust… TiKV Timeline TiKV Architecture Multi-Raft Scale out A simple write flow Key technologies Future plan Hello everyone, today I will talk about how we use Rust in TiKV.Before we begin, let me introduce myself. My name is Siddon Tang, the Chief Architect of PingCAP. Before I joined PingCAP, I had worked at Kingsoft and Tencent. I love open source and have developed some projects like LedisDB, go-mysql, etc…At first, I will explain the reason why we chose Rust to develop TiKV, then show you the architecture of TiKV briefly and the key technologies. In the end, I will introduce what we plan to do in the future.What’s TiKV? All right, let’s begin. First, what is TiKV. TiKV is a distributed Key-Value database with the following features: Geo-replication: We use Raft and Placement Driver to replicate data geographically to guarantee data safety. Horizontal scalability: We can add some nodes directly if we find that the rapidly growing data will soon exceed the system capacity. Consistent distributed transaction: We use an optimized, two phase commit protocol, based on Google Percolator, to support distributed transactions. You can use “begin” to start a transaction, then do something, then use “commit” or “rollback” to finish the transaction. Coprocessor for distributed computing: Just like HBase, we support a coprocessor framework to let user do computing in TiKV directly. Working with TiDB like Spanner with F1: Using TiKV as a backend storage engine of TiDB, we can provide the best distributed relational database. Back to the topWe need a language with… As you see, TiKV has many powerful features. To develop these features, we also need a powerful programming language. The language should have: Fast speed: We take the performance of TiKV very seriously, so we need a language which runs very fast at runtime. Memory safety: As a program that is going to run for a long time, we don’t want to meet any memory problem, such as dangling pointer, memory leak, etc… Thread safety: We must guarantee data consistency all the time, so any data race problem must be avoided. Binding C efficiency: We depend on RocksDB heavily, so we must be able to call the RocksDB API as fast as we can, without any performance reduction. Why not C++? To develop a high performance service, C++ may be the best choice in most cases, but we didn’t choose it. We figured we might spend too much time avoiding the memory problem or the data race problem. Moreover, C++ has no official package manager and that makes the maintaining and compiling third dependences very troublesome and difficult, resulting in a long development cycle.Why not Go? At first, we considered using Go, but then gave up this idea. Go has GC which fixes many memory problems, but it might stop the running process sometimes. No matter how little time the stop takes, we can’t afford it. Go doesn’t solve the data race problem either. Even we can use double dash race in test or at runtime, this isn’t enough.Besides, although we can use Goroutine to write the concurrent logic easily, we still can’t neglect the runtime expenses of the scheduler. We met a problem a few days ago: we used multi goroutines to select the same context but found that the performance was terrible, so we had to use one sub context for one goroutine, then the performance became better.More seriously, CGO has heavy expenses, but we need to call RocksDB API without delay. For the above reasons, we didn’t choose Go even this is the favorite language in our team.Back to the topSo we turned to Rust… But Rust… Rust is a system programming language, maintained by Mozilla. It is a very powerful language, however, you can see the curve, the learning curve is very very steep.I have been using many programming languages, like C++, Go, python, lua, etc. and Rust is the hardest language for me to master. In PingCAP, we will let the new colleague spend at least one month to learn Rust, to struggle with the compiling errors, and then to rise above it. This would never happen for Go.Besides, the compiling time is very long, even longer than C++. Each time when I type cargo build to start building TiKV, I can even do some pushups.Although Rust is around for a long time, it still lacks of libraries and tools, and some third projects have not been verified in production yet. These are all the risks for us. Most seriously, it is hard for us to find Rust programmer because only few know it in China, so we are always shorthanded.Then, Why Rust? Although Rust has the above disadvantages, its advantages are attractive for us too. Rust is memory safe, so we don’t need to worry about memory leak, or dangling pointer any more.Rust is thread safe, so there won’t be any data race problem. All the safety are guaranteed by compiler. So in most cases, when the compiling passes, we are sure that we can run the program safely.Rust has no GC expenses, so we won’t meet the “stop the world” problem. Calling C through FFI is very fast, so we don’t worry the performance reduction when calling the RocksDB API. At last, Rust has an official package manager, Cargo, we can find many libraries and use them directly.We made a hard but great decision: Use Rust! Back to the topTiKV Timeline Here you can see the TiKV timeline. We first began to develop TiKV January 1st, 2016, and made it open source on April 1st, 2016, and this is not a joke like Gmail at All April Fool’s Day. TiKV was first used in production in October, 2016, when we had not even released a beta version. In November, 2016, we released the first beta version; then RC1 in December, 2016, RC2 in February, this year. Later we plan to release RC3 in April and the first GA version in June.As you can see, the development of TiKV is very fast and the released versions of TiKV are stable. Choosing Rust has already been proved a correct decision. Thanks, Rust.TiKV Architecture Now let’s go deep into TiKV. You can see from the TiKV architecture that the hierarchy of TiKV is clear and easy to understand.At the bottom layer, TiKV uses RocksDB, a high performance, persistent Key-Value store, as the backend storage engine.The next layer is Raft KV. TiKV uses the Raft to replicate data geographically. TiKV is designed to store tons of data which one Raft group can’t hold. So we split the data with ranges and use each range as an individual Raft group. We name this approach: Multi-Raft groups.TiKV provides a simple Key-Value API including SET, GET, DELETE to let user use it just as any distributed Key-Value storage. The upper layer also uses these to support advanced functions.Above the Raft layer, it is MVCC. All the keys saved in TiKV must contain a globally unique timestamp, which is allocated by Placement Driver. TiKV uses it to support distributed transactions.On the top layer, it is the KV and coprocessor API layer for handling client requests.Back to the topMulti-Raft Here is an example of Multi-Raft.You can see that there are four TiKV nodes. Within each store, we have several regions. Region is the basic unit of data movement and is replicated by Raft. Each region is replicated to three nodes. These three replicas of one Region make a Raft group.Scale Out Scale-out (initial state) Here is an example of horizontal scalability. At first, we have four nodes, Node A has three regions, others have two regions.Of course, Node A is busier than other nodes, and we want to reduce its stress.Scale-out (add new node) So we add a new Node E, and begin to move the region 1 in Node A to Node E. But here we find that the leader of region 1 is in Node A, so we will first transfer the leader from Node A to Node B.Scale-out (balancing) After that, the leader of region 1 …"}, {"url": "https://pingcap.com/blog-cn/tidb-internal-2/", "title": "三篇文章了解 TiDB 技术内幕 - 说计算", "content": " 关系模型到 Key-Value 模型的映射 在这我们将关系模型简单理解为 Table 和 SQL 语句,那么问题变为如何在 KV 结构上保存 Table 以及如何在 KV 结构上运行 SQL 语句。 假设我们有这样一个表的定义:CREATE TABLE User { ID int, Name varchar(20), Role varchar(20), Age int, PRIMARY KEY (ID), Key idxAge (age) }; SQL 和 KV 结构之间存在巨大的区别,那么如何能够方便高效地进行映射,就成为一个很重要的问题。一个好的映射方案必须有利于对数据操作的需求。那么我们先看一下对数据的操作有哪些需求,分别有哪些特点。对于一个 Table 来说,需要存储的数据包括三部分: 表的元信息 Table 中的 Row 索引数据 表的元信息我们暂时不讨论,会有专门的章节来介绍。 对于 Row,可以选择行存或者列存,这两种各有优缺点。TiDB 面向的首要目标是 OLTP 业务,这类业务需要支持快速地读取、保存、修改、删除一行数据,所以采用行存是比较合适的。对于 Index,TiDB 不止需要支持 Primary Index,还需要支持 Secondary Index。Index 的作用的辅助查询,提升查询性能,以及保证某些 Constraint。查询的时候有两种模式,一种是点查,比如通过 Primary Key 或者 Unique Key 的等值条件进行查询,如 select name from user where id=1; ,这种需要通过索引快速定位到某一行数据;另一种是 Range 查询,如 select name from user where age > 30 and age < 35;,这个时候需要通过idxAge索引查询 age 在 30 和 35 之间的那些数据。Index 还分为 Unique Index 和 非 Unique Index,这两种都需要支持。分析完需要存储的数据的特点,我们再看看对这些数据的操作需求,主要考虑 Insert/Update/Delete/Select 这四种语句。对于 Insert 语句,需要将 Row 写入 KV,并且建立好索引数据。对于 Update 语句,需要将 Row 更新的同时,更新索引数据(如果有必要)。对于 Delete 语句,需要在删除 Row 的同时,将索引也删除。上面三个语句处理起来都很简单。对于 Select 语句,情况会复杂一些。首先我们需要能够简单快速地读取一行数据,所以每个 Row 需要有一个 ID (显示或隐式的 ID)。其次可能会读取连续多行数据,比如 Select * from user;。最后还有通过索引读取数据的需求,对索引的使用可能是点查或者是范围查询。大致的需求已经分析完了,现在让我们看看手里有什么可以用的:一个全局有序的分布式 Key-Value 引擎。全局有序这一点重要,可以帮助我们解决不少问题。比如对于快速获取一行数据,假设我们能够构造出某一个或者某几个 Key,定位到这一行,我们就能利用 TiKV 提供的 Seek 方法快速定位到这一行数据所在位置。再比如对于扫描全表的需求,如果能够映射为一个 Key 的 Range,从 StartKey 扫描到 EndKey,那么就可以简单的通过这种方式获得全表数据。操作 Index 数据也是类似的思路。接下来让我们看看 TiDB 是如何做的。TiDB 对每个表分配一个 TableID,每一个索引都会分配一个 IndexID,每一行分配一个 RowID(如果表有整数型的 Primary Key,那么会用 Primary Key 的值当做 RowID),其中 TableID 在整个集群内唯一,IndexID/RowID 在表内唯一,这些 ID 都是 int64 类型。 每行数据按照如下规则进行编码成 Key-Value pair:Key: tablePrefix_rowPrefix_tableID_rowID Value: [col1, col2, col3, col4] 其中 Key 的 tablePrefix/rowPrefix 都是特定的字符串常量,用于在 KV 空间内区分其他数据。 对于 Index 数据,会按照如下规则编码成 Key-Value pair:Key: tablePrefix_idxPrefix_tableID_indexID_indexColumnsValue Value: rowID Index 数据还需要考虑 Unique Index 和非 Unique Index 两种情况,对于 Unique Index,可以按照上述编码规则。但是对于非 Unique Index,通过这种编码并不能构造出唯一的 Key,因为同一个 Index 的 tablePrefix_idxPrefix_tableID_indexID_  都一样,可能有多行数据的 ColumnsValue  是一样的,所以对于非 Unique Index 的编码做了一点调整:Key: tablePrefix_idxPrefix_tableID_indexID_ColumnsValue_rowID Value:null 这样能够对索引中的每行数据构造出唯一的 Key。 注意上述编码规则中的 Key 里面的各种 xxPrefix 都是字符串常量,作用都是区分命名空间,以免不同类型的数据之间相互冲突,定义如下:var( tablePrefix = []byte{'t'} recordPrefixSep = []byte("_r") indexPrefixSep = []byte("_i") ) 另外请大家注意,上述方案中,无论是 Row 还是 Index 的 Key 编码方案,一个 Table 内部所有的 Row 都有相同的前缀,一个 Index 的数据也都有相同的前缀。这样具体相同的前缀的数据,在 TiKV 的 Key 空间内,是排列在一起。同时只要我们小心地设计后缀部分的编码方案,保证编码前和编码后的比较关系不变,那么就可以将 Row 或者 Index 数据有序地保存在 TiKV 中。这种保证编码前和编码后的比较关系不变 的方案我们称为 Memcomparable,对于任何类型的值,两个对象编码前的原始类型比较结果,和编码成 byte 数组后(注意,TiKV 中的 Key 和 Value 都是原始的 byte 数组)的比较结果保持一致。具体的编码方案参见 TiDB 的 codec 包。采用这种编码后,一个表的所有 Row 数据就会按照 RowID 的顺序排列在 TiKV 的 Key 空间中,某一个 Index 的数据也会按照 Index 的 ColumnValue 顺序排列在 Key 空间内。现在我们结合开始提到的需求以及 TiDB 的映射方案来看一下,这个方案是否能满足需求。首先我们通过这个映射方案,将 Row 和 Index 数据都转换为 Key-Value 数据,且每一行、每一条索引数据都是有唯一的 Key。其次,这种映射方案对于点查、范围查询都很友好,我们可以很容易地构造出某行、某条索引所对应的 Key,或者是某一块相邻的行、相邻的索引值所对应的 Key 范围。最后,在保证表中的一些 Constraint 的时候,可以通过构造并检查某个 Key 是否存在来判断是否能够满足相应的 Constraint。至此我们已经聊完了如何将 Table 映射到 KV 上面,这里再举个简单的例子,便于大家理解,还是以上面的表结构为例。假设表中有 3 行数据: “TiDB”, “SQL Layer”, 10 “TiKV”, “KV Engine”, 20 “PD”, “Manager”, 30 那么首先每行数据都会映射为一个 Key-Value pair,注意这个表有一个 Int 类型的 Primary Key,所以 RowID 的值即为这个 Primary Key 的值。假设这个表的 Table ID 为 10,其 Row 的数据为:t_r_10_1 --> ["TiDB", "SQL Layer", 10] t_r_10_2 --> ["TiKV", "KV Engine", 20] t_r_10_3 --> ["PD", "Manager", 30] 除了 Primary Key 之外,这个表还有一个 Index,假设这个 Index 的 ID 为 1,则其数据为:t_i_10_1_10_1 --> null t_i_10_1_20_2 --> null t_i_10_1_30_3 --> null 大家可以结合上面的编码规则来理解这个例子,希望大家能理解我们为什么选择了这个映射方案,这样做的目的是什么。元信息管理 上节介绍了表中的数据和索引是如何映射为 KV,本节介绍一下元信息的存储。Database/Table 都有元信息,也就是其定义以及各项属性,这些信息也需要持久化,我们也将这些信息存储在 TiKV 中。每个 Database/Table 都被分配了一个唯一的 ID,这个 ID 作为唯一标识,并且在编码为 Key-Value 时,这个 ID 都会编码到 Key 中,再加上 m_ 前缀。这样可以构造出一个 Key,Value 中存储的是序列化后的元信息。 除此之外,还有一个专门的 Key-Value 存储当前 Schema 信息的版本。TiDB 使用 Google F1 的 Online Schema 变更算法,有一个后台线程在不断的检查 TiKV 上面存储的 Schema 版本是否发生变化,并且保证在一定时间内一定能够获取版本的变化(如果确实发生了变化)。这部分的具体实现参见 TiDB 的异步 schema 变更实现一文。SQL on KV 架构 TiDB 的整体架构如下图所示TiKV Cluster 主要作用是作为 KV 引擎存储数据,上篇文章已经介绍过了细节,这里不再敷述。本篇文章主要介绍 SQL 层,也就是 TiDB Servers 这一层,这一层的节点都是无状态的节点,本身并不存储数据,节点之间完全对等。TiDB Server 这一层最重要的工作是处理用户请求,执行 SQL 运算逻辑,接下来我们做一些简单的介绍。SQL 运算 理解了 SQL 到 KV 的映射方案之后,我们可以理解关系数据是如何保存的,接下来我们要理解如何使用这些数据来满足用户的查询需求,也就是一个查询语句是如何操作底层存储的数据。 能想到的最简单的方案就是通过上一节所述的映射方案,将 SQL 查询映射为对 KV 的查询,再通过 KV 接口获取对应的数据,最后执行各种计算。 比如 Select count(*) from user where name="TiDB"; 这样一个语句,我们需要读取表中所有的数据,然后检查 Name 字段是否是 TiDB,如果是的话,则返回这一行。这样一个操作流程转换为 KV 操作流程: 构造出 Key Range:一个表中所有的 RowID 都在 [0, MaxInt64) 这个范围内,那么我们用 0 和 MaxInt64 根据 Row 的 Key 编码规则,就能构造出一个 [StartKey, EndKey) 的左闭右开区间 扫描 Key Range:根据上面构造出的 Key Range,读取 TiKV 中的数据 过滤数据:对于读到的每一行数据,计算 name="TiDB" 这个表达式,如果为真,则向上返回这一行,否则丢弃这一行数据 计算 Count:对符合要求的每一行,累计到 Count 值上面 这个方案肯定是可以 Work 的,但是并不能 Work 的很好,原因是显而易见的: 在扫描数据的时候,每一行都要通过 KV 操作同 TiKV 中读取出来,至少有一次 RPC 开销,如果需要扫描的数据很多,那么这个开销会非常大 并不是所有的行都有用,如果不满足条件,其实可以不读取出来 符合要求的行的值并没有什么意义,实际上这里只需要有几行数据这个信息就行 分布式 SQL 运算 如何避免上述缺陷也是显而易见的,首先我们需要将计算尽量靠近存储节点,以避免大量的 RPC 调用。其次,我们需要将 Filter 也下推到存储节点进行计算,这样只需要返回有效的行,避免无意义的网络传输。最后,我们可以将聚合函数、GroupBy 也下推到存储节点,进行预聚合,每个节点只需要返回一个 Count 值即可,再由 tidb-server 将 Count 值 Sum 起来。 这里有一个数据逐层返回的示意图:这里有一篇文章详细描述了 TiDB 是如何让 SQL 语句跑的更快,大家可以参考一下。SQL 层架构 上面几节简要介绍了 SQL 层的一些功能,希望大家对 SQL 语句的处理有一个基本的了解。实际上 TiDB 的 SQL 层要复杂的多,模块以及层次非常多,下面这个图列出了重要的模块以及调用关系:用户的 SQL 请求会直接或者通过 Load Balancer 发送到 tidb-server,tidb-server 会解析 MySQL Protocol Packet,获取请求内容,然后做语法解析、查询计划制定和优化、执行查询计划获取和处理数据。数据全部存储在 TiKV 集群中,所以在这个过程中 tidb-server 需要和 tikv-server 交互,获取数据。最后 tidb-server 需要将查询结果返回给用户。小结 到这里,我们已经从 SQL 的角度了解了数据是如何存储,如何用于计算。SQL 层更详细的介绍会在今后的文章中给出,比如优化器的工作原理,分布式执行框架的细节。 下一篇文章我们将会介绍一些关于 PD 的信息,这部分会比较有意思,里面的很多东西是在使用 TiDB 过程中看不到,但是对整体集群又非常重要。主要会涉及到集群的管理和调度。"}, {"url": "https://pingcap.com/blog/2017-05-23-perconalive17/", "title": "A Brief Introduction of TiDB", "content": " This is the speech Edward Huang gave at Percona Live - Open Source Database Conference 2017.The slides are here. Speaker introduction What would you do when… TiDB Project - Goal Sofware Stack Safe Split Scale Out ACID Transaction Distributed SQL TiDB SQL Layer Overview What Happens behind a query Distributed Join (HashJoin) Tools Matter Use Cases Sysbench Roadmap Speaker introduction As one of the three co-founders of PingCAP, I feel honored that PingCAP was once again invited to the Percona Live Conference.Last year, our CEO Max Liu has introduced TiDB and TiKV to the public. He mainly focused on how we build TiDB and also formulated a future plan of our projects. This time, I’ll draw a detailed picture of TiDB to help you understand how it works.First of all, I’d like to introduce myself. My name is Edward Huang, an infrastructure software engineer and the CTO of PingCAP.Up to now, I have worked on three projects, Codis, a proxy-based redis cluster solution which is very popular in China , TiDB and TiKV, a NewSQL database, our topic today. All of them are open source and many people benefit from them, especially in China. And I prefer languages such as Golang, Python, and Rust. By the way, we are using Golang and Rust in our projects (TiDB is written in Go and TiKV uses Rust).What would you do when… And first of all I want to ask a question: what would you do when your RDBMS is becoming the bottleneck of your application? Maybe most of you guys may have experienced the following situations. In the old days, all you can do is to either refactor your application or use database middleware, something like mysql proxy. But once you decide to use the sharding solution, you will never get rid of sharding key and say goodbye to complex query as it’s a one-way path.So how to scale your relational database is a pain point of the entire industry.Back to the topTiDB goal And there comes TiDB, when we were designing TiDB, we want to achieve the following goals: Make sharding and data movement transparent to users so that developers can focus on application development. 100% OLTP and 80% OLAP support. TiDB aims to be a hybrid database that supports both OLTP and OLAP. This is feasible because TiDB supports transactions and has our own full featured distributed SQL engine (including parser, optimizer and query executor). TiDB has to be compatible with the MySQL protocol, by implementing MySQL grammars and the network protocol. In this way, our users can reuse many MySQL tools and greatly reduce the migration costs. Twenty-four/Seven availability, even in case of datacenter outages. Thanks to the Raft consensus algorithm, TiDB can ensure the data consistency and availability all the time. Open source, of course. During the first section, I’ll talk about the technical overview of TiDB and TiKV project, including the storage layer, a brief walk through our distributed sql engine, and some tools for community users to migrate from MySQL to TiDB and vice versa. Secondly, I’ll introduce some real world cases and benchmarks. We got several users in China, which have already used TiDB in production for over 3 months. And in the end, I’ll do a quick demo of setting up a TiDB-cluster and have some queries on it.Architecture Below shows the TiDB architecture.In this diagram, there are three components: the SQL layer, which is TiDB; the distributed storage layer, which is TiKV; and Placement Driver, aka PD.These three components communicate with each other through gRPC. TiDB server is stateless. It doesn’t store data and it is for computing only. It translates user’s SQL statement and generates the query plan, which presents as the rpc calls of TiKV. TiKV is a distributed key value database, acting as the underlying storage layer of TiDB and it’s the place where data is actually stored. This layer uses Raft consensus algorithm to replicate data and guarantee data safety. And TiKV also implements a distributed computing mechanism so that the sql layer would be able to do something like predicate push down or aggregate push down. Placement Driver is the managing component of the entire cluster and it stores the metadata, handles timestamp allocation request for ACID transaction, just like the TrueTime for Spanner, but we don’t have the hardware. What’s more, it’s controlling the data movement for dynamic workload balance and failover. Back to the topStorage stack Let’s dive deep into the storage stack of TiKV.As mentioned earlier, TiKV is the underlying storage layer where data is actually stored. More specifically, data is stored in RocksDB locally, which is the bottom layer of the TiKV architecture as you can see from this diagram. On top of RocksDB, we build a Raft layer.So what is Raft? Raft is a consensus algorithm that equals to Multi-Paxos in fault-tolerance and performance. It has several key features such as leader election, auto failover and membership changes. And Raft ensures that data is safely replicated. We have exposed the Raw Key Value API at this layer. If you want a scalable, highly available kv database, and don’t care about cross-row ACID transaction, you can use the Raw Key Value API for higher performance.The middle layer is MVCC, Multiversion concurrency control. The top two layers are transaction and grpc API. The API here is the transactional KV API.TiKV is written in Rust and the reason is that the storage layer is performance-critical and stability is first-class citizen of course. We only got c/c++ in the past, and now we have rust. Rust is great for infrastructure system software like database, operation system… Without any extra cost for GC, runtime and high performance. Another great thing is that Rust does a lot of innovation works to prevent memory leaks and data race, which means a lot to us.Now we know that the actual data is stored in RocksDB. But how exactly is data organized inside of the RocksDB instances? The answer is by Regions.Region is a set of continuous key-value pairs in byte-order.Back to the topSafe split Let’s take a look at the diagram here: The data is split into a set of continuous key-value pairs which we name them from a to z. Region 1 stores “a” to “e”, Region 2 “f” to “j”, Region 3 “k” to “o”, etc. As region is a logical concept, all the regions in a physical node share the same rocksdb instance.In each RocksDB instance, as I just mentioned, there are several regions and each region is replicated to other instances by Raft. The replicas of the same Region, Region 4 for example, make a Raft group.The metadata of the raft groups is stored in Placement Driver, and of course, placement driver is a cluster, replicates the metadata by Raft, too.In TiKV, we adopt a multi-raft model. What’s multi-raft? It’s a way to split and merge regions dynamically, and of course, safely. We name this approach “safe split/merge”.For example, Region 1 from “a” to “e” is safely split into Region 1.1 “a” to “c” and Region 1.2 “d” to “e”, we need to guarantee no data is lost during the split.This explains how one Region is split, but how about its replicas on other nodes? Let me show you the process.This is the initial state for Region 1. You can see there is a Raft group with three TiKV nodes. Region 1 on TiKV1 is the Leader and the other two replicas are the followers.However, there comes a situation that there are too much data in Region 1 and it needs to be split.It’s easy if there is only one Region 1, but in this case, we have three replicas. How can all the replicas be split safely? The answer is also Raft. Let’s see how it works.The split is initiated by the Leader, which means Region 1 is split to Region 1.1 and Region 1.2 firstly in the Leader as you can see from the diagram.When the split-log is written to WAL in the Leader, it is replicated by Raft and sent to the followers. Then, the followers apply the split log, just like any other normal raft log.And finally, once the split-log is …"}, {"url": "https://pingcap.com/blog/2017-05-22-Comparison-between-MySQL-and-TiDB-with-tens-of-millions-of-data-per-day/", "title": "Migration from MySQL to TiDB to handle tens of millions of rows of data per day", "content": " Table of content Background MySQL, our first choice Look for new solutions TiDB, give it a go Feedbacks from TiDB Background GAEA is a mobile gaming provider and aims to develop high-quality games for international players. GAEA uses its GaeaAD system to support the cross-platform real-time advertising system. GaeaAD performs a real-time match between the advertising data and the information reported by the game SDK. In other words, GaeaAD conducts a real-time analysis based on the data of the advertisements on different advertising channels and the amount of players brought by the corresponding channels, with the purpose of displaying and optimizing the conversion effects of advertising within minutes.MySQL, our first choice Considering the amount of data and for a simplified implementation, GAEA chose the highly-available MySQL RDS storage solution at the very beginning of designing GaeaAD. At that time, we mainly used SQL Syntax to implement the matching logic, including many join table queries and aggregation operations. The system worked well and responded within one minute with tens of millions of rows of data. Look for new solutions However, with the growth of business, GaeaAD receives more than tens of millions of rows of data per day and the amount multiplies during peak hours. Obviously, database has become a bottleneck. And at the moment, GAEA’s entire technical framework encounters three problems: The time needed for a single match has increased to over 2 minutes from about 10 seconds. The slowest aggregation query, even takes 20 minutes to complete. This imposes a serious challenge on timeliness. What’s worse, one of the drawbacks of MySQL is the query time increases with the amount of data. Therefore, the larger the data volume, the slower the query. With the accumulation of historical data, the amount of data stored in a single table soon reaches a hundred million rows. At that time, the read/write capabilities of the single table are close to its limit. Due to the query performance mentioned above and the capacity limit of a standalone database, we have to delete data regularly. Thus, it is not possible to query the business data from a long time ago. According to the data volume growth, we thought that distributed database would be a good solution. Vertically and horizontally splitting business, the middleware solutions based on MySQL and some predominant NoSQL solutions were all taken into consideration.After a thorough assessment, we denied the solution of horizontally splitting business. Since the business logic contains lots of related queries and subqueries, it is impossible to achieve transparent compatibility if tables have been split. Besides, it is a core business system, we are not allowed to refactor it given the limited time and energy. The middleware solutions face similar problems with database sharding: even though it enables mass storage and real-time writing, it has a limited query flexibility. Moreover, the maintenance cost of multiple MySQL instances requires a second thought.Then we continued to analyze the second choice, NoSQL. Since this system needs to support the concurrent real-time writing and query from the business-end, it is not suitable to use systems like Greenplum, Hive or SparkSQL, which are not designed for real-time writing. As for MongoDB, its document query access interface is a challenge for our business. Besides, we were not sure whether MongoDB could perform the efficient aggregate analysis under the condition of such a large amount of data.In conclusion, what we want is a database that is as easy to use as MySQL, eliminating the trouble of modifying any business, and it meets the needs of distributed storage and a high performance of complex query.We studied many distributed database solutions in the community and came upon TiDB. As the protocol layer of TiDB is compatible with MySQL and it supports complex query, we can power our applications without changing a single line of code. Besides, there is hardly any migration cost.TiDB, give it a go In the process of test deployment, we used the Syncer tool, provided by TiDB, to deploy TiDB as a MySQL Slave to the MySQL master of the original business, testing the compatibility and stability of read/write. After a while, the system was proved to perform well in read/write so we decided to move the read request of the business layer to TiDB. Later, we also switch the write business to the TiDB cluster, making the system online smoothly.The GaeaAD system works well for more than half a year since it has come online in October, 2016. Based on the hands-on experience, we summarized the following benefits brought by TiDB: We replaced the highly-available MySQL RDS with the 3-node TiDB cluster. The average time needed for a single match reduces to about 30 seconds from over 2 minutes, and it even reaches to 10 seconds or so with the continuous optimization of TiDB’s engineers. In addition, we found that TiDB has superior advantages and outperforms MySQL especially when the data volume is large. We guess this owes to the existence of TiDB’s self-developed distributed SQL Optimizer. But when it comes to a small amount of data, this advantage is not that prominent because of the internal communication cost. (A comparison between the query time of TiDB and MySQL in cases of different amounts of data) TiDB supports automatic Sharding. The business side doesn’t need to split tables and TiDB no longer sets the Sharding key or partition table as a traditional database middleware product. Storage of the bottom layer automatically spreads across clusters according to the data distribution. The capacity and performance can be scaled horizontally through adding more nodes, greatly reducing the maintenance cost. TiDB supports ongoing rolling upgrades. Up to now, we have about 10 online upgrades and never experienced one interrupt, which shows TiDB’s excellent availability. TiDB supports the mutual backup with MySQL. This function solves the transition problem in business migration. Currently, we are replacing MongoDB with TiDB as MongoDB is not easy to use, expensive to maintain and its query manner is not as flexible as traditional SQL. MongoDB once served as our data storage system of the real-time computing business of the BI system in the storm cluster. We are also planning to migrate the business that requires high real-time performance, large storage capacity and long storage cycle to TiDB, which seems to be a suitable scenario.Feedbacks from TiDB TiDB helps GAEA in the following aspects: 1. TiDB supports many push-down expressions and makes full use of the computing resources of TiKV’s multiple instances and therefore, accelerates the computing speed. At the same time, TiDB filters as much unnecessary data as possible and reduces the network overhead. TiDB supports HashJoin by default and tries hard to parallelize operators, making full use of the computing resources of the entire cluster. TiDB reads data in a linear way and has optimized the IndexScan operator, shortening the startup time of the whole process. About the author:LIU Xuan, the senior development engineer of GAEA’s data platform, is responsible for the real-time data business and the data flow field. Graduated from College of Computer Science and Electronic Engineering of Hunan University, LIU was Baidu’s senior operation & maintenance engineer and was responsible for the database creating and maintenance of Search Service Group (SSG)."}, {"url": "https://pingcap.com/weekly/2017-05-22-tidb-weekly/", "title": "Weekly update (May 15 ~ May 21, 2017)", "content": " Weekly update in TiDB Last week, we landed 31 PRs in the TiDB repositories.Added Use etcd to elect DDL job leader. Support Load Data with specified column list. Add the following builtin functions: umcompress and uncompressdlength convert_tz period-diff Support the Json type and Json data encoding/decoding. Add a Jenkins CI in Pull Request. Add the EvalDuration and EvalTime interface for expressions. Support Index Lookup Join in new planner. Fixed Add default value for the Password Validation system variables. Fix the issue of retrying with no limitation when committing primary key failed. Fix the issue of context cancellation triggering onSendFail and dropping cache: context cancel doesn’t mean cache out of data. Fix a bug in Sort Merge Join. Correct comment mistakes. Reprocess SQL statement when meeting the infoschema change error. Update an error code to MySQL standard error code. Consider schema changing when retrying prepared statement. Improved Refator range calculation related code. Consider task type when building the physical plan: to make cost more precise. Support more SQL grammar for Lock Options. Rename SupportRequestType to IsRequestTypeSupported to improve readability. Support more SQL grammar for Compress Options in the AlterTable statement. Change the schema of statistic table. Weekly update in TiKV Last week, We landed 16 PRs in the TiKV repositories.Added Support table scan with DAG in coprocessor. Add Jenkins support, see 643, 644, 1835, 1836. Write Raft log synchronously to ensure data safety. Fixed Use IEC size for size output. Enlarge max duration for scheduler histogram metrics. Improved Use SmallGroupFirstQueue in endpoint scheduler. Fetch snapshot lazily to reduce the cost of creating unnecessary snapshot. Create WriteBatch with capacity to avoid reallocating. "}, {"url": "https://pingcap.com/weekly/2017-05-15-tidb-weekly/", "title": "Weekly update (May 08 ~ May 14, 2017)", "content": " Weekly update in TiDB Last week, we landed 28 PRs in the TiDB repositories.Added Add builtin function uncompress and uncompressdlength, convert_tz, period-diff Fill data into information_schema.key_column_usage. Add Open interface for Executor. Show warnings for Load Data statement. Support Json type and functions in parser. Support top-n operator in new planner. Fixed Consider session variable time_zone for timestamp datum. Fix data race problem in IndexLookup Executor. Fix a bug in HashJoin Executor encoding/decoding. Return right value for @@version. Improved Refator range calculation related code. Refactor expression evaluation framework: Add self attribute in builtin function.Return panic when calling wrong function on baseXBuiltinFunc. Weekly update in TiKV Last week, We landed 17 PRs in the TiKV repositories.Added Use clap to parse command line options. Show TiKV instance downtime state in pd-ctl. Show scheduling operation history in pd-ctl. Show cluster ID in pd-ctl. Introduce SmallGroupFirstQueue to speedup point get later. Use zstd compression type. Add process metrics in Prometheus. Fixed Fix dial wrong listening address bug. Remove the offline peer directly. Mark peer as pending_remove to avoid following operations. Improved Add the reason of cluster ID mismatch in error log. Add log to apply delegate register and deregister. "}, {"url": "https://pingcap.com/blog-cn/tidb-internal-1/", "title": "三篇文章了解 TiDB 技术内幕 - 说存储", "content": " 引言 数据库、操作系统和编译器并称为三大系统,可以说是整个计算机软件的基石。其中数据库更靠近应用层,是很多业务的支撑。这一领域经过了几十年的发展,不断的有新的进展。很多人用过数据库,但是很少有人实现过一个数据库,特别是实现一个分布式数据库。了解数据库的实现原理和细节,一方面可以提高个人技术,对构建其他系统有帮助,另一方面也有利于用好数据库。研究一门技术最好的方法是研究其中一个开源项目,数据库也不例外。单机数据库领域有很多很好的开源项目,其中 MySQL 和 PostgreSQL 是其中知名度最高的两个,不少同学都看过这两个项目的代码。但是分布式数据库方面,好的开源项目并不多。 TiDB 目前获得了广泛的关注,特别是一些技术爱好者,希望能够参与这个项目。由于分布式数据库自身的复杂性,很多人并不能很好的理解整个项目,所以我希望能写一些文章,自顶向上,由浅入深,讲述 TiDB 的一些技术原理,包括用户可见的技术以及大量隐藏在 SQL 界面后用户不可见的技术点。保存数据 数据库最根本的功能是能把数据存下来,所以我们从这里开始。保存数据的方法很多,最简单的方法是直接在内存中建一个数据结构,保存用户发来的数据。比如用一个数组,每当收到一条数据就向数组中追加一条记录。这个方案十分简单,能满足最基本,并且性能肯定会很好,但是除此之外却是漏洞百出,其中最大的问题是数据完全在内存中,一旦停机或者是服务重启,数据就会永久丢失。为了解决数据丢失问题,我们可以把数据放在非易失存储介质(比如硬盘)中。改进的方案是在磁盘上创建一个文件,收到一条数据,就在文件中 Append 一行。OK,我们现在有了一个能持久化存储数据的方案。但是还不够好,假设这块磁盘出现了坏道呢?我们可以做 RAID (Redundant Array of Independent Disks),提供单机冗余存储。如果整台机器都挂了呢?比如出现了火灾,RAID 也保不住这些数据。我们还可以将存储改用网络存储,或者是通过硬件或者软件进行存储复制。到这里似乎我们已经解决了数据安全问题,可以松一口气了。But,做复制过程中是否能保证副本之间的一致性?也就是在保证数据不丢的前提下,还要保证数据不错。保证数据不丢不错只是一项最基本的要求,还有更多令人头疼的问题等待解决: 能否支持跨数据中心的容灾? 写入速度是否够快? 数据保存下来后,是否方便读取? 保存的数据如何修改?如何支持并发的修改? 如何原子地修改多条记录? 这些问题每一项都非常难,但是要做一个优秀的数据存储系统,必须要解决上述的每一个难题。 为了解决数据存储问题,我们开发了 TiKV 这个项目。接下来我向大家介绍一下 TiKV 的一些设计思想和基本概念。Key-Value 作为保存数据的系统,首先要决定的是数据的存储模型,也就是数据以什么样的形式保存下来。TiKV 的选择是 Key-Value 模型,并且提供有序遍历方法。简单来讲,可以将 TiKV 看做一个巨大的 Map,其中 Key 和 Value 都是原始的 Byte 数组,在这个 Map 中,Key 按照 Byte 数组总的原始二进制比特位比较顺序排列。 大家这里需要对 TiKV 记住两点: 这是一个巨大的 Map,也就是存储的是 Key-Value pair 这个 Map 中的 Key-Value pair 按照 Key 的二进制顺序有序,也就是我们可以 Seek 到某一个 Key 的位置,然后不断的调用 Next 方法以递增的顺序获取比这个 Key 大的 Key-Value 讲了这么多,有人可能会问了,这里讲的存储模型和 SQL 中表是什么关系?在这里有一件重要的事情要说四遍:这里的存储模型和 SQL 中的 Table 无关! 这里的存储模型和 SQL 中的 Table 无关! 这里的存储模型和 SQL 中的 Table 无关! 这里的存储模型和 SQL 中的 Table 无关!现在让我们忘记 SQL 中的任何概念,专注于讨论如何实现 TiKV 这样一个高性能高可靠性的巨大的(分布式的) Map。RocksDB 任何持久化的存储引擎,数据终归要保存在磁盘上,TiKV 也不例外。但是 TiKV 没有选择直接向磁盘上写数据,而是把数据保存在 RocksDB 中,具体的数据落地由 RocksDB 负责。这个选择的原因是开发一个单机存储引擎工作量很大,特别是要做一个高性能的单机引擎,需要做各种细致的优化,而 RocksDB 是一个非常优秀的开源的单机存储引擎,可以满足我们对单机引擎的各种要求,而且还有 Facebook 的团队在做持续的优化,这样我们只投入很少的精力,就能享受到一个十分强大且在不断进步的单机引擎。当然,我们也为 RocksDB 贡献了一些代码,希望这个项目能越做越好。这里可以简单的认为 RocksDB 是一个单机的 Key-Value Map。Raft 好了,万里长征第一步已经迈出去了,我们已经为数据找到一个高效可靠的本地存储方案。俗话说,万事开头难,然后中间难,最后结尾难。接下来我们面临一件更难的事情:如何保证单机失效的情况下,数据不丢失,不出错?简单来说,我们需要想办法把数据复制到多台机器上,这样一台机器挂了,我们还有其他的机器上的副本;复杂来说,我们还需要这个复制方案是可靠、高效并且能处理副本失效的情况。听上去比较难,但是好在我们有 Raft 协议。Raft 是一个一致性算法,它和 Paxos 等价,但是更加易于理解。这里是 Raft 的论文,感兴趣的可以看一下。本文只会对 Raft 做一个简要的介绍,细节问题可以参考论文。另外提一点,Raft 论文只是一个基本方案,严格按照论文实现,性能会很差,我们对 Raft 协议的实现做了大量的优化,具体的优化细节可参考我司首席架构师 tangliu 同学的这篇文章。Raft 是一个一致性协议,提供几个重要的功能: Leader 选举 成员变更 日志复制 TiKV 利用 Raft 来做数据复制,每个数据变更都会落地为一条 Raft 日志,通过 Raft 的日志复制功能,将数据安全可靠地同步到 Group 的多数节点中。到这里我们总结一下,通过单机的 RocksDB,我们可以将数据快速地存储在磁盘上;通过 Raft,我们可以将数据复制到多台机器上,以防单机失效。数据的写入是通过 Raft 这一层的接口写入,而不是直接写 RocksDB。通过实现 Raft,我们拥有了一个分布式的 KV,现在再也不用担心某台机器挂掉了。Region 讲到这里,我们可以提到一个 非常重要的概念:Region。这个概念是理解后续一系列机制的基础,请仔细阅读这一节。前面提到,我们将 TiKV 看做一个巨大的有序的 KV Map,那么为了实现存储的水平扩展,我们需要将数据分散在多台机器上。这里提到的数据分散在多台机器上和 Raft 的数据复制不是一个概念,在这一节我们先忘记 Raft,假设所有的数据都只有一个副本,这样更容易理解。对于一个 KV 系统,将数据分散在多台机器上有两种比较典型的方案:一种是按照 Key 做 Hash,根据 Hash 值选择对应的存储节点;另一种是分 Range,某一段连续的 Key 都保存在一个存储节点上。TiKV 选择了第二种方式,将整个 Key-Value 空间分成很多段,每一段是一系列连续的 Key,我们将每一段叫做一个 Region,并且我们会尽量保持每个 Region 中保存的数据不超过一定的大小(这个大小可以配置,目前默认是 64mb)。每一个 Region 都可以用 StartKey 到 EndKey 这样一个左闭右开区间来描述。注意,这里的 Region 还是和 SQL 中的表没什么关系! 请各位继续忘记 SQL,只谈 KV。 将数据划分成 Region 后,我们将会做 两件重要的事情: 以 Region 为单位,将数据分散在集群中所有的节点上,并且尽量保证每个节点上服务的 Region 数量差不多 以 Region 为单位做 Raft 的复制和成员管理 这两点非常重要,我们一点一点来说。先看第一点,数据按照 Key 切分成很多 Region,每个 Region 的数据只会保存在一个节点上面。我们的系统会有一个组件来负责将 Region 尽可能均匀的散布在集群中所有的节点上,这样一方面实现了存储容量的水平扩展(增加新的结点后,会自动将其他节点上的 Region 调度过来),另一方面也实现了负载均衡(不会出现某个节点有很多数据,其他节点上没什么数据的情况)。同时为了保证上层客户端能够访问所需要的数据,我们的系统中也会有一个组件记录 Region 在节点上面的分布情况,也就是通过任意一个 Key 就能查询到这个 Key 在哪个 Region 中,以及这个 Region 目前在哪个节点上。至于是哪个组件负责这两项工作,会在后续介绍。对于第二点,TiKV 是以 Region 为单位做数据的复制,也就是一个 Region 的数据会保存多个副本,我们将每一个副本叫做一个 Replica。Replica 之间是通过 Raft 来保持数据的一致(终于提到了 Raft),一个 Region 的多个 Replica 会保存在不同的节点上,构成一个 Raft Group。其中一个 Replica 会作为这个 Group 的 Leader,其他的 Replica 作为 Follower。所有的读和写都是通过 Leader 进行,再由 Leader 复制给 Follower。 大家理解了 Region 之后,应该可以理解下面这张图:我们以 Region 为单位做数据的分散和复制,就有了一个分布式的具备一定容灾能力的 KeyValue 系统,不用再担心数据存不下,或者是磁盘故障丢失数据的问题。这已经很 Cool,但是还不够完美,我们需要更多的功能。MVCC 很多数据库都会实现多版本控制(MVCC),TiKV 也不例外。设想这样的场景,两个 Client 同时去修改一个 Key 的 Value,如果没有 MVCC,就需要对数据上锁,在分布式场景下,可能会带来性能以及死锁问题。 TiKV 的 MVCC 实现是通过在 Key 后面添加 Version 来实现,简单来说,没有 MVCC 之前,可以把 TiKV 看做这样的:Key1 -> Value Key2 -> Value …… KeyN -> Value 有了 MVCC 之后,TiKV 的 Key 排列是这样的:Key1-Version3 -> Value Key1-Version2 -> Value Key1-Version1 -> Value …… Key2-Version4 -> Value Key2-Version3 -> Value Key2-Version2 -> Value Key2-Version1 -> Value …… KeyN-Version2 -> Value KeyN-Version1 -> Value …… 注意,对于同一个 Key 的多个版本,我们把版本号较大的放在前面,版本号小的放在后面(回忆一下 Key-Value 一节我们介绍过的 Key 是有序的排列),这样当用户通过一个 Key + Version 来获取 Value 的时候,可以将 Key 和 Version 构造出 MVCC 的 Key,也就是 Key-Version。然后可以直接 Seek(Key-Version),定位到第一个大于等于这个 Key-Version 的位置。事务 TiKV 的事务采用的是 Percolator 模型,并且做了大量的优化。事务的细节这里不详述,大家可以参考论文以及我们的其他文章。这里只提一点,TiKV 的事务采用乐观锁,事务的执行过程中,不会检测写写冲突,只有在提交过程中,才会做冲突检测,冲突的双方中比较早完成提交的会写入成功,另一方会尝试重新执行整个事务。当业务的写入冲突不严重的情况下,这种模型性能会很好,比如随机更新表中某一行的数据,并且表很大。但是如果业务的写入冲突严重,性能就会很差,举一个极端的例子,就是计数器,多个客户端同时修改少量行,导致冲突严重的,造成大量的无效重试。其他 到这里,我们已经了解了 TiKV 的基本概念和一些细节,理解了这个分布式带事务的 KV 引擎的分层结构以及如何实现多副本容错。下一节会介绍如何在 KV 的存储模型之上,构建 SQL 层。"}, {"url": "https://pingcap.com/blog-cn/tile-row-store/", "title": "基于 Tile 连接 Row-Store 和 Column-Store", "content": " 在之前的 Kudu 的文章里面,我已经提到过,行列混存是一个非常有意思的研究方向,因为不同的存储方式有不同的针对应用场景,但作为技术人员,折腾是天性,所以大家都在研究如何融合行存和列存,让一个服务能尽量满足大部分应用需求,而这也是 TiDB 在努力的方向。在 Kudu Paper 里面说到,Kudu 首先在 mem 里面使用行存,但刷到硬盘之后,则使用的是列存,这当然是一个可以尝试的方式,但我觉得应该还有更多种的解决方式,于是找到了 CMU 的 Peloton 以及相关的 Paper,觉得有必要研究记录一下。Storage Model 很多时候,我喜欢用行存和列存,但看 Paper 的时候,发现都喜欢使用 NSM 和 DSM 来说明,这里就简单说明一下。NSM NSM 是 N-ary storage model 的简称,当然就是通常的行存了。NSM 主要针对 OLTP 场景,因为需要高性能的随机写入,NSM 的存储方式如下:NSM 不适用需要读取大量数据,并分析特定 column 的场景,因为 NSM 需要把整个 record 给读出来,在拿到对应的 column 数据分析,数据数据量很大,整个开销会很大。DSM DSM 是 decomposition storage model 的简称,也就是列存。DSM 主要针对 OLAP 场景,因为需要对一些特定的 column 进行快速扫描分析,DSM 的存储方式如下:DSM 当然就不适用与需要频繁随机更新的情况,因为任何写入,DSM 需要将 record 分开写入到不同的地方,写开销会很大。FSM 为了解决这个问题,就有了一个 FSM flexible storage model 来融合 NSM 和 DSM,在 Peloton 里面,它把这套系统叫做 HTAP (Hybrid Transactional/Analytical Processing),不同于 NSM 按照每行存放,以及 DSM 按照每列存放,FSM 将数据分成了多个区块,Peloton 里面叫做 Tile,上面的图显示的是两个 Tile,一个 Tile 包含了 ID,Image ID 以及 Name,而另一个 Tile 里面则是包含了 Price 和 Data。各个 Tile 里面数据是连续存放的。就是说,我们使用 Tile 来模拟了 DSM,在 Tile 里面则是 NSM。Tile-Based Architecture Peloton 使用 tiles 来抽象了 storage 这一层,在上面的 FSM 例子我们可以看到,Tile 可以将一个 table 进行垂直和水平切分。Peloton 使用 physical tile 来处理实际的 storage,然后用另一个 logical tile 来隐藏了 physical tile 的实现,让外面更容易使用。Physical Tile Physical tile 的最小存储单位是 tile tuple,一批 tile tuple 形成了一个 physical tile。而一批 physical tile 则组成一个 tile group。一个 table 则是有多个 tile group 组成。在上面的例子中,table 被分成了三个 tile group (A, B, C),每个 group 都有不同的 physical tiles。譬如 group A 就是由 tile A-1 和 A-2 组成,tile A-1 包含 table 前面三个 column ID,IMAGE-ID,和 NAME,而 tile A-2 则包含了 PRICE 和 DATA。使用 tile group,我们可以非常方便的支持 FSM。对于新插入的数据,通常是热点数据,我们会直接放到一个 OLTP 友好的 group 中,也就是 group 里面只有一个 tile(NSM)。当数据变冷之后,我们就将当前的 tile group 转成更 OLAP 优化的布局,也就是 group 里面可能有几个 tile 了。当 group 里面每个 tile 都只有一个 column 的时候,这其实就变成了 DSM 了。Logical Tile 使用 physical tile 的好处在于我们可以根据不同的情况将数据切分成不同的布局,但是这对于查询并不友好,因为数据在不同的 tile 里面。为了解决这个问题,Peloton 引入了 logical tile。Logical tile 隐藏了 physical tile 的具体实现,logical tile 的每个 column 可以指向一个或者多个 physical tiles 的 columns,每个 logical tile column 里面存储的是 tuple 在 physical tiles 里面的偏移位置。在上面的例子中,logical tile X 指向了两个 physical tiles A-1 和 A-2。 X 的第一个 column 指向了 physical tile A-1 的 ATTR-1 和 ATTR-2。而第一个 column 里面存放的 1,2,3 则是对应的 tuple 在 tile A-1 里面的偏移。譬如 1 就对应的是 (101, 201)。一个 logical tile column 也可以映射不同的 physical tile 的 columns。譬如上面 X 的第二个 column,就是对应的 tile A-1 的 ATTR-3 和 A-2 的 ATTR-1。当然一些 physical tile column 也可能不会有任何映射,譬如上面的 A-2 的 ATTR-2。使用 logical tile 的好处是很明显的,主要包括: Layout Transparency:logical tile 隐藏底层底层实际的存储实现,所以我们可以用不同的 engine 来满足不同的场景。 Vectorized Processing:使用 logical tile,我们可以一次进行一批向量处理,在一些场景下能极大的提升 CPU 性能。 Flexible Materialization:我们可以提前或者推迟的物化。在执行 query plan tree 的时候,甚至都能够动态去选择一个物化策略。 Caching Behavior:我们可以根据不同的维度去创建不同的 tile group,放到 cache 了,用来处理后续的查询。 Logical Tile Algebra Peloton 提供 algebra operators 来让外面更方便的使用。Operators 主要包括: Bridge:Bridge operators 连接的 logical tile 和 physical tile。譬如我们可以使用 sequential scan 和 index scan operators 去访问实际的数据,然后生成对应的 logical tile。而 materialize operator 则是将实际的 logical tile 转成实际的 physical tile。 Metadata:Logical tile 的 metadata 存放的一些关于底层 physical tile 的信息,以及一些 bitmap 来表明哪些 rows 在执行的时候必须被检查。Metadata 的 operators 只会改变 logical tile 的 metadata,并不会改变底层的 physical tile 的数据。譬如 projection operator 如果发现上层的 query plan 并不需要一些 attributes 了,就可以在 logical tile 里面移除。 Mutators :Mutator operators 会改变 table 的实际存储数据。譬如 insert operator 首先会重新构建 logical tile 的 tuple,然后在插入到对应的 table 里面,而 delete operator 则是删除 table 里面的数据,update operator 则是先在 logical tile 里面删除,在通过之前的 tuple 重新构建一个新版本的 tuple,在插入到 table。Mutators 同时也会控制 tuple 在 transaction 里面的可见性。 Pipeline Breakers:当我们给一个 query plan 生成对应的 query plan tree 之后,在 tree 上层的 operators 需要等待 children 的操作完成返回了,才能继续进行。譬如 join operator 需要处理多个 logical tiles,并且在这些 tiles 上面执行 predicate。首先,join operator 会构建一个 output logical tile,它的 schema 是根据输入的 logical tile 来构建的。然后 join operator 会遍历 input logical tile,如果发现满足 predicate,就将结果放到 output logical tile,下面是 join 的一个例子: Layout reorganization 虽然基于 Tile-Based Architecture 看起来很美好,但如果对于不同的 query,如果没有好的 tile 与其对应,那么其实根本就没啥用。 Peloton 采用的方法是定期对每个 table 计算出最优化的 storage layout,然后在根据这个 layout 重新组织 table。Peloton 使用一个轻量级的 monitor 来记录每个 query 访问的 attributes,用来确定哪一些 attributes 应该在新的 physical tile 里面放在一起。通常 Peloton 会收集 query 里面的 SELECT 和 WHERE 上面的 attributes。为了减少监控带来的开销,monitor 会随机的对 query 进行采样统计,并且 monitor 还需要保证不能只关注频繁的 transactional query,还需要关注一些不频繁的 analytical query,所以 Peloton 会也会记录 query 的 plan cost,并通过这些来给 analytical query 生成特定的 storage layout。Peloton 使用增量的方式进行 data layout 的 reorganization。对于一个给定的 tile group,Peloton 首先会将 data 拷贝到一个新的 layout 上面,同时会原子地用一个新的 tile group 来替换。任何并发的 delete 或者 update 操作都只会更新metadata 信息。新的 tile group 会有旧的 tile group metadata 的引用。如果一个 physical tile 没有被任何 logical tile 引用,那么 Peloton 就会将其回收。对于一个热点 tile group 来说,因为很可能一直在被 OLTP 的事务持续访问,所以 Peloton 并不会对这种 tile group 做 reorganization,只会等到数据变冷之后才会进行。因为 Peloton 使用的是通用的 MVCC 模式,所以一段时间之后,老版本的数据一定会变成冷数据,那么就可以开始 reorganization 了。Reorganization 通常就是将 layout 从 OLTP 友好的,逐渐变成 OLAP 友好的。小结 上面仅仅是介绍 Peloton 的一些实现 FSM 的机制,这里并没有介绍 MVCC,transaction 这些,因为这些对于数据库产品来说都几乎是标配的东西,原理上面差不多。这里仅仅是关注的是 Peloton 是如何做到行列混存的。简单来说,Peloton 使用 physical tile 将数据切分成了不同的单元,同时用 logical tile 来隐藏了相关的实现,并提供 algebra 让上层更方便的操作。在后台,统计 query 等信息,并定期增量的对 layout 进行 reorganization。不得不说,整个设计思路还是很巧妙的。TiKV 后面也会考虑行列混存,我们一直想同时搞定 OLTP + OLAP,但究竟采用哪些方案,还需要我们慢慢研究和思考,也欢迎对这块感兴趣的同学加入。"}, {"url": "https://pingcap.com/meetup/meetup-2017-05-13/", "title": "【Infra Meetup No.48】分布式对象存储面临的挑战", "content": " 今天的 Meetup,我们请到了来自白山云的张炎泼老师,为大家分享《分布式对象存储面临的挑战》。 本期讲师:张炎泼 (xp)30 年软件开发经验,物理系背叛者,设计师眼中的美工,bug maker,vim 死饭,悬疑片脑残粉。曾就职新浪,美团。现在白山云,不是白云山。在本次分享中,张炎泼老师从:海量小文件如何存储、如何节省存储成本、如何实现数据的自动恢复,三个方面,为大家进行了详细讲解。以下是本期 PPT 节选附:完整 PPT 下载链接 PingCAP Infra Meetup作为一个基础架构领域的前沿技术公司,PingCAP 希望能为国内真正关注技术本身的 Hackers 打造一个自由分享的平台。自 2016 年 3 月 5 日开始,我们定期在周六的上午举办 Infra Meetup,邀请业内大牛与大家深度探讨基础架构领域的前瞻性技术思考与经验。在这里,我们希望提供一个高水准的前沿技术讨论空间,让大家真正感受到自由的开源精神魅力。 "}, {"url": "https://pingcap.com/blog-cn/kudu/", "title": "Kudu - 一个融合低延迟写入和高性能分析的存储系统", "content": " Kudu 是一个基于 Raft 的分布式存储系统,它致力于融合低延迟写入和高性能分析这两种场景,并且能很好的嵌入到 Hadoop 生态系统里面,跟其他系统譬如 Cloudera Impala,Apache Spark 等对接。Kudu 很类似 TiDB。最开始,TiDB 是为了 OLTP 系统设计的,但后来发现我们 OLAP 的功能也越来越强大,所以就有了融合 OLTP 和 OLAP 的想法,当然这条路并不是那么容易,我们还有很多工作要做。因为 Kudu 的理念跟我们类似,所以我也很有兴趣去研究一下它,这里主要是依据 Kudu 在 2015 发布的 paper,因为 Kudu 是开源的,并且在不断的更新,所以现在代码里面一些实现可能还跟 paper 不一样了,但这里仅仅先说一下我对 paper 的理解,实际的代码我后续研究了在详细说明。为什么需要 Kudu? 结构化数据存储系统在 Hadoop 生态系统里面,通常分为两类: 静态数据,数据通常都是使用二进制格式存放到 HDFS 上面,譬如 Apache Avro,Apache Parquet。但无论是 HDFS 还是相关的系统,都是为高吞吐连续访问数据这些场景设计的,都没有很好的支持单独 record 的更新,或者是提供好的随机访问的能力。 动态数据,数据通常都是使用半结构化的方式存储,譬如 Apache HBase,Apache Cassandra。这些系统都能低延迟的读写单独的 record,但是对于一些像 SQL 分析这样需要连续大量读取数据的场景,显得有点捉紧见拙。 上面的两种系统,各有自己的侧重点,一类是低延迟的随机访问特定数据,而另一类就是高吞吐的分析大量数据。之前,我们并没有这样的系统可以融合上面两种情况,所以通常的做法就是使用 pipeline,譬如我们非常熟悉的 Kafka,通常我们会将数据快速写到 HBase 等系统里面,然后通过 pipeline,在导出给其它分析系统。虽然我们在一定层面上面,我们其实通过 pipeline 来对整个系统进行了解耦,但总归要维护多套系统。而且数据更新之后,并不能直接实时的进行分析处理,有延迟的开销。所以在某些层面上面,并不是一个很好的解决方案。Kudu 致力于解决上面的问题,它提供了简单的来处理数据的插入,更新和删除,同时提供了 table scan 来处理数据分析。通常如果一个系统要融合两个特性,很有可能就会陷入两边都做,两边都没做好的窘境,但 Kudu 很好的在融合上面取得了平衡,那么它是如何做到的呢?Keyword Tables 和 schemas Kudu 提供了 table 的概念。用户可以建立多个 table,每个 table 都有一个预先定义好的 schema。Schema 里面定义了这个 table 多个 column,每个 column 都有名字,类型,是否允许 null 等。一些 columns 组成了 primary key。可以看到,Kudu 的数据模型非常类似关系数据库,在使用之前,用户必须首先建立一个 table,访问不存在的 table 或者 column 都会报错。用户可以使用 DDL 语句添加或者删除 column,但不能删除包含 primary key 的 column。但在 Paper 里面说到 Kudu 不支持二级索引以及除了 primary key 之外的唯一索引,这个后续可以通过更新的代码来确定下。其实我这里非常关注的是 Kudu 的 Online DDL 是如何做的,只是 Paper 里面貌似没有提及,后面只能看代码了。API Kudu 提供了 Insert,Update 和 Delete 的 write API。不支持多行事务 API,这个不知道最新的能支持了没有,因为仅仅能对单行数据操作,还远远不够。Kudu 提供了 Scan read API 让用户去读取数据。用户可以指定一些特定的条件来过滤结果,譬如用一个常量跟一个 column 里面的值比较,或者一段 primary key 的范围等条件。提供 API 的好处在于实现简单,但对于用户来说,其实更好的使用方式仍然是 SQL,一些复杂的查询最好能通过 SQL 搞定,而不是让用户自己去 scan 数据,然后自己组装。一致性模型 Kudu 提供两种一致性模型:snapshot consistency 和 external consistency。默认 Kudu 提供 Snapshot consistency, 它具有更好的读性能,但可能会有 write skew 问题。而 External consistency 则能够完全保证整个系统的 linearizability,也就是当写入一条数据之后,后面的任何读取都一定能读到最新的数据。为了实现 External consistency,Kudu 提供了几种方法: 在 clients 之间显式地传递时间戳。当写入一条数据之后,用户用要求 client 去拿一个时间戳作为 token,然后通过一个 external channel 的方式传递给另一个 client。然后另一个 client 就可以通过这个 token 去读取数据,这样就一定能保证读取到最新的数据了。不过这个方法实在是有点复杂。 提供类似 Spanner 的 commit-wait 机制。当写入一条数据之后,client 需要等待一段时间来确定写入成功。Kudu 并没有采用 Spanner TrueTime 的方案,而是使用了 HybridTime 的方案。HybridTime 依赖 NTP,这个可能导致 wait 的时间很长,但 Kudu 认为未来随着 read-time clock 的完善,这应该不是问题了。 Kudu 是我已知的第二个采用 HybridTime 来解决 External consistency 的产品,第一个当然就是 CockroachDB 了。TiDB 跟他们不一样,我们采用的是全局授时的方案,这个会简单很多,但其实也有跟 PD 交互的网络开销。后续TiDB 可能使用类似 Spanner 的 GPS + 原子钟,现阶段相关硬件的制造方式 Google 并没有说明,但其实难度不大。因为已经有很多硬件厂商主动找我们希望一起合作提供,只是比较贵,而现阶段我们大多数客户并没有跨全球事务这种场景。Kudu 的一致性模型依赖时间戳,这应该是现在所有分布式系统通用的做法。Kudu 并没有给用户保留时间戳的概念,主要是觉得用户很可能会困惑,毕竟不是所有的用户都能很好的理解 MVCC 这些概念。当然,对于 read API,还是允许用户指定特定的一个时间戳,这样就能读取到历史数据。这个 TiDB 也是类似的做法,用户不知道时间戳,只是我们额外提供了一个设置 snapshot 的操作,让用户指定生成某个时间点的快照,读取那个时间点的数据。这个功能已经帮很多公司恢复了因为错误操作写坏的数据了。架构 上面说了一些 Kudu 的 keyword, 现在来说说 Kudu 的整体架构。Kudu 类似 GFS,提供了一个单独的 Master 服务,用来管理整个集群的元信息,同时有多个 Tablet 服务,用来存储实际的数据。分区 Kudu 支持对数据按照 Range 以及 Hash 的方式进行分区。 每个大的 table 都可以通过这种方式将数据分不到不同的 Tablet 上面。当用户创建一个表的时候,同时也可以指定特定的 partition schema,partition schema 会将 primary key 映射成对应的 partition key。每个 Tablet 上面会覆盖一段或者多段 partition keys 的range。当 client 需要操作数据的时候,它可以很方便的就知道这个数据在哪一个 Tablet 上面。一个 partition schema 可以包括 0 或者多个 hash-partitioning 规则和最多一个 range-partitioning 规则。用户可以根据自己实际的场景来设置不同的 partition 规则。譬如有一行数据是 (host, metric, time, value),time 是单调递增的,如果我们将 time 按照 hash 的方式分区,虽然能保证数据分散到不同的 Tablets 上面,但如果我们想查询某一段时间区间的数据,就得需要全部扫描所有的 Tablets 了。所以通常对于 time,我们都是采用 range 的分区方式。但 range 的方式会有 hot range 的问题,也就是同一个时间会有大量的数据写到一个 range 上面,而这个 hot range 是没法通过 scale out 来缓解的,所以我们可以将 (host, metric) 按照 hash 分区,这样就在 write 和 read 之间提供了一个平衡。通过多个 partition 规则组合,能很好的应对一些场景,但同时这个这对用户的要求比较高,他们必须更加了解 Kudu,了解自己的整个系统数据会如何的写入以及查询。现在 TiDB 还只是单纯的支持 range 的分区方式,但未来不排除也引入 hash。Raft Kudu 使用 Raft 算法来保证分布式环境下面数据一致性,这里就不再详细的说明 Raft 算法了,因为有太多的资料了。Kudu 的 heartbeat 是 500 毫秒,election timeout 是 1500 毫秒,这个时间其实很频繁,如果 Raft group 到了一定量级,网络开销会比较大。另外,Kudu 稍微做了一些 Raft 的改动: 使用了 exponential back-off 算法来处理 leader re-election 问题。 当一个新的 leader 跟 follower 进行交互的时候,Raft 会尝试先找到这两个节点的 log 分叉点,然后 leader 再从这个点去发送 log。Kudu 直接是通过 committedIndex 这个点来发送。 对于 membership change,Kudu 采用的是 one-by-one 算法,也就是每次只对一个节点进行变更。这个算法的好处是不像 joint consensus 那样复杂,容易实现,但其实还是会有一些在极端情况下面的 corner case 问题。当添加一个新的节点之后,Kudu 首先要走一个 remote bootstrap 流程。 将新的节点加入到 Raft 的 configuration 里面 Leader 发送 StartEmoteBootstrap RPC,新的 follower 开始拉去 snapshot 和之后的 log Follower 接受完所有数据并 apply 成功之后,开始响应 Raft RPC 可以看到,这个流程跟 TiKV 的做法类似,这个其实有一个缺陷的。假设我们有三个节点,加入第四个之后,如果新的节点还没 apply 完 snapshot,这时候挂掉了一个节点,那么整个集群其实是没法工作的。为了解决这个问题,Kudu 引入了 PRE_VOTER 概念。当新的节点加入的时候,它是 PRE_VOTE 状态,这个节点不会参与到 Raft Vote 里面,只有当这个节点接受成功 snapshot 之后,才会变成 VOTER。当删除一个节点的时候,Leader 直接提交一个新的 configuration,删除这个节点,当这个 log 被 committed 之后,这个节点就把删除了。被删除的节点有可能不知道自己已经被删除了,如果它长时间没有收到其他的节点发过来的消息,就会问下 Master 自己还在不在,如果不在了,就自己干掉自己。这个做法跟 TiKV 也是类似的。Master Kudu 的 Master 是整个集群最核心的东西,类似于 TiKV 里面的 PD。在分布式系统里面,一些系统采用了无中心化的架构设计方案,但我个人觉得,有一个中心化的单点,能更好的用全局视角来控制和调度整个系统,而且实现起来很简单。在 Kudu 里面,Master 自己也是一个单一的 Tablet table,只是对用户不可见。它保存了整个集群的元信息,并且为了性能,会将其全部缓存到内存上面。因为对于集群来说,元信息的量其实并不大,所以在很长一段时间,Master 都不会有 scale 的风险。同时 Master 也是采用 Raft 机制复制,来保证单点问题。这个设计其实跟 PD 是一样的,PD 也将所有的元信息放到内存。同时,PD 内部集成 etcd,来保证整个系统的可用性。跟 Kudu Master 不一样的地方在于,PD 是一个独立的组件,而 Kudu 的 Master 其实还是集成在 Kudu 集群里面的。Kudu 的 Master 主要负责以下几个事情:Catalog manager Master 的 catalog table 会管理所有 table 的一些元信息,譬如当前 table schema 的版本,table 的 state(creating,running,deleting 等),以及这个 table 在哪些 Tables 上面。当用户要创建一个 table 的时候,首先 Master 在 catalog table 上面写入需要创建 table 的记录,table 的 state 为 CREATING。然后异步的去选择 Tablet servers 去创建相关的元信息。如果中间 Master 挂掉了,table 记录里面的 CREATING state 会表明这个 table 还在创建中,新的 Master leader 会继续这个流程。Cluster coordinator 当 Tablet server 启动之后,会给 Master 注册,并且持续的给 Master 进行心跳汇报消后续的状态变化。虽然 Master 是整个系统的中心,但它其实是一个观察者,它的很多信息都需要依赖 Tablet server 的上报,因为只有 Tablet server 自己知道当前自己有哪一些 tablet 在进行 Raft 复制,Raft 的操作是否执行成功,当前 tablet 的版本等。因为 Tablet 的状态变更依赖 Raft,每一次变更其实就在 Raft log 上面有一个对应的 index,所以上报给 Master 的消息一定是幂等的,因为 Master 自己会比较 tablet 上报的 log index 跟当前自己保存的 index,如果上报的 log index 是旧的,那么会直接丢弃。这个设计的好处在于极大的简化了整个系统的设计,如果要 Master 自己去负责管理整个集群的状态变更,譬如 Master 给一个 tablet 发送增加副本的命令,然后等待这个操作完成,在继续处理后面的流程。整个系统光异常处理,都会变得特别复杂,譬如我们需要关注网络是不是断开了,超时了到底是成功了还是失败了,要不要再去 tablet 上面查一下?相反,如果 Master 只是给 tablet 发送一个添加副本的命令,然后不管了,剩下的事情就是一段时间后让 tablet 自己上报回来,如果成功了继续后面的处理,不成功则尝试在加一次。虽然依赖 tablet 的上报会有延迟(通常情况,只要有变动,tablet 会及时的上报通知,所以这个延迟其实挺小的),整个架构简单了很多。其实看到这里的时候,我觉得非常的熟悉,因为我们也是采用的这一套架构方案。最开始设计 PD 的时候,我们还设想的是 PD 主动去控制 TiKV,也就是我上面说的那套复杂的发命令流程。但后来发现实在是太复杂了,于是改成 TiKV 主动上报,这样 PD 其实就是一个无状态的服务了,无状态的服务好处就是如果挂了,新启动的 PD 能立刻恢复(当然,实际还是要做一些很多优化工作的)。Tablet directory 因为 Master 知道集群所有的信息,所以当 client 需要读写数据的时候,它一定要先跟 Master 问一下对应的数据在哪一个 Tablet server 的 tablet 上面,然后才能发送对应的命令。如果每次操作都从 Master 获取信息,那么 Master 铁定会成为一个性能瓶颈,鉴于 tablet 的变更不是特别的频繁,所以很多时候,client 会缓存访问的 tablet 信息,这样下次再访问的时候就不用从 Master 再次获取。因为 tablet 也可能会变化,譬如 leader 跑到了另一个 server 上面,或者 tablet 已经不在当前 server 上面,client 会收到相关的错误,这时候,client 就重新再去 Master 获取一下最新的路由信息。这个跟我们的做法仍然是一样的,client 缓存最近的路由信息,当路由失效的时候,重新去 PD 获取一下。当然,如果只是单纯的 leader 变更,其实返回的错误里面通常就会带上新的 leader 信息,这时候 client 直接刷新缓存,在直接访问了。Tablet storage Tablet server 是 Kudu 用来存放实际数据的服务,为了更好的性能,Kudu 自己实现了一套 tablet storage,而没有用现有的开源解决方案。Tablet storage 目标主要包括: 快速的按照 Column 扫描数据 低延迟的随机更新 一致的性能 RowSets Tablets 在 Kudu 里面被切分成更小的单元,叫做 RowSets。一些 RowSets 只存在于内存,叫做 MemRowSets,而另一些则是使用 disk 和 memory 共享存放,叫做 DiskRowSets。任何一行数据只存在一个 RowSets 里面。在任何时候,一个 tablet 仅有一个单独的 MemRowSet 用来保存最近插入的数据。后台有一个线程会定期的将 这些 MemRowSets 刷到 disk 上面。当一个 MemRowSet 被刷到 disk 之后,一个新的空的 MemRowSet 被创建出来。之前的 MemRowSet 在刷到 disk 之后,就变成了 DiskRowSet。当刷的同时,如果有新的写入,仍然会写到这个正在刷的 MemRowSet 上面,Kudu 有一套机制能够保证新写入的数据也能一起被刷到 disk 上面。MemRowSet MemRowSet 是一个支持并发,提供锁优化的 B-tree,主要基于 MassTree,也有一些不同: 因为 Kudu 使用的是 MVCC,所以任何的删除其实也是插入,所以这个 tree 没有删除操作。 不支持任意的 in-place 数据变更操作,除非这次操作不会改变 value 的大小。 将 Leaf link 起来,类似 B+-tree,这样对于 scan 会有明显的性能提升。 并没有完全实现 trie of trees,是只是使用了一个单一 tree,因为 Kudu 并没有太多高频随机访问的场景。 DiskRowSet 当 MemRowSets 被刷到 disk 之后,就变成了 DiskRowSets。 …"}, {"url": "https://pingcap.com/weekly/2017-05-08-tidb-weekly/", "title": "Weekly update (May 01 ~ May 07, 2017)", "content": " Weekly update in TiDB Last week, we landed 33 PRs in the TiDB repositories.Added Add builtin function is_ipv4_mapped, makedate, utc_time Enable privilege checking by default. You could also disable privilege checking through --privilege=false. Support Analyze Index statement: after adding an index, we could run this statement to analyze the newly added index. Add Trigger_priv column in mysql.user system table. Add coveralls in CI. Fixed Fix incompatible issue in found_rows(). Fix a few panic when infering type for some functions without argument. Fix a data race in Join operator. Fix parse time_zone -6:00. Fix a bug in checking duplicate column. Check ignored errors. Fix comment warning in executor package. Fix a bug about converting string to bit. Recognize uuid() as a dynamic function. Fix a bug in rand() with seed. Improved Enlarge the stack size to save the runtime.morestack cost. Parallelly prewrite primary and secondary lock. New planner framework: SortMergeJoin, IndexReader Refactor expression evaluation framework: Rewrite compare operator. Implement the new Eval interface for ColumnExpr and ConstExpr. Decide the return type of ColumnExpr and ConstExpr during planning. Weekly update in TiKV Last week, We landed 13 PRs in the TiKV repositories.Added Apply the Raft logs of multiply regions in batches. Add hotspot command in pd-ctl: detect and show hotspot regions. Add sub-compaction, base-background-compactions and writable-file-max-buffer-size for RocksDB. Let manual compaction run concurrently with background compaction. Fixed Create column family orderly. Remove CRC32 checksum when initializing snapshot in RaftStore thread. Get the correct position in the pending vote queue. Remove old operator limiter when adding new PriorityKind operator. Improved Use channel to reduce lock contention when pushing task to thread pool. Make scheduler more smooth when starting PD. "}, {"url": "https://pingcap.com/meetup/meetup-2017-05-06/", "title": "【Infra Meetup No.47】分布式定时任务中间件架构 Elastic-Job 的两种实现", "content": " 今天的 Meetup ,我们请到了当当架构部负责人张亮,大家分享了《分布式定时任务中间件架构 Elastic-Job 的两种实现》。 本期讲师:张亮当当架构部负责人,主要负责分布式中间件以及私有云平台的搭建。致力于开源,目前主导两个开源项目 elastic-job 和 sharding-jdbc。擅长以 java 为主分布式架构以及以 Mesos 为主的云平台方向,推崇优雅代码,对如何写出具有展现力的代码有较多研究。今日帝都依然大风,但小伙伴们学习的热情丝毫未减哦~在本次分享中,张亮老师从分布式定时任务中间件的适用场景,轻量级去中心化架构方案以及基于 Mesos 的中心化架构方案,三个方面为大家进行了详细讲解。在互联网应用中,各式各样的定时任务存于系统的各个角落,我们希望由一个平台统一将这些作业管理起来。然而,一旦平台中运行大量的作业,发现异常作业并手动处理难免会感到繁琐,同时人工处理还会带来很多其他的额外成本。如何最大限度的减少人工干预?高可用可以让作业在被系统发现宕机之后能自动切换。而弹性化可以认为是高可用的进阶版本,在高可用的同时还能够提升效率和充分利用资源。对于动态的扩容和缩容,通常采用分片的方式实现。去中心化架构是指所有的作业节点都是对等的,优点是轻量级,部署成本低;缺点则是,如果各作业服务器时钟不一致会产生同一作业的不同分片运行有先有后,缺乏统一调度,并且不能跨语言。中心化架构将系统分为调度节点和执行节点,可以解决服务器时间差以及跨语言的问题;缺点是部署和运维稍复杂。Elastic-Job 最初的版本分离于当当内部的应用框架 ddframe,是一个纯 Java 实现的分布式方案,参照 dubbo 的方式,提供无中心化解决方案。如今,Elastic-Job 已开源近 2 年,截止目前已更新发布18 次,GitHub Star 数近 2000,成绩出色。更有多个开源产品衍生自 Elastic-Job。应小伙伴们的强烈要求,张亮老师临时加场 Demo 演示。最后,还有超多第一手爆料,是属于现场听讲小伙伴们的专属福利 ✌️ 很心动?下周六,老时间,老地点,PingCAP 第 48 期 Infra Meetup 等你呦! PingCAP Infra Meetup作为一个基础架构领域的前沿技术公司,PingCAP 希望能为国内真正关注技术本身的 Hackers 打造一个自由分享的平台。自 2016 年 3 月 5 日开始,我们定期在周六的上午举办 Infra Meetup,邀请业内大牛与大家深度探讨基础架构领域的前瞻性技术思考与经验。在这里,我们希望提供一个高水准的前沿技术讨论空间,让大家真正感受到自由的开源精神魅力。 "}, {"url": "https://pingcap.com/weekly/2017-05-02-tidb-weekly/", "title": "Weekly update (April 24 ~ April 30, 2017)", "content": " Weekly update in TiDB Last week, we landed 49 PRs in the TiDB repositories.Added Add builtin function truncate, makedate, utc_time Add pre-commit hook. Add a plan for Analyze. Add a check list about the things that contributors should think about before sending a PR. Support ENGINE option with partition option in table definition. Add code review guide. Fixed Fix bug in converting string to hex/bit. Fix a few panic when infering type for some functions without argument. Fix a data race in Join operator. Improved Add countReliable attribute in physicalPlanInfo: In CBO phrase, when row count is estimated by real statistics or limit clause, the cost is reliable. Refactor TypeInferer: Add a few interfaces for evaluate expression, Refine EvalBool, Refactor planner: Union, Hash Aggregate, Union Scan, Join, Apply, Refine code Refactor executor: Table Scan Improve contribute guide. Make goword happy in the following package: ddl, util, tablecodec, expression, bootstrap, model, table, ast, perfschema Add a few empty memory tables in information_schema: Make DTS happy. When where expresion can be converted to false, use dual table instead of a read table. New Contributors Thank you guys! lkk2003rty Ce Gao Zejun Li Weekly update in TiKV Last week, We landed 16 PRs in the TiKV repositories.Added Let the right split region derive the parent region information. Add a hot region scheduler. Introduce structure log and support JSON format. Use --data-dir instead of --store for TiKV storage path. Fixed Support idempotent bootstrap for TiKV. Detect snapshot in all nodes. Use non-system port to avoid test failed. Improved Throttle big query to reduce the influence on the point query. Add test for applying entries. Use a better mechanism when re-connecting PD. Ignore unnecessary message size computing. "}, {"url": "https://pingcap.com/meetup/meetup-2017-04-22/", "title": "【Infra Meetup No.46】MySQL 5.7 的特性及实践", "content": " 今天的 Meetup,我们邀请到了熊猫直播 DBA 杨尚刚老师,为大家分享《MySQL 5.7 的特性及实践》~ 讲师介绍:杨尚刚,熊猫直播高级 DBA,负责后端数据库平台建设和架构设计。前新浪高级数据库工程师,负责新浪微博核心数据库架构改造优化,以及数据库相关的服务器存储选型设计。 2015 年最重磅的当属 MySQL 5.7 GA 的发布,号称 160 万只读 QPS,大有赶超 NoSQ L趋势。不过官方的硬件测试环境是很高的,所以这个 160 万 QPS 对于大家测试来说,可能还比较遥远,所以实际测试的结果可能会失望。但是,至少我们看到了基于同样测试环境,MySQL 5.7 在性能上的改进,对于多核利用的改善。本次分享中,杨老师讲解了 MySQL 5.7 在运维、优化器 Server 层、InnoDB 层等方面的优化,以及 MySQL 未来的发展趋势。运维方面 动态修改 Buffer Pool MySQL redo log大小 innodb_file_per_table query cache SQL_Mode binlog_rows_query_log_events max_execution_time replication info in tables innodb_numa_interleave 动态修改 replication filter 优化器 Server 层改进 优化器主要还是基于 cost model 层面和给用户更多自主优化。可配置cost based optimizer、mysql.server_cost 和mysql.engine_cost。New JSON 数据类型和函数支持。当然 JSON 也可以存在 Text 或 VARCHAR 里用内置 json,更容易访问,方便修改。支持生成列(虚拟列),以及虚拟列上索引。5.7 还对 explain 做了增强,对于当前正在运行查询 explain。InnoDB 层优化 InnoDB 层核心还是拆分各种锁,提高并发。只读事务优化就是其中一个例子。atomic write,disable double write支持 spatial index 空间索引。Transparent page compressionperformance_schema 改进新增加的 sys 数据库。Replication 改进。最大的亮点 GTID 增强,支持在线调整 GTID。使用 mysqlbinlog 作为伪 slave 是个不错方案。并行复制优化,Database 5.6 默认并行复制,logical-clock 5.7 引入。5.7 引入的 group replication 也是为了提高可用性。多主复制,多点写入,内部检测冲突,保证一致性,自动探测。支持 GTID,共享 UUID,只支持 InnoDB,不支持并发 DDL。讲师总结 从整体来说,MySQL 5.7 做的改进还是非常有吸引力的,不论是从运维角度还是性能优化上,当然真正在生产环境上遇到问题时在所难免的,要做好踩坑的准备。 PingCAP Infra Meetup作为一个基础架构领域的前沿技术公司,PingCAP 希望能为国内真正关注技术本身的 Hackers 打造一个自由分享的平台。自 2016 年 3 月 5 日开始,我们定期在周六的上午举办 Infra Meetup,邀请业内大牛与大家深度探讨基础架构领域的前瞻性技术思考与经验。在这里,我们希望提供一个高水准的前沿技术讨论空间,让大家真正感受到自由的开源精神魅力。 "}, {"url": "https://pingcap.com/blog-cn/talk-cloud-native/", "title": "演讲实录|黄东旭:Cloud-Native 的分布式数据库架构与实践", "content": " 4 月 19 日,我司 CTO 黄东旭同学在全球云计算开源大会上,发表了《Cloud-Native 的分布式数据库架构与实践》主题演讲,以下为演讲实录。实录 大家好,今天我的题目是 Cloud-Native 与分布式数据库的实践。先简单的介绍一下自己,我是 PingCAP 的联合创始人和 CTO,过去一直在做基础软件领域的工程师,基本上做的所有的东西都是开源。在分享之前我想说一下为什么现在各行各业或者整个技术软件社区一直在重复的再造数据库,现在数据库到底怎么了,为什么这么百花齐放? 首先随着业务的多种多样,还有不管是传统行业还是互联网行业,业务的迭代速度越来越互联网化,使得整个数据量其实是一直在往上走的; 第二就是随着 IOT 的设备还有包括像手机、移动互联网蓬勃的发展,终端其实也不再仅仅是传统的 PC 客户端的数据的接入; 第三方面随着现在 AI 或者大数据分析一些模型或者理论上的突破,使得在大数据上进行计算的手段越来越多样,还有在物理上一些硬件的新的带有保护的内存,各种各样新的物理的设备,越来越多的硬件或者物理上的存储成本持续的降低,使得我们的数据库需要要面对更多的挑战。 关联数据库理论是上世纪七十年代做出来的东西,现在四十年过去不管是物理的环境还是计算模型都是完全不一样的阶段,还抱着过去这种观念可能并不是一个面向未来的设计。而且今天我的题目是 Cloud-Native,有一个比较大胆的假设,大家在过去三十年的计算平台基本都是在一台 PC 或者一个服务器或者一个手机这样的独立的计算平台,但是未来我觉得一切的服务都应该是分布式的。因为我觉得摩尔定律已经失效了,所以未来的操作系统会是一个大规模分布式的操作系统,在上面跑的任何的进程,任何的服务都应该是分布式的,在这个假设下怎么去做设计,云其实是这个假设最好的载体。怎么在这个假设上去设计面向云的技术软件,其实是最近我一直在思考的一个问题。其实在这个时代包括面向云的软件,对业务开发来说尽量还是不要太多的改变过去的开发习惯。你看最近大数据的发展趋势,从最传统的关系数据库到过去十年相比,整个改变了用户的编程模型,但是改变到底是好的还是不好的,我个人觉得其实并不是太好。最近这两年大家会看到整个学术圈各种各样的论文都在回归,包括 DB 新时代的软件都会把扩展性和分布式放在第一个要素。大家可能听到主题会有点蒙,叫 Cloud-Native,Cloud-Native 是什么?其实很早的过去也不是没有人做过这种分布式系统的尝试,最早是 IBM 提出面向服务的软件架构设计,最近热门的 SOA、Micro Service 把自己的服务拆分成小的服务,到现在谷歌一直对外输出一个观点就是 Cloud-Native,就是未来大家的业务看上去的分布式会变成一个更加透明的概念,就是你怎么让分布式的复杂性消失在云的基础设施后,这是 Cloud-Native 更加关心的事情。这个图是 CNCF 的一个基金会,也是谷歌支持的基金会上扒过来的图。这里面有一个简单的定义,就是 SCALE 作为一等公民,面向 Cloud-Native 的业务必须是弹性伸缩的,不仅能伸也得能缩;第二就是在对于这种 Cloud-Native 业务来说是面向 Micro service 友好;第三就是部署更加的去人工化。最近大家可能也看到很多各种各样容器化的方案,背后代表的意义是什么?就是整个运维和部署脱离人工,大家可以想象过去十几二十年来,一直以来运维的手段是什么样的。我找了一个运维,去买服务器,买服务器装系统,在上面部署业务。但是现在 Cloud-Native 出现变得非常的自动化,就相当于把人的功能变得更低,这是很有意义的,因为理想中的世界或者未来的世界应该怎么样,一个业务可能会有成百上千的物理节点,如果是人工的去做运维和部署是根本不可能做得到的,所以其实构建整个 Cloud-Native 的基础设施的两个条件:第一个就是存储本身的云化;第二就是运维要和部署的方式必须是云化的。我就从这两个点说一下我们 TiDB 在上面的一些工作和一些我的思考。存储本身的云化有几个基本条件,大家过去认为是高可用,主要停留在双活。其实仔细去思考的话,主备的方案是很难保证数据在完全不需要人工的介入情况下数据的一致性可用性的,所以大家会发现最近这几年出来的分布式存储系统的可用性的协议跟复制协议基本都会用类似 Raft/Paxos 基于选取的一致性算法,不会像过去做这种老的复制的方案。第二就是整个分片的策略,作为分布式系统数据一定是会分片的,数据分片是来做分布式存储唯一的思路,自动分片一定会取代传统的人工分片来去支撑业务。比如传统分片,当你的数据量越来越大,你只能做分库分表或者用中间件,不管你分库分表还是中间件都必须制订自己人工的分辨规则,但是其实在一个真正面向 Cloud 的数据库设计里,任何一种人的介入的东西都是不对的。第三,接入层的去状态化,因为你需要面对 Cloud-Native 做设计,你的接入层就不能带有状态,你可以相当于是前端的接入层是一层无状态的或者连接到任何一个服务的接入的入口,对你来说应该都是一样的,就是说你不能整个系统因为一个关键组件的损坏或者说磁盘坏掉或者机器的宕机,整个系统就不能服务了,整个测试系统应该具有自我愈合和自我维护的能力。 其实我本身是架构师,所以整个我们数据库的设计都是围绕这些点来做思考的,就是一个数据库怎么能让他自我的生长,自我的维护,哪怕出现任何的灾难性的物理故障(有物理故障是非常正常的,每天在一个比较大的集群的规模下,网络中断、磁盘损坏甚至是很多很诡异的问题都是很正常的),所以怎么设计这种数据库。我们的项目是 TiDB,我不知道在座的有没有听说过这个项目,它其实是一个开源实现。当你的业务已经用了数据库,数据量一大就有可能遇到一些问题,一个是单点的可靠性的问题,还有一个数据容量怎么去弹性伸缩的问题。TiDB 就能解决这个问题,它本身对外暴露了一个接口,你可以用客户端去连接,你可以认为你下面面对的是一个弹性动态伸缩完全没有容量限制,同时还可以在上面支持复杂的子查询的东西。底层存储的话,相当于这一层无状态的会把这个请求发到底层的节点上,这个存储里面的数据都是通过协议做高可用和复制的,这个数据在底层会不停的分裂和移动,你可以认为这个数据库是一个活的数据库,你任何一个节点的宕机都不会影响整个数据库对业务层的使用,包括你可以跨数据中心部署,甚至你在跨数据中心的时候,整个数据中心网络被切断,机房着火,业务层都几乎完全是透明的,而且这个数据比如副本丢失会自己去修复,自己去管理或者移动数据。上图右边是一个集群的调度模块,你可以认为它是整个集群的大脑,是一个 7×24 小时不眠的 DBA,你任何的业务可以接上来。NewSQL 这个词大家听的都烂了,但是我还是想提,首先它是一个面向扩展的数据库,同时它还结合的传统管理数据库的强一致事务,必须得是 SSI 隔离级别的,并不是非常弱根本没法用的隔离级别,而是需要提供最强一致性的隔离级别的数据库。扩展性其实是通过在 TiKV 层面做完全自动分片,可用性是通过 Raft 为保证,我们整个数据库没有主从的概念,每一个节点既可以是主又可以是从,然后整个数据复制通过 Raft 为保证,对外的是一个强一致性的事务层,其实背后的算法是用两阶段提交的算法,比如一个最简单的例子,我一百个并发过来很快,每个平均十毫秒访问数据,一百个并发,一百万个并发,你还能保证每一个请求都是十毫秒返回数据吗?那我可以简单的通过添加机器把系统的吞吐加上去,每一个吞吐的响应延迟会更大一些,在论文里提到过,谷歌数据库写的每一个平均延迟是 150 到 100 毫秒,可以做到线性扩展。所以终于有一个数据库可以 scable。刚才说的是存储层面的云化,刚才提到了 Cloud-Native 还有一个重要的点就是部署和运维方式的云化,我们其实选的这个 Kubernetes 就是用来承载背后数据库大规模集群上的部署,其实大家都知道这个是什么东西,这是最出名的开源项目之一,谷歌开源的,大家也知道 borg,就是他们用了这么多年的集群调度服务,主要做的事情就是服务的编排、部署、自动化的运维,一台物理机挂掉了,他会很好的让这个业务不中断,像集群调度器,它就是整个数据中心的操作系统,但是面临最大的问题就是所有的业务一旦是有状态的,那你这个就非常恶心。举个案例,比如我在跑一个数据库,如果你这台物理机宕机,按照 Kubernetes 会开一个服务器在那边展开,但是这一台老的宕机服务器数据是存在上面的,你不能只是把进程在新的服务器那启起来而数据不带过去,相当于这种业务是带状态的,这在 Kubernetes 过去是一个老大难的问题,其实整个应用层,因为它的特性被分成了四个大的阵营,如果想上可以看一下自己的业务到底属于哪一个阵营。第一个就是完全无状态的业务,比如这是一个简单的 CRUD 业务层的逻辑,其实是无状态的应用层。第二种就是单点的带状态的 applications,还有任何单机的数据库其实都有属于 applications。第三个就是 Static distributed,比如高可用的分布式服务,大家也不会做扩容什么的,这种是静态的分布式应用。还有最难的一个问题,就是这种集群型的 applications,clustered 是没有办法很好的调度服务的。这是刚才说的,其实对于 Single point,其实是很好解决的,对于静态的其实也是用 Static distributed 来解决带状态的持续化的方案。刚才我说最难的那个问题,我们整个架构中引入了 Operational,调度一套有状态服务的方案,其实它思路也很简单,就是把运维分布人员系统的领域知识给嵌入到了系统中,Knowledge 发布调度任务之前都会相当于被 CoreOS 提供的接口以后再调度业务,这套方案依赖了 HtirdPartyResources 调度,因为这个里面我的状态我自己才知道,这个时候你需要通过把你的系统领域知识放到 operator 里。很简单,就是 Create 用 TiDB Operator 来实现,还有 Rollingupdate 和 Scale Out 还有 Failover 等。使用 Kubemetes 很重要的原因就是它只用到了很毛的一层 API,内部大量的逻辑是在 Operator 内部,而且像 PV/Statefulset 中并不是一个很好的方案,比如 PV 实现你可以用分布式文件系统或者快存储作为你持久化的这一层,但是数据库的业务,我对我底层的 IO 或者硬件有很强的掌控力的,我在我的业务层自己做了三副本和高可用,我其实就不需要在存储层面上比如我在一个裸盘上跑的性能能比其他上快十倍,这个时候你告诉我不好意思下面只支持 statefulset 那这是不适合跑数据库的,也就是数据库集群是跟它的普通的云盘或者云存储的业务是分开的。分布式数据库也不是百分之百所有的业务场景都适合,特别是大规模的分布式数据库来说,比如自增 ID,虽然我们支持,但是自增 IT 高压力写入的时候它的压力会集中在表的末尾,其实是我不管怎么调度总会有一块热点,当然你可以先分表,最后我们聚合分析也没有问题,像秒杀或者特别小的表,其实是完全不适合在这种分布式数据库上做的,比较好的一些实践业务的读写比较平均,数据量比较大,同时还有并发的事务的支持,需要有事务的支持,但并不是冲突特别大的场景,并不是秒杀的场景,同时你又可以需要在上面做比较复杂的分析,比如现在我们的一些线上的用户特别好玩,过去它的业务全都是跑在 MySQL 上,一主多从,他发现我一个个 MySQL 成为了信息的孤岛,他并没有办法做聚合地分析,过去传统的方案就是我把 MySQL 或者数据通过一个 ETL 流程导到数据仓库里,但是开发者不会用各种琳琅满目大数据的东西,他只会用 MySQL,一般他做的数据分析都会把 MySQL 倒腾到一个库上再做分析,数据量一大堆分析不出来,这个时候他把所有他自己的 MySQL 总库连到了一个 TiDB上,过去是一主多从,先多主多从,把所有的从都打通,做 MySQL 的分析,所以我觉得 TiDB 打造了新的模型,可以读写高并发的事务,所以未来的数据库会是一个什么样子的,我觉得可能是至少我们觉得沿着这条路走下去应该会有一条新的路,谢谢大家。"}, {"url": "https://pingcap.com/weekly/2017-04-17-tidb-weekly/", "title": "Weekly update (April 10 ~ April 16, 2017)", "content": " Weekly update in TiDB Last week, we landed 26 PRs in the TiDB repositories.Added Update etcd client in vendor. Add builtin function time-to-sec Add definition for builtin functions: bit_count, to_base64, right Fixed Fix the error message for data overflow. Fix a panic. Fix a bug in top-n pushdown. Fix a data race bug in session context. Fix a bug in name resolver for GroupBy clause. Improved Refactor optimizer: Implement new planner interface for projection and sort. Refactor statistic module.#3014, #3019, #3029, #3031, #3044, #3048, #3053 Refactor coprocessor architecture: #3009, #3027 Use etcd for privilege update notification among tidb-servers. Enlarge the limitation of write flow to TiKV. Reduce memory usage in HashAggregate operator. Reduce memory usage in Distinct operator. Code cleanup in type infer. New Contributors Thank you guys! Xuanwo fudali113 Weekly update in TiKV Last week, We landed 18 PRs in the TiKV repositories.Added Support memory profiling. Add block cache monitoring. Add log for critical operations. Use tokio-core to support asynchronous PD client, see 1745, 1752, 1753. Fixed Always update PD client to avoid the problem that PD client can not reconnect to PD server after network error. Fix the bug when decode empty data to a StringSlice. Fix a deadlock bug when PD client reconnects server. Improved Add lots of test cases to improve stability, see 1737 , 1738, 1742. "}, {"url": "https://pingcap.com/meetup/meetup-2017-04-16/", "title": "【Infra Meetup No.45】Rust 专场", "content": " 今天,小伙伴们期待已久的北京 Rust Meetup 终于和大家见面啦!在这场 Rust 社区在中国的首次官方活动中,我们邀请了两位 Rust 团队核心成员,Alex Crichton、Brian Anderson,与我司首席架构师唐刘,共同为大家带来了干货十足的分享内容~第一手现场资料,看这里! 这一次的 Meetup,小伙伴们都好积极 👏 提前一小时就有入场抢座位的~也是让小编感动到不行~~知道大家都已经迫不及待了,简单的开场之后,我们直接上干货!Concurrency and asynchronous IO in Rust 并发在当今编程领域是如此重要,然而要想实现并发程序通常会面临数据竞争,竞态,死锁,悬空指针,多次 free 等问题,Alex 在本期 meetup 里给我们讲解了 Rust 是如何用 ownership/borrowing 系统解决这些问题的,其核心思想是: A mutable reference cannot be aliased A reference cannot outlive its referent Alex Crichton,Mozilla 工程师,Rust 核心团队成员。从事 Rust 编程语言方面的工作已有 5 年。在 Mozilla 主要负责 Rust 的标准库、Cargo、异步 I/O 子系统以及 Rust 本身的基础设施。目前在做异步 I/O 栈 Tokio。 Rust 语言本身只提供了 ownership/borrowing 机制,标准库里提供了 thread,channel,arc,atomic,mutex 等基础设施,但没有提供轻量级协程,这样虽说并发程序写起来比较麻烦,但是不会只局限于一种并发模型。而后,简单介绍了第三方并行库 rayon 和 crossbeam。最后重点讲解了异步 IO 库 futures。Alex 在台上的分享刚刚结束,台下的小伙伴们便开始踊跃提问~让我们递话筒的妹子,不得已开启了满场飞模式 :-DQ&A 时间抢不到机会,没关系,还有茶歇时间可以利用 ✧(≖ ◡ ≖✿)How we use Rust in TiKV TiKV 是一个分布式 Key-Value 数据库,它通过 Raft 支持跨数据中心的复制,保证数据安全,提供了分布式事务支持,coprocessor computing 支持等。为了支持这些 feature,需要选择一门高性能的语言,不能有 memory 问题,不能用 data race 问题,同时也需要保证能快速的对 TiKV 进行开发迭代,基于这些原因, PingCAP 团队选择了 Rust 作为 TiKV 的开发语言。 唐刘,PingCAP 首席架构师,分布式存储引擎 TiKV 项目负责人。分布式数据库专家,知名开源软件 LedisDB / RebornDB / Mixer 作者。 在 Rust 关键技术选择上面,唐刘表示:“首先我们选择 mio 作为整个网络处理以及异步处理的框架。但 mio 过于底层,需要额外做很多工作,而且 mio 的 callback 写法很容易造成代码逻辑的割裂。所以后面,我们开始使用 gRPC 重构整个网络模块,同时使用 tokio-core 以及 futures 机制来重构整个异步框架。另外,我们也开启了 clippy 在编译的时候对 TiKV 进行更多的检查,保证代码的安全。并嵌入了一些 profile 和 monitoring 的工具来帮助我们在 TiKV 运行时动态的排查问题。”这是一场 Q&A 时长几近赶超 Talk 时长的一次分享~😜 宾主尽欢后,当然是要记录下这美好瞬间啦~~不管你们拍照是喊茄子还是 Cheers,反正我们只喊:Let’s Rust the World!最后附赠两张侧面杀~~ (๑•ᴗ•๑) PingCAP Infra Meetup作为一个基础架构领域的前沿技术公司,PingCAP 希望能为国内真正关注技术本身的 Hackers 打造一个自由分享的平台。自 2016 年 3 月 5 日开始,我们定期在周六的上午举办 Infra Meetup,邀请业内大牛与大家深度探讨基础架构领域的前瞻性技术思考与经验。在这里,我们希望提供一个高水准的前沿技术讨论空间,让大家真正感受到自由的开源精神魅力。 "}, {"url": "https://pingcap.com/weekly/2017-04-10-tidb-weekly/", "title": "Weekly update (March 27 ~ April 09, 2017)", "content": " Weekly update in TiDB Last two weeks, we landed 74 PRs in the TiDB repositories.Added Support Index Nest Lookup Join operator.#2834, #2945 Add many builtin functions: quote, is_ipv4, compress, inet_aton, format, bin, random-bytes, sin, inet_ntoa, cos, from_base64, tan, cot, to_days, timestampadd Check privileges for show databases/tables statement. Calculate distinct information in statistic module.#2947, #2966 Add a switcher to split large inset transaction into multiple small transactions automatically. Add memory table INFORMATION_SCHEMA.USER_PRIVILEGES. Add memory table INFORMATION_SCHEMA.ENGINES. Support Super_priv. Support Top-N operator push down in optimizer. Fixed Fix case-when expression and coalesce expression type inference. Fix a goroutine leak in tikv client. Fix a bug in the date_format builtin function. Fix goroutine leak in tikv client. Reset affected rows counter when retrying SQL statement. Recognize number literal as decimal when meet int64 overflow error. Improved Refactor optimizer: Introduce TaskProfile to represent a group of physical plans. Add base phyiscal plans. Refactor statistic module.#2913, #2952, #2956, #2993 Refactor coprocessor architecture: table scan and index scan operator, aggregation operator, limit operator, top-n operator Add sorted information for SortMergeJoin operator. Refactor distsql package. Reduce memory usage in HashJoin operator. New Contributors Thank you guys! Blame cosmos Zhao Yi Jun Bin Liu Michael Belenchenko Van jinhelin Weekly update in TiKV Last two weeks, We landed 46 PRs in the TiKV repositories.Added Add rate limiter for RocksDB compaction. Add gRPC support for PD, see 493, 590, 1591, 1712, 1725. Add RocksDB SST format for snapshot. Show replication configuration in pd-ctl. Make RocksDB info log path configurable. Slow down balance interval increasing speed. Report disk space usage to PD. Report region write-flow rate to PD. Show more information for region in HTTP API. Output statistics regularly for pd-tso-bench. Avoid selecting on the same context in different Goroutines. Fixed Avoid removing the leader peer directly. Avoid open RocksDB many times. Parse ALREADY_BOOTSTRAPPED error correctly, see 593, 1720. Use pool to store TSO request to reduce memory allocation and GC pressure. Improved Abort Prewrite command if the transaction is rolled back before. Make PD scheduler more reliable. Make Raft ReadIndex more stable. Add many unit tests to improve the system stability. "}, {"url": "https://pingcap.com/meetup/meetup-2017-04-08/", "title": "【Infra Meetup No.44】Elasticsearch 运维", "content": " 今天的 Meetup,我们邀请到去哪儿网的资深工程师徐磊,为大家分享关于 Elasticsearch 运维的那些事,跟小编一起走进现场吧~~Elasticsearch 运维 Elasticsearch 在近两年越来越火了,越来越多的公司和团队尝试使用它支撑业务。运维人员如何保证 Elasticsearch 集群的稳定?有哪些必须掌握的优化技巧?在本次分享中,徐磊老师从数据模型设计,使用技巧,参数优化,监控对比等多个方面为大家分析了 Elasticsearch 的优缺点和运维重点。同时与大家分享了内部的 Elasticsearch 私有云的建设经验。 徐磊,2015 年加入去哪儿网平台事业部 OPSDEV 团队,负责实时日志系统的建设和运维工作,开源社区贡献者,曾供职于 Red Hat。 干货节选 来~这里还有讲师的 PPT 节选,一起看看,在 Elasticsearch 中,有哪些要注意的坑吧~~ PingCAP Infra Meetup作为一个基础架构领域的前沿技术公司,PingCAP 希望能为国内真正关注技术本身的 Hackers 打造一个自由分享的平台。自 2016 年 3 月 5 日开始,我们定期在周六的上午举办 Infra Meetup,邀请业内大牛与大家深度探讨基础架构领域的前瞻性技术思考与经验。在这里,我们希望提供一个高水准的前沿技术讨论空间,让大家真正感受到自由的开源精神魅力。 "}, {"url": "https://pingcap.com/weekly/2017-03-27-tidb-weekly/", "title": "Weekly update (March 20 ~ March 26, 2017)", "content": " Weekly update in TiDB Last week, we landed 40 PRs in the TiDB repositories.Added Support Sort Merge Join operator. Add many builtin functions: degree, insert, instr, any_value, elt, uuid, ord, sin, inet_ntoa, maketime, sha2, quarter Add a command line flag to start TiDB without authentication function. Support use special comment /*+ */ for optimizer hint. Make index serial scan concurrency configurable with system variable. Fixed Replace standard context package with golang.org/x/net/context. Fix a bug in the floor builtin function. Fix a bug in the date_format builtin function. Fix goroutine leak in tikv client. Improved Build statistics with multiple goroutines. Refactor coprocessor architecture: Add DAG physical plan protobuf. Refactor TiDB specific system variable: Make code cleaner. New Contributors Thank you guys! Ma Xiaoyu Zhang Yuning zs634134578 Arthur Yang qhsong Sheng Tang hiwjd Weekly update in TiKV Last week, We landed 18 PRs in the TiKV repositories.Added Add RocksDB WAL options to support in memory storage. Fixed Fix fetching stale TSO when leader switches back to the previous node. Make sure that commit TS is always after the start TS. Speed up the process of transfer leader. Improved Make Lock CF configurable. Make schedule and replication options persistent. Optimize balance speed with calculating leader/region count from cache. Prepare for introducing mio 0.6, see 1691 1692 1695. New Contributor (Thanks!) aya "}, {"url": "https://pingcap.com/blog-cn/how-to-contribute/", "title": "如何从零开始参与大型开源项目", "content": " 写在前面的话 上世纪 70 年代,IBM 发明了关系型数据库。但是随着现在移动互联网的发展,接入设备越来越多,数据量越来越大,业务越来越复杂,传统的数据库显然已经不能满足海量数据存储的需求。虽然目前市场上也不乏分布式数据库模型,但没有品位的文艺青年不是好工程师,我们觉得,不,这些方案都不是我们想要的,它们不够美,鲜少能够把分布式事务与弹性扩展做到完美。受 Google Spanner/F1 的启发,一款从一开始就选择了开源道路的 TiDB 诞生了。 它是一款代表未来的新型分布式 NewSQL 数据库,它可以随着数据增长而无缝水平扩展,只需要通过增加更多的机器来满足业务增长需求,应用层可以不用关心存储的容量和吞吐,用东旭的话说就是「他自己会生长」。在开源的世界里,TiDB 和 TiKV 吸引了更多的具有极客气质的开发者,目前已经拥有超过 9000 个 star 和 100 个 contributor,这已然是一个世界顶级开源项目的水准。而成就了这一切的,则是来自社区的力量。最近我们收到了很多封这样的邮件和留言,大家说: 谢谢你们,使得旁人也能接触大型开源项目。本身自己是DBA,对数据库方面较干兴趣,也希望自己能逐步深入数据库领域,深入TiDB,为 TiDB 社区贡献更多、更有价值的力量。 我是一个在校学生,刚刚收到邮件说我成为了 TiDB 的 Contributor,这让我觉得当初没听父母的话坚持了自己喜欢的计算机技术,是个正确的选择,但我还需要更多的历练,直到能完整地展现、表达我的思维。 这让我感触颇多,因为,应该是我们感谢你们才是啊,没有社区,一个开源项目就成不了一股清泉甚至一汪海洋。 公司的小姑娘说,她觉得还有很多的人想要参与进来的,可工程师团队欠缺平易近人的表达,这个得改。于是便有了这篇文章以及未来的多篇文章和活动,我们欢迎所有的具有气质的开发者能和 TiDB 一起成长,一起见证数据库领域的革新,改变世界这事儿有时候也不那么难。我要重点感谢今天这篇文章的作者,来自社区的朱武(GitHub ID:viile )、小卢(GitHub ID:lwhhhh )和杨文(GitHub ID: yangwenmai),当在 TiDB Contributor Club 里提到想要做这件事的时候,是他们踊跃地加入了 TiDB Tech Writer 的队伍,高效又专业地完成了下文的编辑,谢谢你们。一个典型的开源项目是由什么组成的 The Community(社区) 一个项目经常会有一个围绕着它的社区,这个社区由各个承担不同角色的用户组成。 项目的拥有者:在他们账号中创建项目并拥有它的用户或者组织。 维护者和合作者:主要做项目相关的工作和推动项目发展,通常情况下拥有者和维护者是同一个人,他们拥有仓库的写入权限。 贡献者:发起拉取请求 (pull request) 并且被合并到项目里面的人。 社区成员:对项目非常关心,并且在关于项目的特性以及 pull requests 的讨论中非常活跃的人。 The Docs(文档) 项目中经常出现的文件有: Readme:几乎所有的 Github 项目都包含一个 README.md 文件,readme 文件提供了一些项目的详细信息,包括如何使用,如何构建。有时候也会告诉你如何成为贡献者。 TiDB Readme https://github.com/pingcap/tidb/blob/master/README.md Contributing:项目以及项目的维护者各式各样,所以参与贡献的最佳方式也不尽相同。如果你想成为贡献者的话,那么你要先阅读那些有 CONTRIBUTING 标签的文档。Contributing 文档会详细介绍了项目的维护者希望得到哪些补丁或者是新增的特性。 文件里也可以包含需要写哪些测试,代码风格,或者是哪些地方需要增加补丁之类的内容。 TiDB Contributing 文档 https://github.com/pingcap/tidb/blob/master/CONTRIBUTING.md License:LICENSE 文件就是这个开源项目的许可证。一个开源项目会告知用户他们可以做什么,不可做什么(比如:使用,修改,重新分发),以及贡献者允许其他人做哪些事。开源许可证有多种,你可以在认识各种开源协议及其关系了解更多关于开源许可证的信息。 TiDB 遵循 Apache-2.0 Lincense https://github.com/pingcap/tidb/blob/master/LICENSE TiKV 遵循 Apache-2.0 Lincense https://github.com/pingcap/tikv/blob/master/LICENSE Documentation:许多大型项目不会只通过自述文件去引导用户如何使用。在这些项目中你经常可以找到通往其他文件的超链接,或者是在仓库中找到一个叫做 docs 的文件夹. TiDB Docs https://github.com/pingcap/tidb/tree/master/docs 齐步走成为 Contributor Create an Issue 如果你在使用项目中发现了一个 bug,而且你不知道怎么解决这个 bug。或者使用文档时遇到了麻烦。或者有关于这个项目的问题。你可以创建一个 issue。 不管你有什么 bug,你提出 bug 后,会对那些和你有同样 bug 的人提供帮助。 更多关于 issue 如何工作的信息,请点击 Issues guide。Issues Pro Tips 检查你的问题是否已经存在 重复的问题会浪费大家的时间,所以请先搜索打开和已经关闭的问题,来确认你的问题是否已经提交过了。 清楚描述你的问题 TiDB Issue 模版如下 TiKV Issue 模版如下 给出你的代码链接 使用像 JSFiddle 或者 CodePen 等工具,贴出你的代码,好帮助别人复现你的问题 详细的系统环境介绍 例如使用什么版本的浏览器,什么版本的库,什么版本的操作系统等其他你运行环境的介绍。 go 版本: go version Linux 版本: uname -a 详细的错误输出或者日志 使用 Gist 贴出你的错误日志。如果你在 issue 中附带错误日志,请使用`来标记你的日志。以便更好的显示。 Pull Request 如果你能解决这个 bug,或者你能够添加其他的功能。并且知道如何成为贡献者,理解 license,已经签过Contributor Licence Agreement (CLA) 后,请发起 Pull Request。这样维护人员可以将你的分支与现有分支进行比较,来决定是否合并你的更改。Pull Request Pro Tips Fork 代码并且 clone 到你本地 通过将项目的地址添加为一个 remote,并且经常从 remote 合并更改来保持你的代码最新,以便在提交你的 pull 请求时,尽可能少的发生冲突。详情请参阅这里 创建 branch 来修改你的代码,目前 TiDB 相关的项目默认的 branch 命名规则是 user/name。例如 disksing/grpc,简单明确,一目了然。 描述清楚你的问题 方便其他人能够复现。或者说明你添加的功能有什么作用,并且清楚描述你做了哪些更改。 注意测试 如果项目中包含逻辑修改,那么必须包含相应的测试,在 CI 中会包含测试覆盖率的检测,如果测试覆盖率下降,那么是不可以合并到 master 的。 包含截图 如果您的更改包含 HTML/CSS 中的差异,请添加前后的屏幕截图。将图像拖放到您的 pull request 的正文中。 保持良好的代码风格这意味着使用与你自己的代码风格中不同的缩进,分号或注释,但是使维护者更容易合并,其他人将来更容易理解和维护。目前 TiDB 项目的 CI 检测包含代码风格的检查,如果代码风格不符合要求,那么是不可以合并到 master 的。 Open Pull Requests 一旦你新增一个 pull request,讨论将围绕你的更改开始。其他贡献者和用户可能会进入讨论,但最终决定是由维护者决定的。你可能会被要求对你的 pull request 进行一些更改,如果是这样,请向你的 branch 添加更多代码并推送它们,它们将自动进入现有的 pull request。如果你的 pull request 被合并,这会非常棒。如果没有被合并,不要灰心。也许你的更改不是项目维护者需要的。或者更改已经存在了。发生这种情况时,我们建议你根据收到的任何反馈来修改代码,并再次提出 pull request。或创建自己的开源项目。TiDB 合并流程 PR 提交之后,请耐心等待维护者进行 Review。 目前一般在一到两个工作日内都会进行 Review,如果当前的 PR 堆积数量较多可能回复会比较慢。 代码提交后 CI 会执行我们内部的测试,你需要保证所有的单元测试是可以通过的。期间可能有其它的提交会与当前 PR 冲突,这时需要修复冲突。 维护者在 Review 过程中可能会提出一些修改意见。修改完成之后如果 reviewer 认为没问题了,你会收到 LGTM(looks good to me) 的回复。当收到两个及以上的 LGTM 后,该 PR 将会被合并。标注:本文「一个典型的开源项目是由什么组成的」及「齐步走为 Contributor」参考自英文 GitHub Guide,由社区成员朱武(GitHub ID: viile)、小卢(GitHub ID:lwhhhh)着手翻译并替换部分原文中的截图。GitHub Guides:如何参与一个 GitHub 开源项目英文原文地址: https://guides.github.com/activities/contributing-to-open-source/加入 TiDB Contributor Club为更好地促进 Contributor 间的交流,便于随时提出好的想法和反馈,我们创建了一个 Contributor Club 微信群,对成为 TiDB Contributor 有兴趣的同学可以添加 TiDB Robot 微信号,它会在后台和你打招呼,并积极招募你成为开源社区的一员。"}, {"url": "https://pingcap.com/meetup/meetup-2017-03-25/", "title": "RocksDB 专场分享|PingCAP 第 43 期 NewSQL Meetup", "content": " RocksDB 专场分享|PingCAP 第 43 期 NewSQL Meetup 2017-03-25 宋昭&赵安安 PingCAP PingCAPPingCAP ![]() 微信号pingcap2015功能介绍PingCAP 专注于新型"}, {"url": "https://pingcap.com/weekly/2017-03-20-tidb-weekly/", "title": "Weekly update (March 13 ~ March 19, 2017)", "content": " Weekly update in TiDB Last week, we landed 33 PRs in the TiDB repositories.Added Add system table mysql.stats_meta: used for storing statistic information. Add a Restful API to get region info from pd. Add a system variable to control the behavior of unfolding subquery in in expression. Add many builtin functions: acos, asin, atan, make_set, oct, pi, lpad, radians, exp, ip_v6 Fixed Check truncated UTF8 string when casting value. Fix data race. Stop the service when meet critical error. Keep the return value of builtin function conv consistent with MySQL when meet invalid input. Improved Refactor tikv coprocessor client: make code cleaner and fix memory leak. Refactor code about aggregation pushdown and aggregation prunning: make code cleaner. New Contributors Thank you guys! Huxley Hu Zhao Yi Jun silenceper Rick Yu Qiannan Tao Meng yangwenmai Hongyuan Wang 8cbx alston111111 Du Chuan Weekly update in TiKV Last week, We landed 10 PRs in the TiKV repositories.Added Use SSE support by default. Handle [CTRL + D] in pd-ctl (https://github.com/pingcap/pd/pull/570) Fixed Avoid panic when get the tombstone store information. Check epoch in ReadIndex to avoid stale read. Clean ReadIndex callback when peer is destroyed to avoid deadlock. Improved Queue vote to prevent followers from discarding it if region hasn’t been split. Improve random picking region from cache. "}, {"url": "https://pingcap.com/meetup/meetup-2017-03-18/", "title": "COISF 专场|PingCAP 第 42 期 NewSQL Meetup", "content": " COISF 专场|PingCAP 第 42 期 NewSQL Meetup 2017-03-18 梁堰波 PingCAP PingCAPPingCAP ![]() 微信号pingcap2015功能介绍PingCAP 专注于新型"}, {"url": "https://pingcap.com/blog-cn/add-a-built-in-function/", "title": "十分钟成为 TiDB Contributor 系列 | 添加內建函数", "content": " 背景知识 SQL 语句发送到 TiDB 后首先会经过 parser,从文本 parse 成为 AST(抽象语法树),通过 Query Optimizer 生成执行计划,得到一个可以执行的 plan,通过执行这个 plan 即可得到结果,这期间会涉及到如何获取 table 中的数据,如何对数据进行过滤、计算、排序、聚合、滤重以及如何对表达式进行求值。 对于一个 builtin 函数,比较重要的是进行语法解析以及如何求值。其中语法解析部分需要了解如何写 yacc 以及如何修改 TiDB 的词法解析器,较为繁琐,我们已经将这部分工作提前做好,大多数 builtin 函数的语法解析工作已经做完。 对 builtin 函数的求值需要在 TiDB 的表达式求值框架下完成,每个 builtin 函数被认为是一个表达式,用一个 ScalarFunction 来表示,每个 builtin 函数通过其函数名以及参数,获取对应的函数类型以及函数签名,然后通过函数签名进行求值。 总体而言,上述流程对于不熟悉 TiDB 的朋友而言比较复杂,我们对这部分做了些工作,将一些流程性、较为繁琐的工作做了统一处理,目前已经将大多数未实现的 buitlin 函数的语法解析以及寻找函数签名的工作完成,但是函数实现部分留空。换句话说,只要找到留空的函数实现,将其补充完整,即可作为一个 PR。添加 builtin 函数整体流程 找到未实现的函数在 TiDB 源码中的 expression 目录下搜索 errFunctionNotExists,即可找到所有未实现的函数,从中选择一个感兴趣的函数,比如 SHA2 函数:func (b *builtinSHA2Sig) eval(row []types.Datum) (d types.Datum, err error) { return d, errFunctionNotExists.GenByArgs("SHA2") } 实现函数签名接下来要做的事情就是实现 eval 方法,函数的功能请参考 MySQL 文档,具体的实现方法可以参考目前已经实现函数。 在 typeinferer 中添加类型推导信息在 plan/typeinferer.go 中的 handleFuncCallExpr() 里面添加这个函数的返回结果类型,请保持和 MySQL 的结果一致。全部类型定义参见 MySQL Const。 注意:大多数函数除了需要填写返回值类型之外,还需要获取返回值的长度。 写单元测试在 expression 目录下,为函数的实现增加单元测试,同时也要在 plan/typeinferer_test.go 文件中添加 typeinferer 的单元测试 运行 make dev,确保所有的 test case 都能跑过。 示例 这里以新增 SHA1() 函数的 PR 为例,进行详细说明 首先看 expression/builtin_encryption.go: 将 SHA1() 的求值方法补充完整func (b *builtinSHA1Sig) eval(row []types.Datum) (d types.Datum, err error) { // 首先对参数进行求值,这块一般不用修改 args, err := b.evalArgs(row) if err != nil { return types.Datum{}, errors.Trace(err) } // 每个参数的意义请参考 MySQL 文档 // SHA/SHA1 function only accept 1 parameter arg := args[0] if arg.IsNull() { return d, nil } // 这里对参数值做了一个类型转换,函数的实现请参考 util/types/datum.go bin, err := arg.ToBytes() if err != nil { return d, errors.Trace(err) } hasher := sha1.New() hasher.Write(bin) data := fmt.Sprintf("%x", hasher.Sum(nil)) // 设置返回值 d.SetString(data) return d, nil } 接下来给函数实现添加单元测试,参见 expression/builtin_encryption_test.go:var shaCases = []struct { origin interface{} crypt string }{ {"test", "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3"}, {"c4pt0r", "034923dcabf099fc4c8917c0ab91ffcd4c2578a6"}, {"pingcap", "73bf9ef43a44f42e2ea2894d62f0917af149a006"}, {"foobar", "8843d7f92416211de9ebb963ff4ce28125932878"}, {1024, "128351137a9c47206c4507dcf2e6fbeeca3a9079"}, {123.45, "22f8b438ad7e89300b51d88684f3f0b9fa1d7a32"}, } func (s *testEvaluatorSuite) TestShaEncrypt(c *C) { defer testleak.AfterTest(c)() // 监测 goroutine 泄漏的工具,可以直接照搬 fc := funcs[ast.SHA] for _, test := range shaCases { in := types.NewDatum(test.origin) f, _ := fc.getFunction(datumsToConstants([]types.Datum{in}), s.ctx) crypt, err := f.eval(nil) c.Assert(err, IsNil) res, err := crypt.ToString() c.Assert(err, IsNil) c.Assert(res, Equals, test.crypt) } // test NULL input for sha var argNull types.Datum f, _ := fc.getFunction(datumsToConstants([]types.Datum{argNull}), s.ctx) crypt, err := f.eval(nil) c.Assert(err, IsNil) c.Assert(crypt.IsNull(), IsTrue) } 注意:除了正常 case 之外,最好能添加一些异常的case,如输入值为 nil,或者是多种类型的参数 最后还需要添加类型推导信息以及 test case,参见 plan/typeinferer.go,plan/typeinferer_test.go:case ast.SHA, ast.SHA1: tp = types.NewFieldType(mysql.TypeVarString) chs = v.defaultCharset tp.Flen = 40{`sha1(123)`, mysql.TypeVarString, "utf8"}, {`sha(123)`, mysql.TypeVarString, "utf8"}, 编辑按:添加 TiDB Robot 微信,加入 TiDB Contributor Club,无门槛参与开源项目,改变世界从这里开始吧(萌萌哒)。"}, {"url": "https://pingcap.com/weekly/2017-03-13-tidb-weekly/", "title": "Weekly update (March 06 ~ March 12, 2017)", "content": " Weekly update in TiDB Last week, we landed 30 PRs in the TiDB repositories.Added Add context in exector: prepare for canceling execution. Support the KILL statement. Support string literal with in the national character set N'literal'. Check privilege when running create user statement. Add a session variable to prevent eager aggregation. Fixed Clean up pending task when close executor: fix memory leak. Make the type of coalesce function the same with MySQL. Clean up process info when finish running statement. Fix a bug in optimizer about pushing down limit across filter. Fix a bug in optimizer about column prunning on union statement. Use QUOTE as an identifier. Improved Create user automatically when grant privilege for unexist user. Speed up Add Column statement. Update grpc version to v1.0.4 in vendor. Avoid useless schema version update when running DDL. Add metrics for potential time-consuming queries. Weekly update in TiKV Last week, We landed 13 PRs in the TiKV repositories.Added Add metric for RocksDB compaction. Collect scanned key count to detect region access hotspot. Support GetRegionByID for pd-ctl. Enable AutoCompactionRetention to reduce PD space occupation. Fixed Reduce manual compaction for Lock CF to avoid too many WAL logs. Only check scheduler busy error for Write command. Fix data race for updating replication configuration. Prohibit joining the PD cluster with empty name. Improved Beautify region log. Cleanup iterator creation. Adjust default leader scheduler limit to speed up leader balance. "}, {"url": "https://pingcap.com/meetup/meetup-2017-03-11/", "title": "COISF 专场|PingCAP 第 41 期 NewSQL Meetup", "content": " COISF 专场|PingCAP 第 41 期 NewSQL Meetup 2017-03-11 杨建军&张金鹏 PingCAP PingCAPPingCAP ![]() 微信号pingcap2015功能介绍PingCAP 专注于新型"}, {"url": "https://pingcap.com/blog-cn/optimizing-raft-in-tikv/", "title": "TiKV 源码解析系列 - Raft 的优化", "content": " 在分布式领域,为了保证数据的一致性,通常都会使用 Paxos 或者 Raft 来实现。但 Paxos 以其复杂难懂著称,相反 Raft 则是非常简单易懂,所以现在很多新兴的数据库都采用 Raft 作为其底层一致性算法,包括我们的 TiKV。当然,Raft 虽然简单,但如果单纯的按照 Paper 的方式去实现,性能是不够的。所以还需要做很多的优化措施。本文假定用户已经熟悉并了解过 Raft 算法,所以对 Raft 不会做过多说明。Simple Request Flow 这里首先介绍一下一次简单的 Raft 流程: Leader 收到 client 发送的 request。 Leader 将 request append 到自己的 log。 Leader 将对应的 log entry 发送给其他的 follower。 Leader 等待 follower 的结果,如果大多数节点提交了这个 log,则 apply。 Leader 将结果返回给 client。 Leader 继续处理下一次 request。 可以看到,上面的流程是一个典型的顺序操作,如果真的按照这样的方式来写,那性能是完全不行的。Batch and Pipeline 首先可以做的就是 batch,大家知道,在很多情况下面,使用 batch 能明显提升性能,譬如对于 RocksDB 的写入来说,我们通常不会每次写入一个值,而是会用一个 WriteBatch 缓存一批修改,然后在整个写入。 对于 Raft 来说,Leader 可以一次收集多个 requests,然后一批发送给 Follower。当然,我们也需要有一个最大发送 size 来限制每次最多可以发送多少数据。如果只是用 batch,Leader 还是需要等待 Follower 返回才能继续后面的流程,我们这里还可以使用 Pipeline 来进行加速。大家知道,Leader 会维护一个 NextIndex 的变量来表示下一个给 Follower 发送的 log 位置,通常情况下面,只要 Leader 跟 Follower 建立起了连接,我们都会认为网络是稳定互通的。所以当 Leader 给 Follower 发送了一批 log 之后,它可以直接更新 NextIndex,并且立刻发送后面的 log,不需要等待 Follower 的返回。如果网络出现了错误,或者 Follower 返回一些错误,Leader 就需要重新调整 NextIndex,然后重新发送 log 了。Append Log Parallelly 对于上面提到的一次 request 简易 Raft 流程来说,我们可以将 2 和 3 并行处理,也就是 Leader 可以先并行的将 log 发送给 Followers,然后再将 log append。为什么可以这么做,主要是因为在 Raft 里面,如果一个 log 被大多数的节点append,我们就可以认为这个 log 是被 committed 了,所以即使 Leader 再给 Follower 发送 log 之后,自己 append log 失败 panic 了,只要 N / 2 + 1 个 Follower 能接收到这个 log 并成功 append,我们仍然可以认为这个 log 是被 committed 了,被 committed 的 log 后续就一定能被成功 apply。那为什么我们要这么做呢?主要是因为 append log 会涉及到落盘,有开销,所以我们完全可以在 Leader 落盘的同时让 Follower 也尽快的收到 log 并 append。这里我们还需要注意,虽然 Leader 能在 append log 之前给 Follower 发 log,但是 Follower 却不能在 append log 之前告诉 Leader 已经成功 append 这个 log。如果 Follower 提前告诉 Leader 说已经成功 append,但实际后面 append log 的时候失败了,Leader 仍然会认为这个 log 是被 committed 了,这样系统就有丢失数据的风险了。Asynchronous Apply 上面提到,当一个 log 被大部分节点 append 之后,我们就可以认为这个 log 被 committed 了,被 committed 的 log 在什么时候被 apply 都不会再影响数据的一致性。所以当一个 log 被 committed 之后,我们可以用另一个线程去异步的 apply 这个 log。所以整个 Raft 流程就可以变成: Leader 接受一个 client 发送的 request。 Leader 将对应的 log 发送给其他 follower 并本地 append。 Leader 继续接受其他 client 的 requests,持续进行步骤 2。 Leader 发现 log 已经被 committed,在另一个线程 apply。 Leader 异步 apply log 之后,返回结果给对应的 client。 使用 asychronous apply 的好处在于我们现在可以完全的并行处理 append log 和 apply log,虽然对于一个 client 来说,它的一次 request 仍然要走完完整的 Raft 流程,但对于多个 clients 来说,整体的并发和吞吐量是上去了。Now Doing… SST Snapshot 在 Raft 里面,如果 Follower 落后 Leader 太多,Leader 就可能会给 Follower 直接发送 snapshot。在 TiKV,PD 也有时候会直接将一个 Raft Group 里面的一些副本调度到其他机器上面。上面这些都会涉及到 Snapshot 的处理。在现在的实现中,一个 Snapshot 流程是这样的: Leader scan 一个 region 的所有数据,生成一个 snapshot file Leader 发送 snapshot file 给 Follower Follower 接受到 snapshot file,读取,并且分批次的写入到 RocksDB 如果一个节点上面同时有多个 Raft Group 的 Follower 在处理 snapshot file,RocksDB 的写入压力会非常的大,然后极易引起 RocksDB 因为 compaction 处理不过来导致的整体写入 slow 或者 stall。幸运的是,RocksDB 提供了 SST 机制,我们可以直接生成一个 SST 的 snapshot file,然后 Follower 通过 injest 接口直接将 SST file load 进入 RocksDB。Asynchronous Lease Read 在之前的 Lease Read 文章中,我提到过 TiKV 使用 ReadIndex 和 Lease Read 优化了 Raft Read 操作,但这两个操作现在仍然是在 Raft 自己线程里面处理的,也就是跟 Raft 的 append log 流程在一个线程。无论 append log 写入 RocksDB 有多么的快,这个流程仍然会 delay Lease Read 操作。所以现阶段我们正在做的一个比较大的优化就是在另一个线程异步实现 Lease Read。也就是我们会将 Leader Lease 的判断移到另一个线程异步进行,Raft 这边的线程会定期的通过消息去更新 Lease,这样我们就能保证 Raft 的 write 流程不会影响到 read。总结 虽然外面有声音说 Raft 性能不好,但既然我们选择了 Raft,所以就需要对它持续的进行优化。而且现阶段看起来,成果还是很不错的。相比于 RC1,最近发布的 RC2 无论在读写性能上面,性能都有了极大的提升。但我们知道,后面还有很多困难和挑战在等着我们,同时我们也急需在性能优化上面有经验的大牛过来帮助我们一起改进,如果你对我们做的东西感兴趣,想让 Raft 快的飞起,欢迎联系我: 邮箱:tl@pingcap.com 微信:siddontang "}, {"url": "https://pingcap.com/weekly/2017-03-06-tidb-weekly/", "title": "Weekly update (February 27 ~ March 05, 2017)", "content": " Weekly update in TiDB Last week, we landed 21 PRs in the TiDB repositories.Added Add metrics for related region count for a transaction. Record sql_mode in session context. Support Show Processlist. Add an empty Triggers table in information_schema database. Support ANSI_QUOTES sql_mode in parser. Support use wildcard as user hostname in grant statement. Support the MD5 builtin function. Support the SHA/SHA1 builtin function. Fixed Use PI as identifier Fix a panic in prepared statement. Improved Use unique key to eliminate aggregation. Tuning tikv client max timeout parameter. Adjust log level in tikv client. Weekly update in TiKV Last week, We landed 8 PRs in the TiKV repositories.Added Use ReadIndex to serve safe Raft read. Add tso command for pd-ctl. Add ServerIsBusy metric. Fixed Fix a data race when update configuration. Improved Notify PD immediately when leader changes. Make scheduler TooBusy threshold configurable. "}, {"url": "https://pingcap.com/meetup/meetup-2017-03-04/", "title": "COISF 专场|PingCAP 第 40 期 NewSQL Meetup", "content": " COISF 专场|PingCAP 第 40 期 NewSQL Meetup 2017-03-04 吴晓飞&韩飞 PingCAP PingCAPPingCAP ![]() 微信号pingcap2015功能介绍PingCAP 专注于新型"}, {"url": "https://pingcap.com/blog-cn/how-to-use-tidb/", "title": "TiDB 的正确使用姿势", "content": " 最近这几个月,特别是 TiDB RC1 发布后,越来越多的用户已经开始测试起来,也有很多朋友已经在生产环境中使用,我们这边也陆续的收到了很多用户的测试和使用反馈。非常感谢各位小伙伴和早期用户的厚爱,而且看了这么多场景后,也总结出了一些 TiDB 的使用实践 (其实 Spanner 的最佳实践大部分在 TiDB 中也是适用的,MySQL 最佳实践也是),也是借着 Google Cloud Spanner 发布的东风,看了一下 Spanner 官方的一些最佳实践文档,写篇文章讲讲 TiDB 以及分布式关系型数据库的一些正确的使用姿势,当然,时代也在一直发展,TiDB 也在不停的进化,这篇文章基本上只代表近期的一些观察。 首先谈谈 Schema 设计的一些比较好的经验。由于 TiDB 是一个分布式的数据库,可能在表结构设计的时候需要考虑的事情和传统的单机数据库不太一样,需要开发者能够带着「这个表的数据会分散在不同的机器上」这个前提,才能做更好的设计。和 Spanner 一样,TiDB 中的一张表的行(Rows)是按照主键的字节序排序的(整数类型的主键我们会使用特定的编码使其字节序和按大小排序一致),即使在 CREATE TABLE 语句中不显式的创建主键,TiDB 也会分配一个隐式的。 有四点需要记住: 1. 按照字节序的顺序扫描的效率是比较高的; 2. 连续的行大概率会存储在同一台机器的邻近位置,每次批量的读取和写入的效率会高; 3. 索引是有序的(主键也是一种索引),一行的每一列的索引都会占用一个 KV Pair,比如,某个表除了主键有 3 个索引,那么在这个表中插入一行,对应在底层存储就是 4 个 KV Pairs 的写入:数据行以及 3 个索引行。 4. 一行的数据都是存在一个 KV Pair 中,不会被切分,这点和类 BigTable 的列式存储很不一样。表的数据在 TiDB 内部会被底层存储 TiKV 切分成很多 64M 的 Region(对应 Spanner 的 Splits 的概念),每个 Region 里面存储的都是连续的行,Region 是 TiDB 进行数据调度的单位,随着一个 Region 的数据量越来越大和时间的推移,Region 会分裂/合并,或者移动到集群中不同的物理机上,使得整个集群能够水平扩展。 建议: 尽可能批量写入,但是一次写入总大小不要超过 Region 的分裂阈值(64M),另外 TiDB 也对单个事务有大小的限制。 存储超宽表是比较不合适的,特别是一行的列非常多,同时不是太稀疏,一个经验是最好单行的总数据大小不要超过 64K,越小越好。大的数据最好拆到多张表中。 对于高并发且访问频繁的数据,尽可能一次访问只命中一个 Region,这个也很好理解,比如一个模糊查询或者一个没有索引的表扫描操作,可能会发生在多个物理节点上,一来会有更大的网络开销,二来访问的 Region 越多,遇到 stale region 然后重试的概率也越大(可以理解为 TiDB 会经常做 Region 的移动,客户端的路由信息可能更新不那么及时),这些可能会影响 .99 延迟;另一方面,小事务(在一个 Region 的范围内)的写入的延迟会更低,TiDB 针对同一个 Region 内的跨行事务是有优化的。另外 TiDB 对通过主键精准的点查询(结果集只有一条)效率更高。 关于索引 除了使用主键查询外,TiDB 允许用户创建二级索引以加速访问,就像上面提到过的,在 TiKV 的层面,TiDB 这边的表里面的行数据和索引的数据看起来都是 TiKV 中的 KV Pair,所以很多适用于表数据的原则也适用于索引。和 Spanner 有点不一样的是,TiDB 只支持全局索引,也就是 Spanner 中默认的 Non-interleaved indexes。全局索引的好处是对使用者没有限制,可以 scale 到任意大小,不过这意味着,索引信息*不一定*和实际的数据在一个 Region 内。 建议: 对于大海捞针式的查询来说 (海量数据中精准定位某条或者某几条),务必通过索引。 当然也不要盲目的创建索引,创建太多索引会影响写入的性能。 反模式 (最好别这么干!) 其实 Spanner 的白皮书已经写得很清楚了,我再赘述一下:第一种,过度依赖单调递增的主键,AUTO INCREMENT ID 在传统的关系型数据库中,开发者经常会依赖自增 ID 来作为 PRIMARY KEY,但是其实大多数场景大家想要的只是一个不重复的 ID 而已,至于是不是自增其实无所谓,但是这个对于分布式数据库来说是不推荐的,随着插入的压力增大,会在这张表的尾部 Region 形成热点,而且这个热点并没有办法分散到多台机器。TiDB 在 GA 的版本中会对非自增 ID 主键进行优化,让 insert workload 尽可能分散。 建议: 如果业务没有必要使用单调递增 ID 作为主键,就别用,使用真正有意义的列作为主键(一般来说,例如:邮箱、用户名等) 使用随机的 UUID 或者对单调递增的 ID 进行 bit-reverse (位反转) 第二种,单调递增的索引 (比如时间戳) 很多日志类型的业务,因为经常需要按照时间的维度查询,所以很自然需要对 timestamp 创建索引,但是这类索引的问题本质上和单调递增主键是一样的,因为在 TiDB 的内部实现里,索引也是一堆连续的 KV Pairs,不断的插入单调递增的时间戳会造成索引尾部的 Region 形成热点,导致写入的吞吐受到影响。 建议: 因为不可避免的,很多用户在使用 TiDB 存储日志,毕竟 TiDB 的弹性伸缩能力和 MySQL 兼容的查询特性是很适合这类业务的。另一方面,如果发现写入的压力实在扛不住,但是又非常想用 TiDB 来存储这种类型的数据,可以像 Spanner 建议的那样做 Application 层面的 Sharding,以存储日志为例,原来的可能在 TiDB 上创建一个 log 表,更好的模式是可以创建多个 log 表,如:log_1, log_2 … log_N,然后业务层插入的时候根据时间戳进行 hash ,随机分配到 1..N 这几个分片表中的一个。 相应的,查询的时候需要将查询请求分发到各个分片上,最后在业务层汇总结果。查询优化 TiDB 的优化分为基于规则的优化(Rule Based Optimization)和基于代价的优化(Cost Based Optimization), 本质上 TiDB 的 SQL 引擎更像是一个分布式计算框架,对于大表的数据因为本身 TiDB 会将数据分散到多个存储节点上,能将查询逻辑下推,会大大的提升查询的效率。TiDB 基于规则的优化有: 谓词下推 谓词下推会将 where/on/having 条件推到离数据表尽可能近的地方,比如:select * from t join s on t.id = s.id where t.c1 < 10可以被 TiDB 自动改写成select * from (select * from t where t.c1 < 10) as t join s on t.id = s.id关联子查询消除关联子查询可能被 TiDB 改写成 Join,例如:select * from t where t.id in (select id from s where s.c1 < 10 and s.name = t.name)可以被改写成:select * from t semi join s on t.id = s.id and s.name = t.name and s.c1 < 10聚合下推 聚合函数可以被推过 Join,所以类似带等值连接的 Join 的效率会比较高,例如:select count(s.id) from t join s on t.id = s.t_id可以被改写成:select sum(agg0) from t join (select count(id) as agg0, t_id from s group by t_id) as s on t.id = s.t_id基于规则的优化有时可以组合以产生意想不到的效果,例如:select s.c2 from s where 0 = (select count(id) from t where t.s_id = s.id)在TiDB中,这个语句会先通过关联子查询消除的优化,变成:select s.c2 from s left outer join t on t.s_id = s.id group by s.id where 0 = count(t.id)然后这个语句会通过聚合下推的优化,变成:select s.c2 from s left outer join (select count(t.id) as agg0 from t group by t.s_id) t on t.s_id = s.id group by s.id where 0 = sum(agg0)再经过聚合消除的判断,语句可以优化成:select s.c2 from s left outer join (select count(t.id) as agg0 from t group by t.s_id) t on t.s_id = s.id where 0 = agg0基于代价的优化有:读取表时,如果有多条索引可以选择,我们可以通过统计信息选择最优的索引。例如:select * from t where age = 30 and name in ( ‘小明’, ‘小强’) 对于包含 Join 的操作,我们可以区分大小表,TiDB 的对于一个大表和一个小表的 Join 会有特殊的优化。 例如 select * from t join s on s.id = t.id 优化器会通过对表大小的估计来选择 Join 的算法:即选择把较小的表装入内存中。 对于多种方案,利用动态规划算法选择最优者,例如:(select * from t where c1 < 10) union all (select * from s where c2 < 10) order by c3 limit 10t 和 s 可以根据索引的数据分布来确定选择索引 c3 还是 c2。总之正确使用 TiDB 的姿势,或者说 TiDB 的典型的应用场景是:大数据量下,MySQL 复杂查询很慢;大数据量下,数据增长很快,接近单机处理的极限,不想分库分表或者使用数据库中间件等对业务侵入性较大,架构反过来约束业务的 Sharding 方案;大数据量下,有高并发实时写入、实时查询、实时统计分析的需求;有分布式事务、多数据中心的数据 100% 强一致性、auto-failover 的高可用的需求。如果整篇文章你只想记住一句话,那就是数据条数少于 5000w 的场景下通常用不到 TiDB,TiDB 是为大规模的数据场景设计的。如果还想记住一句话,那就是单机 MySQL 能满足的场景也用不到 TiDB。"}, {"url": "https://pingcap.com/weekly/2017-02-27-tidb-weekly/", "title": "Weekly update (February 19 ~ February 26, 2017)", "content": " Weekly update in TiDB Last week, we landed 39 PRs in the TiDB repositories.Added Support Revoke statement. Add rules in parser and empty implementation for unsupported builtin functions: #2667, #2677, #2679 Support wildcard chars in username or host in Grant statement. Add a context arggument for distsql/kv interface: We will use the context to cancel running jobs. Support Create Table ... Like statement. Support ON UPDATE CURRENT_TIMESTAMP with precision Support Show Warnings statement. Fixed Fix memory leak when IndexScanExecutor meet error. Add missing field length information for show databases; Add missing field length information for Show statement. Fix compatibility problme about string truncate error. Ignore malformated data in MySQL packet. Fix a bug about topn operator pushdown. Fix a bug about add column with default value and not null flag. Improved Prune correlated columns in groupby item list. Imporve the performance of point get query using primary key or unique key by 3%. Decorrelated for aggregation. Weekly update in TiKV Last week, We landed 25 PRs in the TiKV repositories.Added Detect system CPU/memory to adjust config automatically. Add RocksDB statistics. Balance store according to region count. Add label, ping , admin, scheduler, operator commands for pd-ctl. Add shuffle region scheduler. Fixed Verify PD address when start pd-ctl. Reject read index when new leader hasn’t committed the empty entry. Accelerate campaign faster after split happens. Use default value in column info. Improved Save one TS get for single point get by unique or primary key. Prettfiy command label name in metrics. Make Raft apply atomically. Add region ID for scheduler slow log. "}, {"url": "https://pingcap.com/meetup/meetup-2017-02-25/", "title": "COISF 专场|PingCAP 第 39 期 NewSQL Meetup", "content": " COISF 专场|PingCAP 第 39 期 NewSQL Meetup 2017-02-25 郝立飞 PingCAP PingCAPPingCAP ![]() 微信号pingcap2015功能介绍PingCAP 专注于新型"}, {"url": "https://pingcap.com/blog-cn/Spanner-cap-truetime-transaction/", "title": "Spanner - CAP, TrueTime and Transaction", "content": " 最近非常关注的一件事情就是 Google Spanner Cloud 的发布,这应该算是 NewSQL 又一个里程碑的事件。NewSQL 的概念应该就是在 12 年 Google Spanner 以及 F1 的论文发表之后,才开始慢慢流行,然后就开始有企业尝试根据 paper 做自己的 NewSQL,譬如国外的 CockroachDB 以及国内我们 PingCAP。Spanner 的论文在很早就发布了,国内也有很多中文翻译,这里笔者只是想聊聊自己对 Spanner 的理解,以及 Spanner 的一些关键技术的实现,以及跟我们自己的 TiDB 的相关对比。CAP 在分布式领域,CAP 是一个完全绕不开的东西,大家应该早就非常熟悉,这里笔者只是简单的再次说明一下: C:一致性,也就是通常说的线性一致性,假设在 T 时刻写入了一个值,那么在 T 之后的读取一定要能读到这个最新的值。 A:完全 100% 的可用性,也就是无论系统发生任何故障,都仍然能对外提供服务。 P:网络分区容忍性。 在分布式环境下面,P 是铁定存在的,也就是只要我们有多台机器,那么网络隔离分区就一定不可避免,所以在设计系统的时候我们就要选择到底是设计的是 AP 系统还是 CP 系统,但实际上,我们只要深入理解下 CAP,就会发现其实有时候系统设计上面没必要这么纠结,主要表现在: 网络分区出现的概率很低,所以我们没必要去刻意去忽略 C 或者 A。多数时候,应该是一个 CA 系统。 CAP 里面的 A 是 100% 的可用性,但实际上,我们只需要提供 high availability,也就是仅仅需要满足 99.99% 或者 99.999% 等几个 9 就可以了。 Spanner 是一个 CP + HA 系统,官方文档说的可用性是优于 5 个 9 ,稍微小于 6 个 9,也就是说,Spanner 在系统出现了大的故障的情况下面,大概 31s+ 的时间就能够恢复对外提供服务,这个时间是非常短暂的,远远比很多外部的系统更加稳定。然后鉴于 Google 强大的自建网络,P 很少发生,所以 Spanner 可以算是一个 CA 系统。TiDB 在设计的时候也是一个 CP + HA 系统,多数时候也是一个 CA 系统。如果出现了 P,也就是刚好对外服务的 leader 被隔离了,新 leader 大概需要 10s+ 以上的时间才能选举出来对外提供服务。当然,我们现在还不敢说系统的可用性在 6 个 9 了,6 个 9 现在还是我们正在努力的目标。当然,无论是 Spanner 还是 TiDB,当整个集群真的出现了灾难性的事故,导致大多数节点都出现了问题,整个系统当然不可能服务了,当然这个概率是非常小的,我们可以通过增加更多的副本数来降低这个概率发生。据传在一些关键数据上面,Spanner 都有 7 个副本。TrueTime 最开始看到 Spanner 论文的时候,我是直接被 TrueTime 给惊艳到了,这特么的完全就是解决分布式系统时间问题的一个核弹呀(银弹我可不敢说)。在分布式系统里面,时间到底有多么重要呢?之前笔者也写过一篇文章来聊过分布式系统的时间问题,简单来说,我们需要有一套机制来保证相关事务之间的先后顺序,如果事务 T1 在事务 T2 开始之前已经提交,那么 T2 一定能看到 T1 提交的数据。也就是事务需要有一个递增序列号,后开始的事务一定比前面开始的事务序列号要大。那么这跟时间又有啥关系呢,用一个全局序列号生成器不就行呢,为啥还要这么麻烦的搞一个 TrueTime 出来?笔者觉得有几个原因: 全局序列号生成器是一个典型的单点,即使会做一些 failover 的处理,但它仍然是整个系统的一个瓶颈。同时也避免不了网络开销。但全局序列号的实现非常简单,Google 之前的 Percolator 以及现在 TiDB 都是采用这种方式。 为什么要用时间?判断两个事件的先后顺序,时间是一个非常直观的度量方式,另外,如果用时间跟事件关联,那么我们就能知道某一个时间点整个系统的 snapshot。在 TiDB 的用户里面,一个非常典型的用法就是在游戏里面确认用户是否谎报因为回档丢失了数据,假设用户说在某个时间点得到某个装备,但后来又没有了,我们就可以直接在那个特定的时间点查询这个用户的数据,从而知道是否真的有问题。 我们不光可以用时间来确定以前的 snapshot,同样也可以用时间来约定集群会在未来达到某个状态。这个典型的应用就是 schema change。虽然笔者不清楚 Spanner schema change 的实现,但 Google F1 有一篇 Online, Asynchronous Schema Change in F1 论文提到了相关的方法,而 TiDB 也是采用的这种实现方式。简单来说,对于一个 schema change,通常都会分几个阶段来完成,如果集群某个节点在未来一个约定的时间没达到这个状态,这个节点就需要自杀下线,防止因为数据不一致损坏数据。 使用 TrueTime,Spanner 可以非常方便的实现笔者提到的用法,但 TrueTime 也并不是万能的: TrueTime 需要依赖 atomic clock 和 GPS,这属于硬件方案,而 Google 并没有论文说明如何构造 TrueTime,对于其他用户的实际并没有太多参考意义。 TrueTime 也会有误差范围,虽然非常的小,在毫秒级别以下,所以我们需要等待一个最大的误差时间,才能确保事务的相关顺序。 Transaction Spanner 默认将数据使用 range 的方式切分成不同的 splits,就跟 TiKV 里面 region 的概念比较类似。每一个 Split 都会有多个副本,分布在不同的 node 上面,各个副本之间使用 Paxos 协议保证数据的一致性。Spanner 对外提供了 read-only transaction 和 read-write transaction 两种事务,这里简单的介绍一下,主要参考 Spanner 的白皮书。Single Split Write 假设 client 要插入一行数据 Row 1,这种情况我们知道,这一行数据铁定属于一个 split,spanner 在这里使用了一个优化的 1PC 算法,流程如下: API Layer 首先找到 Row 1 属于哪一个 split,譬如 Split 1。 API Layer 将写入请求发送给 Split 1 的 leader。 Leader 开始一个事务。 Leader 首先尝试对于 Row 1 获取一个 write lock,如果这时候有另外的 read-write transaction 已经对于这行数据上了一个 read lock,那么就会等待直到能获取到 write lock。 这里需要注意的是,假设事务 1 先 lock a,然后 lock b,而事务 2 是先 lock b,在 lock a,这样就会出现 dead lock 的情况。这里 Spanner 采用的是 wound-wait 的解决方式,新的事务会等待老的事务的 lock,而老的事务可能会直接 abort 掉新的事务已经占用的 lock。 当 lock 被成功获取到之后,Leader 就使用 TrueTime 给当前事务绑定一个 timestamp。因为用 TrueTime,我们能够保证这个 timestamp 一定大于之前已经提交的事务 timestamp,也就是我们一定能够读取到之前已经更新的数据。 Leader 将这次事务和对应的 timestamp 复制给 Split 1 其他的副本,当大多数副本成功的将这个相关 Log 保存之后,我们就可以认为该事务已经提交(注意,这里还并没有将这次改动 apply)。 Leader 等待一段时间确保事务的 timestamp 有效(TrueTime 的误差限制),然后告诉 client 事务的结果。这个 commit wait 机制能够确保后面的 client 读请求一定能读到这次事务的改动。另外,因为 commit wait 在等待的时候,Leader 同时也在处理上面的步骤 6,等待副本的回应,这两个操作是并行的,所以 commit wait 开销很小。 Leader 告诉 client 事务已经被提交,同时也可以顺便返回这次事务的 timestamp。 在 Leader 返回结果给 client 的时候,这次事务的改动也在并行的被 apply 到状态机里面。 Leader 将事务的改动 apply 到状态机,并且释放 lock。 Leader 同时通知其他的副本也 apply 事务的改动。 后续其他的事务需要等到这次事务的改动被 apply 之后,才能读取到数据。对于 read-write 事务,因为要拿 read lock,所以必须等到之前的 write lock 释放。而对于 read-only 事务,则需要比较 read-only 的 timestamp 是不是大于最后已经被成功 apply 的数据的 timestamp。 TiDB 现在并没有使用 1PC 的方式,但不排除未来也针对单个 region 的 read-write 事务,提供 1PC 的支持。Multi Split Write 上面介绍了单个 Split 的 write 事务的实现流程,如果一个 read-write 事务要操作多个 Split 了,那么我们就只能使用 2PC 了。假设一个事务需要在 Split 1 读取数据 Row 1,同时将改动 Row 2,Row 3 分别写到 Split 2,Split 3,流程如下: client 开始一个 read-write 事务。 client 需要读取 Row 1,告诉 API Layer 相关请求。 API Layer 发现 Row 1 在 Split 1。 API Layer 给 Split 1 的 Leader 发送一个 read request。 Split1 的 Leader 尝试将 Row 1 获取一个 read lock。如果这行数据之前有 write lock,则会持续等待。如果之前已经有另一个事务上了一个 read lock,则不会等待。至于 deadlock,仍然采用上面的 wound-wait 处理方式。 Leader 获取到 Row 1 的数据并且返回。 . Clients 开始发起一个 commit request,包括 Row 2,Row 3 的改动。所有的跟这个事务关联的 Split 都变成参与者 participants。 一个 participant 成为协调者 coordinator,譬如这个 case 里面 Row 2 成为 coordinator。Coordinator 的作用是确保事务在所有 participants 上面要不提交成功,要不失败。这些都是在 participants 和 coordinator 各自的 Split Leader 上面完成的。 Participants 开始获取 lock Split 2 对 Row 2 获取 write lock。 Split 3 对 Row 3 获取 write lock。 Split 1 确定仍然持有 Row 1 的 read lock。 每个 participant 的 Split Leader 将 lock 复制到其他 Split 副本,这样就能保证即使节点挂了,lock 也仍然能被持有。 如果所有的 participants 告诉 coordinator lock 已经被持有,那么就可以提交事务了。coordinator 会使用这个时候的时间点作为这次事务的提交时间点。 如果某一个 participant 告诉 lock 不能被获取,事务就被取消 如果所有 participants 和 coordinator 成功的获取了 lock,Coordinator 决定提交这次事务,并使用 TrueTime 获取一个 timestamp。这个 commit 决定,以及 Split 2 自己的 Row 2 的数据,都会复制到 Split 2 的大多数节点上面,复制成功之后,就可以认为这个事务已经被提交。 Coordinator 将结果告诉其他的 participants,各个 participant 的 Leader 自己将改动复制到其他副本上面。 如果事务已经提交,coordinator 和所有的 participants 就 apply 实际的改动。 Coordinator Leader 返回给 client 说事务已经提交成功,并且返回事务的 timestamp。当然为了保证数据的一致性,需要有 commit-wait。 TiDB 也使用的是一个 2PC 方案,采用的是优化的类 Google Percolator 事务模型,没有中心的 coordinator,全部是靠 client 自己去协调调度的。另外,TiDB 也没有实现 wound-wait,而是对一个事务需要操作的 key 顺序排序,然后依次上 lock,来避免 deadlock。Strong Read 上面说了在一个或者多个 Split 上面 read-write 事务的处理流程,这里在说说 read-only 的事务处理,相比 read-write,read-only 要简单一点,这里以多个 Split 的 Strong read 为例。假设我们要在 Split 1,Split 2 和 Split 3 上面读取 Row 1,Row 2 和 Row 3。 API Layer 发现 Row 1,Row 2,和 Row 3 在 Split1,Split 2 和 Split 3 上面。 API Layer 通过 TrueTime 获取一个 read timestamp(如果我们能够接受 Stale Read 也可以直接选择一个以前的 timestamp 去读)。 API Layer 将读的请求发给 Split 1,Split 2 和 Split 3 的一些副本上面,这里有几种情况: 多数情况下面,各个副本能通过内部状态和 TrueTime 知道自己有最新的数据,直接能提供 read。 如果一个副本不确定是否有最新的数据,就向 Leader 问一下最新提交的事务 timestamp 是啥,然后等到这个事务被 apply 了,就可以提供 read。 如果副本本来就是 Leader,因为 Leader 一定有最新的数据,所以直接提供 read。 各个副本的结果汇总然会返回给 client。 当然,Spanner 对于 Read 还有一些优化,如果我们要进行 stale read,并且这个 stale 的时间在 10s 之前,那么就可以直接在任何副本上面读取,因为 Leader 会每隔 10s 将最新的 timestamp 更新到其他副本上面。现在 TiDB 只能支持从 Leader 读取数据,还没有支持 follower read,这个功能已经实现,但还有一些优化需要进行,现阶段并没有发布。TiDB 在 Leader 上面的读大部分走的是 lease read,也就是只要 Leader 能够确定自己仍然在 lease 有效范围里面,就可以直接读,如果不能确认,我们就会走 Raft 的 ReadIndex 机制,让 Leader 跟其他节点进行 heartbeat 交互,确认自己仍然是 Leader 之后再进行读操作。小结 随着 Spanner Cloud 的发布,我们这边也会持续关注 Spanner Cloud 的进展,TiDB 的原始模型就是基于 Spanner + F1 搭建起来,随着 Spanner Cloud 更多资料的公布,TiDB 也能有更多的参考。另外,我们一直相信,我们走在正确的道路上面,如果你对我们的东西感兴趣,欢迎联系我。 邮箱:tl@pingcap.com 微信:siddontang "}, {"url": "https://pingcap.com/blog-cn/lease-read/", "title": "TiKV 源码解析系列 - Lease Read", "content": " Raft log read TiKV 是一个要保证线性一致性的分布式 KV 系统,所谓线性一致性,一个简单的例子就是在 t1 的时间我们写入了一个值,那么在 t1 之后,我们的读一定能读到这个值,不可能读到 t1 之前的值。因为 Raft 本来就是一个为了实现分布式环境下面线性一致性的算法,所以我们可以通过 Raft 非常方便的实现线性 read,也就是将任何的读请求走一次 Raft log,等这个 log 提交之后,在 apply 的时候从状态机里面读取值,我们就一定能够保证这个读取到的值是满足线性要求的。当然,大家知道,因为每次 read 都需要走 Raft 流程,所以性能是非常的低效的,所以大家通常都不会使用。我们知道,在 Raft 里面,节点有三个状态,leader,candidate 和 follower,任何 Raft 的写入操作都必须经过 leader,只有 leader 将对应的 raft log 复制到 majority 的节点上面,我们才会认为这一次写入是成功的。所以我们可以认为,如果当前 leader 能确定一定是 leader,那么我们就可以直接在这个 leader 上面读取数据,因为对于 leader 来说,如果确认一个 log 已经提交到了大多数节点,在 t1 的时候 apply 写入到状态机,那么在 t1 之后后面的 read 就一定能读取到这个新写入的数据。那么如何确认 leader 在处理这次 read 的时候一定是 leader 呢?在 Raft 论文里面,提到了两种方法。ReadIndex Read 第一种就是 ReadIndex,当 leader 要处理一个读请求的时候: 将当前自己的 commit index 记录到一个 local 变量 ReadIndex 里面。 向其他节点发起一次 heartbeat,如果大多数节点返回了对应的 heartbeat response,那么 leader 就能够确定现在自己仍然是 leader。 Leader 等待自己的状态机执行,直到 apply index 超过了 ReadIndex,这样就能够安全的提供 linearizable read 了。 Leader 执行 read 请求,将结果返回给 client。 可以看到,不同于最开始的通过 Raft log 的 read,ReadIndex read 使用了 heartbeat 的方式来让 leader 确认自己是 leader,省去了 Raft log 那一套流程。虽然仍然会有网络开销,但 heartbeat 本来就很小,所以性能还是非常好的。但这里,需要注意,实现 ReadIndex 的时候有一个 corner case,在 etcd 和 TiKV 最初实现的时候,我们都没有注意到。也就是 leader 刚通过选举成为 leader 的时候,这时候的 commit index 并不能够保证是当前整个系统最新的 commit index,所以 Raft 要求当 leader 选举成功之后,首先提交一个 no-op 的 entry,保证 leader 的 commit index 成为最新的。所以,如果在 no-op 的 entry 还没提交成功之前,leader 是不能够处理 ReadIndex 的。但之前 etcd 和 TiKV 的实现都没有注意到这个情况,也就是有 bug。解决的方法也很简单,因为 leader 在选举成功之后,term 一定会增加,在处理 ReadIndex 的时候,如果当前最新的 commit log 的 term 还没到新的 term,就会一直等待跟新的 term 一致,也就是 no-op entry 提交之后,才可以对外处理 ReadIndex。使用 ReadIndex,我们也可以非常方便的提供 follower read 的功能,follower 收到 read 请求之后,直接给 leader 发送一个获取 ReadIndex 的命令,leader 仍然走一遍之前的流程,然后将 ReadIndex 返回给 follower,follower 等到当前的状态机的 apply index 超过 ReadIndex 之后,就可以 read 然后将结果返回给 client 了。Lease Read 虽然 ReadIndex 比原来的 Raft log read 快了很多,但毕竟还是有 Heartbeat 的开销,所以我们可以考虑做更进一步的优化。在 Raft 论文里面,提到了一种通过 clock + heartbeat 的 lease read 优化方法。也就是 leader 发送 heartbeat 的时候,会首先记录一个时间点 start,当系统大部分节点都回复了 heartbeat response,那么我们就可以认为 leader 的 lease 有效期可以到 start + election timeout / clock drift bound 这个时间点。为什么能够这么认为呢?主要是在于 Raft 的选举机制,因为 follower 会在至少 election timeout 的时间之后,才会重新发生选举,所以下一个 leader 选出来的时间一定可以保证大于 start + election timeout / clock drift bound。虽然采用 lease 的做法很高效,但仍然会面临风险问题,也就是我们有了一个预设的前提,各个服务器的 CPU clock 的时间是准的,即使有误差,也会在一个非常小的 bound 范围里面,如果各个服务器之间 clock 走的频率不一样,有些太快,有些太慢,这套 lease 机制就可能出问题。TiKV 使用了 lease read 机制,主要是我们觉得在大多数情况下面 CPU 时钟都是正确的,当然这里会有隐患,所以我们也仍然提供了 ReadIndex 的方案。TiKV 的 lease read 实现在原理上面跟 Raft 论文上面的一样,但实现细节上面有些差别,我们并没有通过 heartbeat 来更新 lease,而是通过写操作。对于任何的写入操作,都会走一次 Raft log,所以我们在 propose 这次 write 请求的时候,记录下当前的时间戳 start,然后等到对应的请求 apply 之后,我们就可以续约 leader 的 lease。当然实际实现还有很多细节需要考虑的,譬如: 我们使用的 monotonic raw clock,而 不是 monotonic clock,因为 monotonic clock 虽然不会出现 time jump back 的情况,但它的速率仍然会受到 NTP 等的影响。 我们默认的 election timeout 是 10s,而我们会用 9s 的一个固定 max time 值来续约 lease,这样一个是为了处理 clock drift bound 的问题,而另一个则是为了保证在滚动升级 TiKV 的时候,如果用户调整了 election timeout,lease read 仍然是正确的。因为有了 max lease time,用户的 election timeout 只能设置的比这个值大,也就是 election timeout 只能调大,这样的好处在于滚动升级的时候即使出现了 leader 脑裂,我们也一定能够保证下一个 leader 选举出来的时候,老的 leader lease 已经过期了。 当然,使用 Raft log 来更新 lease 还有一个问题,就是如果用户长时间没有写入操作,这时候来的读取操作因为早就已经没有 lease 了,所以只能强制走一次上面的 ReadIndex 机制来 read,但上面已经说了,这套机制性能也是有保证的。至于为什么我们不在 heartbeat 那边更新 lease,原因就是我们 TiKV 的 Raft 代码想跟 etcd 保持一致,但 etcd 没这个需求,所以我们就做到了外面。小结 在 TiKV 里面,从最开始的 Raft log read,到后面的 Lease Read,我们一步一步的在保证线性一致性的情况下面改进着性能。后面,我们会引入更多的一致性测试 case 来验证整个系统的安全性,当然,也会持续的提升性能。"}, {"url": "https://pingcap.com/meetup/meetup-2017-02-18/", "title": "COISF 专场|PingCAP 第 38 期 NewSQL Meetup", "content": " COISF 专场|PingCAP 第 38 期 NewSQL Meetup 2017-02-18 刘奇 PingCAP PingCAPPingCAP ![]() 微信号pingcap2015功能介绍PingCAP 专注于新型"}, {"url": "https://pingcap.com/weekly/2017-02-13-tidb-weekly/", "title": "Weekly update (February 06 ~ February 12, 2017)", "content": " Weekly update in TiDB Last two weeks, we landed 25 PRs in the TiDB repositories.Added Support basic privilege framework: #2423, #2557, #2603, #2607, Support ALTER [COLUMN] col_name SET DEFAULT statement. Validate column default value when creating table. Support ALTER TABLE ... DROP DEFAULT statement. Support changing default value and comment in alter table statement. Fixed Fix build on i386. Fix output format of prometheus interval log. Clean up log: #2599, #2601 Fix a bug in HashJoin executor: some errors are ignored. Fix a bug in arithmetic expression type inference. Fix a bug in builtin function timediff. Improved Speed up unit tests. Make test cases more stable: #2595, #2596 Remove useless code in parser package. Change string default collation to utf8_bin. We do not support case insensitive comparation yet. Weekly update in TiKV Last week, We landed 14 PRs in the TiKV repositories.Added Use seek_for_prev directly. Refactor cut_row and cut_idx_key for row value analysis in coprocessor. Extract an interface to support different snapshot format. Fixed Fix panic when stop scheduler worker. Fix invalid link in PD readme. Improved Evaluate logic operations lazily. Use prefix seek to speed up read for Write CF. Separate advance to advance_ready and advance_apply for async-apply later. Use shutdown to do cleanup when stop worker. "}, {"url": "https://pingcap.com/weekly/2017-02-05-tidb-weekly/", "title": "Weekly update (January 23 ~ February 05, 2017)", "content": " Weekly update in TiDB Last two weeks, we landed 43 PRs in the TiDB repositories.Added Support information_schema.table_constraints. Support the UTC_TIMESTAMP builtin function Increase transaction entry count limit. Add logs for expensive query and big transaction: 2536, 2545, 2546 Fixed Fix GC lifetime metrics. Fix primary key name parsing. Fix a bug of left outer semi join. Fix a bug of exists sub query. Fix a bug abaout prefix index. Improved Only plans that have apply will add cache. Use a short-cut way to way And/Or/Xor expresson. Refine the range calculating. Weekly update in TiKV Last two weeks, we landed 20 PRs in the TiKV repositories.Added Add start_ts for scan in tikv-ctl. Support HTTP scheme parsing. Fixed Fix too long scan slow log. Improved Use reverse_seek_le for the reverse seek write. Ignore overwriting data in prewrite. Update raft in raftstore after handling ConfChange. Make coprocessor task run more concurrently. Ignore deleting the value when roll back lock. Update leader lease before applying raft log. "}, {"url": "https://pingcap.com/weekly/2017-01-24-tidb-weekly/", "title": "Weekly update (January 09 ~ January 22, 2017)", "content": " Weekly update in TiDB Last two weeks, we landed 87 PRs in the TiDB repositories.Added Support statistic on index data Support file sort operator Add key prefix length limitation on index Support the TIMESTAMPDIFF built-in function. Support the CONV built-in function. Support the SUBSTR built-in function. Support the SIGN built-in function. Support the FROM_DAYS built-in function. Support the FIELD built-in function. Support the FLOOR built-in function. Support the SQRT built-in function. Add some metrics: #2417, #2419, #2435, #2451, #2460, [#2477])(https://github.com/pingcap/tidb/pull/2477) Set a limitation about the key-value count and size in a single transaction. Support Rename Table and Alter Table Rename Table statement. Fixed Add a length limitation for logging sql statement when meet sytax error. Fix a bug when binary literal has charset prefix. Fix a few bugs about optimizer: #2439, #2440, #2452 Fix a bug about parsing aggragate function. Fix a bug about two phrase commit. Fix a bug about round function. Fix a bug occurs when subquery contains a aggragetion. Fix a memory leak in Join Executor. Improved Use cache to store privilege info. Refactor correlated subquery optimization. Speed up delete statement executor. Handle raft entry too large error. Change the argument name for displaying version from v to V: keep consistent with pd/tikv. Convert distinct to aggragate. New contributor zhexuany Weekly update in TiKV Last two weeks, We landed 50 PRs in the TiKV repositories.Added Add -V flag for PD and TiKV. Set a limitation for the max size of the raft entry. Make disabling manual compaction configurable. Add fail reason tag in raft request and coprocessor metrics. Add snapshot KV count and size metrics. Add count of written keys metric. Add raft log lag metric. Add thread CPU collector. Support compaction_readahead_size for spinning disk. Support getting region with key in pd-ctl . Statistic region write key-value count and bytes. Fixed Fix a pitfall when use different context package. Count KV count in other CF when check splitting. Avoid submitting secondary key if primary key is locked. Use disk size as storage capacity when capacity is set to 0. Check locked for ResolveLock in latch. Improved Keep large integer precision and check integer overflow. Check promotable when handle raft MsgTimeoutNow. Unify logger. Resume paused follower when receive MsgHeartbeatResp message. Reset the pending state when add node. Allow running one GC command at the same time. Guarantee replicas are safe if possible. Keep leader alive before initialization. Log slow request for scheduler. Record scan efficiency for coprocessor. Make raft log GC not depend on PeerStorage. Accelerate ticks for new split region leader. "}, {"url": "https://pingcap.com/blog-cn/pd-scheduler/", "title": "TiKV 源码浅析 - PD Scheduler", "content": " 在前面的文章里面,我们介绍了 PD 一些常用功能,以及它是如何跟 TiKV 进行交互的,这里,我们重点来介绍一下 PD 是如何调度 TiKV 的。介绍 假设我们只有一个 TiKV,那么根本就无需调度了,因为数据只可能在这一台机器上面,client 也只可能跟这一个 TiKV 进行交互。但我们知道,在分布式存储领域,这样的情况不可能一直持续,因为数据量的增量一定会超过当前机器的物理存储极限,必然我们需要将一部分数据迁移到其他机器上面去。在之前的文章里面,我们介绍过,TiKV 是通过 range 的方式将数据进行切分的。我们使用 Region 来表示一个数据 range,每个 Region 有多个副本 peer,通常为了安全,我们会使用至少三个副本。最开始系统初始化的时候,我们只有一个 region,当数据量持续增大,超过了 Region 设置的最大 size(64MB) 阈值的时候,region 就会分裂,生成两个新的 region。region 是 PD 调度 TiKV 的基本单位。当我们新增加一个 TiKV 的时候,PD 就会将原来TiKV 里面的一些 Region 调度到这个新增的 TiKV 上面,这样就能保证整个数据均衡的分布在多个 TiKV 上面。因为一个 Region 通常是 64MB,其实将一个 Region 从一个 TiKV 移动到另一个 TiKV,数据量的变更其实不大,所以我们可以直接使用 Region 的数量来大概的做数据的平衡。譬如,现在假设有六个 TiKV,我们有一百个 region,每个 Region 三个副本 peer,总共三百个 Region peer,我们只要保证每个 TiKV 有五十个左右的 Region peer,就大概知道数据是平衡了。上面我们只是介绍了数据的调度,但实际情况比这个要复杂很多,我们不光要考虑数据的均衡,也需要考虑计算的均衡,这样才能保证整个 TiKV 集群更好更快的对外提供服务。因为 TiKV 使用的是 Raft 分布式一致性算法,Raft 有一个强约束就是为了保证线性一致性,所有的读写都必须通过 leader 发起(后续我们会支持 follower read,能分担读压力)。假设现在有三个 TiKV,如果几乎所有的 leader 都集中在某一个 TiKV 上面,那么会造成这个 TiKV 成为性能瓶颈,最好的做法就是 leader 能够均衡在不同的 TiKV 上面,这样整个系统都能对外提供服务。所以,在 PD,我们主要会对两种资源进行调度,存储 storage 以及计算 leader。关键 Interface 和 Structure 为了满足不同的调度需求,PD 将调度相关的操作都抽象成了 interface,外面可以自由组合形成自己的调度方案。Scheduler Scheduler 是用来调度资源的接口,定义如下:// Scheduler is an interface to schedule resources. type Scheduler interface { GetName() string GetResourceKind() ResourceKind Schedule(cluster *clusterInfo) Operator } GetName 返回 Scheduler 名字,不同的 scheduler 不能重名。GetResourceKind 则是返回这个 Scheduler 要处理的资源类型,现阶段我们就两种,一个 leader,一个 storage。 Scheduler 则是进行实际的调度,它需要的参数就是整个集群的信息 ,在里面会生成实际的调度操作 Operator。Operator 前面我们说了,PD 对于 TiKV 调度的基本单位就是 region,所以 Scheduler 生成的 Operator 就是对一个 Region 进行调度。Operator 定义如下:// Operator is an interface to schedule region. type Operator interface { GetRegionID() uint64 GetResourceKind() ResourceKind Do(region *regionInfo) (*pdpb.RegionHeartbeatResponse, bool) } GetRegionID 得到需要调度的 Region ID,GetResourceKind 的含义跟 Scheduler 的一样。Do 则是对这个 Region 执行实际的操作,返回一个 RegionHeartbeatResponse。在之前的文章里面,我们说过,PD 对于 TiKV 的调度操作,都是在 TiKV Region heartbeat 命令里面返回给 TiKV,然后 TiKV 再去执行的。多个 Operator 也可以组合成一个更上层的 Operator,但需要注意,这些 Operator 一定要有相同的 ResourceKind,也就是说,我们不能在一组 Operator 里面操作不同的 resource。Selector / Filter 假设我们要进行 storage 的调度,选择了一个 region,那么我们就需要做的是将 region 里面的一个副本 peer,迁移到另外的一个新的 TiKV 上面。所以我们在调度的时候,就需要选择一个合适的需要调度的 TiKV,也就是 source,然后就是一个合适的将被调度到的 TiKV,也就是 target。这个就是通过 Selector 来完成的。// Selector is an interface to select source and target store to schedule. type Selector interface { SelectSource(stores []*storeInfo, filters ...Filter) *storeInfo SelectTarget(stores []*storeInfo, filters ...Filter) *storeInfo } Selector 的接口非常的简单,就是根据传入的 storeInfo 列表,以及一批 Filter,选择合适的 source 和 target,供 scheduler 实际去调度。Filter 的定义如下:// Filter is an interface to filter source and target store. type Filter interface { // Return true if the store should not be used as a source store. FilterSource(store *storeInfo) bool // Return true if the store should not be used as a target store. FilterTarget(store *storeInfo) bool } 如果 Filter 的函数返回 true,就表明我们不能选择这个 store。Controller 通常,我们希望调度越来越快就好,但是实际情况,我们必须要保证调度不能影响现有的系统,不能造成现有系统出现太大的波动。譬如,在做 storage 的调度的时候,PD 需要将 region 的某一个副本从一个 TiKV 迁移到另一个 TiKV,该 region 的 leader peer 会首先在目标 TiKV 上面添加一个新的 peer,这时候的操作是 leader 会生成当前 region 的 snapshot,然后发给 follower。Follower 收到 snapshot 之后,apply 到自己的状态机里面。同时,leader 会给原来要迁移的 peer 发送删除命令,该 follower 会在状态机里面清掉对应的数据。虽然一个 region 大概是 64MB,但过于频繁的一下子删除 64MB 数据,或者新增 64MB 数据,对于整个系统都是一个不小的负担。所以我们一定要控制整个调度的速度。// Controller is an interface to control the speed of different schedulers. type Controller interface { Ctx() context.Context Stop() GetInterval() time.Duration AllowSchedule() bool } Controller 主要用来负责控制整个调度的速度,GetInterval 返回调度的间隔时间,当上一次调度之后,需要等待多久开始下一次的调度。AllowSchedule 则是表明是否允许调度。Coordinator PD 使用 Coodinator 来管理所有的 Scheduler 以及 Controlller。// ScheduleController combines Scheduler with Controller. type ScheduleController struct { Scheduler Controller } 通常,对于调度,Scheduler 和 Controller 是同时存在的,所以在 Coordinator 里面会使用 ScheduleController 来统一进行管理。Coordinator 在 region heartbeat 的时候,会看这个 region 是否需要调度,如果需要,则进行调度。另外,在 Coordinator 里面,我们还有一个 replicaCheckController 定期检查 region 是否需要调度。因为 PD 知道整个集群的情况,所以 PD 就知道什么时候该进行调度。譬如,假设 PD 发现一个 TiKV 已经当掉,那么就会对在这个 TiKV 有副本的 region 生成调度 Operator,移除这个坏掉的副本,添加另一个好的副本,当 region heartbeat 上来的时候,直接接返回这个调度策略让 TiKV 去执行。小结 这里简单的介绍了 PD 调度器的基本原理,需要调度的资源,以及一些关键的调度 Interface 以及 Structure,后面,我们会详细的介绍一些特定的调度策略,以及 PD 是如何通过 label 来进行更精确的调度的。"}, {"url": "https://pingcap.com/meetup/meetup-2017-01-14/", "title": "COISF 专场|PingCAP 第 37 期 NewSQL Meetup", "content": " COISF 专场|PingCAP 第 37 期 NewSQL Meetup 2017-01-14 杨策&黄华超 PingCAP PingCAPPingCAP ![]() 微信号pingcap2015功能介绍PingCAP 专注于新型"}, {"url": "https://pingcap.com/blog-cn/placement-driver/", "title": "TiKV 源码解析系列 - Placement Driver", "content": " 介绍 Placement Driver (后续以 PD 简称) 是 TiDB 里面全局中心总控节点,它负责整个集群的调度,负责全局 ID 的生成,以及全局时间戳 TSO 的生成等。PD 还保存着整个集群 TiKV 的元信息,负责给 client 提供路由功能。作为中心总控节点,PD 通过集成 etcd ,自动的支持 auto failover,无需担心单点故障问题。同时,PD 也通过 etcd 的 raft,保证了数据的强一致性,不用担心数据丢失的问题。在架构上面,PD 所有的数据都是通过 TiKV 主动上报获知的。同时,PD 对整个 TiKV 集群的调度等操作,也只会在 TiKV 发送 heartbeat 命令的结果里面返回相关的命令,让 TiKV 自行去处理,而不是主动去给 TiKV 发命令。这样设计上面就非常简单,我们完全可以认为 PD 是一个无状态的服务(当然,PD 仍然会将一些信息持久化到 etcd),所有的操作都是被动触发,即使 PD 挂掉,新选出的 PD leader 也能立刻对外服务,无需考虑任何之前的中间状态。初始化 PD 集成了 etcd,所以通常,我们需要启动至少三个副本,才能保证数据的安全。现阶段 PD 有集群启动方式,initial-cluster 的静态方式以及 join 的动态方式。在继续之前,我们需要了解下 etcd 的端口,在 etcd 里面,默认要监听 2379 和 2380 两个端口。2379 主要是 etcd 用来处理外部请求用的,而 2380 则是 etcd peer 之间相互通信用的。假设现在我们有三个 pd,分别为 pd1,pd2,pd3,分别在 host1,host2,host3 上面。对于静态初始化,我们直接在三个 PD 启动的时候,给 initial-cluster 设置 pd1=http://host1:2380,pd2=http://host2:2380,pd3=http://host3:2380。对于动态初始化,我们先启动 pd1,然后启动 pd2,加入到 pd1 的集群里面,join 设置为 pd1=http://host1:2379。然后启动 pd3,加入到 pd1,pd2 形成的集群里面, join 设置为 pd1=http://host1:2379。可以看到,静态初始化和动态初始化完全走的是两个端口,而且这两个是互斥的,也就是我们只能使用一种方式来初始化集群。etcd 本身只支持 initial-cluster 的方式,但为了方便,PD 同时也提供了 join 的方式。join 主要是用了 etcd 自身提供的 member 相关 API,包括 add member,list member 等,所以我们使用 2379 端口,因为需要将命令发到 etcd 去执行。而 initial-cluster 则是 etcd 自身的初始化方式,所以使用的 2380 端口。相比于 initial-cluster,join 需要考虑非常多的 case(在 server/join.go prepareJoinCluster 函数里面有详细的解释),但 join 的使用非常自然,后续我们会考虑去掉 initial-cluster 的初始化方案。选举 当 PD 启动之后,我们就需要选出一个 leader 对外提供服务。虽然 etcd 自身也有 raft leader,但我们还是觉得使用自己的 leader,也就是 PD 的 leader 跟 etcd 自己的 leader 是不一样的。当 PD 启动之后,Leader 的选举如下: 检查当前集群是不是有 leader,如果有 leader,就 watch 这个 leader,只要发现 leader 掉了,就重新开始 1。 如果没有 leader,开始 campaign,创建一个 Lessor,并且通过 etcd 的事务机制写入相关信息,如下:// Create a lessor. ctx, cancel := context.WithTimeout(s.client.Ctx(), requestTimeout) leaseResp, err := lessor.Grant(ctx, s.cfg.LeaderLease) cancel() // The leader key must not exist, so the CreateRevision is 0. resp, err := s.txn(). If(clientv3.Compare(clientv3.CreateRevision(leaderKey), "=", 0)). Then(clientv3.OpPut(leaderKey, s.leaderValue, clientv3.WithLease(clientv3.LeaseID(leaseResp.ID)))). Commit() 如果 leader key 的 CreateRevision 为 0,表明其他 PD 还没有写入,那么我就可以将我自己的 leader 相关信息写入,同时会带上一个 Lease。如果事务执行失败,表明其他的 PD 已经成为了 leader,那么就重新回到 1。 成为 leader 之后,我们对定期进行保活处理:// Make the leader keepalived. ch, err := lessor.KeepAlive(s.client.Ctx(), clientv3.LeaseID(leaseResp.ID)) if err != nil { return errors.Trace(err) } 当 PD 崩溃,原先写入的 leader key 会因为 lease 到期而自动删除,这样其他的 PD 就能 watch 到,重新开始选举。 初始化 raft cluster,主要是从 etcd 里面重新载入集群的元信息。拿到最新的 TSO 信息:// Try to create raft cluster. err = s.createRaftCluster() if err != nil { return errors.Trace(err) } log.Debug("sync timestamp for tso") if err = s.syncTimestamp(); err != nil { return errors.Trace(err) } 所有做完之后,开始定期更新 TSO,监听 lessor 是否过期,以及外面是否主动退出:for { select { case _, ok := <-ch: if !ok { log.Info("keep alive channel is closed") return nil } case <-tsTicker.C: if err = s.updateTimestamp(); err != nil { return errors.Trace(err) } case <-s.client.Ctx().Done(): return errors.New("server closed") } } TSO 前面我们说到了 TSO,TSO 是一个全局的时间戳,它是 TiDB 实现分布式事务的基石。所以对于 PD 来说,我们首先要保证它能快速大量的为事务分配 TSO,同时也需要保证分配的 TSO 一定是单调递增的,不可能出现回退的情况。TSO 是一个 int64 的整形,它由 physical time + logical time 两个部分组成。Physical time 是当前 unix time 的毫秒时间,而 logical time 则是一个最大 1 << 18 的计数器。也就是说 1ms,PD 最多可以分配 262144 个 TSO,这个能满足绝大多数情况了。对于 TSO 的保存于分配,PD 会做如下处理: 当 PD 成为 leader 之后,会从 etcd 上面获取上一次保存的时间,如果发现本地的时间比这个大,则会继续等待直到当前的时间大于这个值:last, err := s.loadTimestamp() if err != nil { return errors.Trace(err) } var now time.Time for { now = time.Now() if wait := last.Sub(now) + updateTimestampGuard; wait > 0 { log.Warnf("wait %v to guarantee valid generated timestamp", wait) time.Sleep(wait) continue } break } 当 PD 能分配 TSO 之后,首先会向 etcd 申请一个最大的时间,譬如,假设当前时间是 t1,每次最多能申请 3s 的时间窗口,PD 会向 etcd 保存 t1 + 3s 的时间值,然后 PD 就能在内存里面直接使用这一段时间窗口.当当前的时间 t2 大于 t1 + 3s 之后,PD 就会在向 etcd 继续更新为 t2 + 3s:if now.Sub(s.lastSavedTime) >= 0 { last := s.lastSavedTime save := now.Add(s.cfg.TsoSaveInterval.Duration) if err := s.saveTimestamp(save); err != nil { return errors.Trace(err) } } 这么处理的好处在于,即使 PD 当掉,新启动的 PD 也会从上一次保存的最大的时间之后开始分配 TSO,也就是 1 处理的情况。 因为 PD 在内存里面保存了一个可分配的时间窗口,所以外面请求 TSO 的时候,PD 能直接在内存里面计算 TSO 并返回。resp := pdpb.Timestamp{} for i := 0; i < maxRetryCount; i++ { current, ok := s.ts.Load().(*atomicObject) if !ok { log.Errorf("we haven't synced timestamp ok, wait and retry, retry count %d", i) time.Sleep(200 * time.Millisecond) continue } resp.Physical = current.physical.UnixNano() / int64(time.Millisecond) resp.Logical = atomic.AddInt64(¤t.logical, int64(count)) if resp.Logical >= maxLogical { time.Sleep(updateTimestampStep) continue } return resp, nil } 因为是在内存里面计算的,所以性能很高,我们自己内部测试每秒能分配百万级别的 TSO。 如果 client 每次事务都向 PD 来请求一次 TSO,每次 RPC 的开销也是非常大的,所以 client 会批量的向 PD 获取 TSO。client 会首先收集一批事务的 TSO 请求,譬如 n 个,然后直接向 PD 发送命令,参数就是 n,PD 收到命令之后,会生成 n 个 TSO 返回给客户端。 心跳 在最开始我们说过,PD 所有关于集群的数据都是由 TiKV 主动心跳上报的,PD 对 TiKV 的调度也是在心跳的时候完成的。通常 PD 会处理两种心跳,一个是 TiKV 自身 store 的心跳,而另一个则是 store 里面 region 的 leader peer 上报的心跳。对于 store 的心跳,PD 在 handleStoreHeartbeat 函数里面处理,主要就是将心跳里面当前的 store 的一些状态缓存到 cache 里面。store 的状态包括该 store 有多少个 region,有多少个 region 的 leader peer 在该 store 上面等,这些信息都会用于后续的调度。对于 region 的心跳,PD 在 handleRegionHeartbeat 里面处理。这里需要注意,只有 leader peer 才会去上报所属 region 的信息,follower peer 是不会上报的。收到 region 的心跳之后,首先 PD 也会将其放入 cache 里面,如果 PD 发现 region 的 epoch 有变化,就会将这个 region 的信息也保存到 etcd 里面。然后,PD 会对这个 region 进行具体的调度,譬如发现 peer 数目不够,添加新的 peer,或者有一个 peer 已经坏了,删除这个 peer 等,详细的调度实现,我们会在后续讨论。这里再说一下 region 的 epoch,在 region 的 epoch 里面,有 conf_ver 和 version,分别表示这个 region 不同的版本状态。如果一个 region 发生了 membership changes,也就是新增或者删除了 peer,conf_ver 会加 1,如果 region 发生了 split 或者 merge,则 version 加 1。无论是 PD 还是在 TiKV,我们都是通过 epoch 来判断 region 是否发生了变化,从而拒绝掉一些危险的操作。譬如 region 已经发生了分裂,version 变成了 2,那么如果这时候有一个写请求带上的 version 是 1, 我们就会认为这个请求是 stale,会直接拒绝掉。因为 version 变化表明 region 的范围已经发生了变化,很有可能这个 stale 的请求需要操作的 key 是在之前的 region range 里面而没在新的 range 里面。Split / Merge 前面我们说了,PD 会在 region 的 heartbeat 里面对 region 进行调度,然后直接在 heartbeat 的返回值里面带上相关的调度信息,让 TiKV 自己去处理,TiKV 处理完成之后,通过下一个 heartbeat 重新上报,PD 就能知道是否调度成功了。对于 membership changes,比较容易,因为我们有最大副本数的配置,假设三个,那么当 region 的心跳上来,发现只有两个 peer,那么就 add peer,如果有四个 peer,就 remove peer。而对于 region 的 split / merge,则情况稍微要复杂一点,但也比较简单。注意,现阶段,我们只支持 split,merge 处于开发阶段,没对外发布,所以这里仅仅以 split 举例: 在 TiKV 里面,leader peer 会定期检查 region 所占用的空间是否超过某一个阀值,假设我们设置 region 的 size 为 64MB,如果一个 region 超过了 96MB, 就需要分裂。 Leader peer 会首先向 PD 发送一个请求分裂的命令,PD 在 handleAskSplit 里面处理,因为我们是一个 region 分裂成两个,对于这两个新分裂的 region,一个会继承之前 region 的所有的元信息,而另一个相关的信息,譬如 region ID,新的 peer ID,则需要 PD 生成,并将其返回给 leader。 Leader peer 写入一个 split raft log,在 apply 的时候执行,这样 region 就分裂成了两个。 分裂成功之后,TiKV 告诉 PD,PD 就在 handleReportSplit 里面处理,更新 cache 相关的信息,并持久化到 etcd。 路由 因为 PD 保存了所有 TiKV 的集群信息,自然对 client 提供了路由的功能。假设 client 要对 key 写入一个值。 client 先从 PD 获取 key 属于哪一个 region,PD 将这个 region 相关的元信息返回。 client 自己 cache,这样就不需要每次都从 PD 获取。然后直接给 region 的 leader peer 发送命令。 有可能 region 的 leader 已经漂移到其他 peer,TiKV 会返回 NotLeader 错误,并带上新的 leader 的地址,client 在 cache 里面更新,并重新向新的 leader 发送请求。 也有可能 region 的 version 已经变化,譬如 split 了,这时候,key 可能已经落入了新的 region 上面,client 会收到 StaleCommand 的错误,于是重新从 PD 获取,进入状态 1。 小结 PD 作为 TiDB 集群的中心调度模块,在设计上面,我们尽量保证无状态,方便扩展。本篇文章主要介绍了 PD 是如何跟 TiKV,TiDB 协作交互的。后面,我们会详细地介绍核心调度功能,也就是 PD 是如何控制整个集群的。"}, {"url": "https://pingcap.com/weekly/2017-01-08-tidb-weekly/", "title": "Weekly update (January 02 ~ January 08, 2017)", "content": " Weekly update in TiDB Last week, we landed 38 PRs in the TiDB repositories.Added Add nested loop join. Support the UNIX_TIMESTAMP built-in function. Support the INTERVAL built-in function. Support the FIND_IN_SET built-in function. Support the DATEDIFF built-in function. Enable pushing down IF expr to TiKV coprocessor Fixed In prepared statement, limit and offset could be parameter marker. When creating table, index option could be a list. Fix a bug in creating table, some field length is missing. Fix a bug about parsing datetime overflow. Trim leading zeros before parsing int literal. Fix float truncate bug. Improved Improve TiDB schema lease checker. Speed up alter table add index statement. Refactor system variable related code. Refactor built-in function, add function class and function signature: #2361, #2384, #2385, #2389, #2391, #2399, #2410 Add unique key information into plan’s schema, this will be used for plan optimizing. Fetch tso and compiling statement concurrently: reduce the latency of small transaction. Load data in a batch way: make it easier for loading large data. Extract a built-in function factory for date arithmetic operations. New contributor idlesummerbreeze Weekly update in TiKV Last week, We landed 15 PRs in the TiKV repositories.Added Support pre vote feature for raft. Schedule replicas according to the location of the stores. Coprocessor support if, IsNull, IfNull and NullIf. Fixed Check cluseter ID to avoid PD joining different cluster. Improved Return StoreNotMatch error when store ID doesn’t match. Use upper bound for scanner. Unify logger to make the log format the same with TiDB/PD. "}, {"url": "https://pingcap.com/meetup/meetup-2017-01-07/", "title": "COISF 专场|PingCAP 第 36 期 NewSQL Meetup", "content": " COISF 专场|PingCAP 第 36 期 NewSQL Meetup 2017-01-07 蔡杰明&袁进辉 PingCAP PingCAPPingCAP ![]() 微信号pingcap2015功能介绍PingCAP 专注于新型"}, {"url": "https://pingcap.com/blog/2017-01-06-about-the-tidb-source-code/", "title": "About the TiDB Source Code", "content": " The target audience of this document is the contributors in the TiDB community. The document aims to help them understand the TiDB project. It covers the system architecture, the code structure, and the execution process.Table of content System architecture Overview of the code structure The protocol layer The SQL layer The optimizer The executor The distributed executor System architecture As is shown in the architecture diagram, the TiDB Server is between the Load Balancer (or Application) and the storage engine layer at the bottom. Within the TiDB server, there are three layers: The MySQL Protocol layer This layer has two functions: At the beginning, it receives the requests from the MySQL client, parses the MySQL Protocol packages to the corresponding commands in TiDB Session. In the end, it transfers the result to the MySQL protocol format and returns it to the Client. The SQL layer This layer has the following functions: Parse and execute the SQL statement Make and optimize the query plans Generate the optimizer Access data through the Storage Engine API layer Return the result to the MySQL Protocol layer This layer is very important and see The SQL layer for further information. The Storage Engine API layer This layer provides transactional (distributed or standalone) storage. There is an abstraction layer between the KV layer and the SQL layer and it enables the SQL layer to see the unified interface and ignore the differences among the KV storage engines. Overview of the code structure See the following list for all the packages and their main functions: tidbThis package can be considered to be the interface between the MySQL Protocol Layer and the SQL layer. There are three main files: session.go: Each session object corresponds to a connection of the MySQL client. The MySQL protocol layer manages the binding between the connection and the session. All the MySQL queries/commands are executed by calling the Session interface. tidb.go: This file includes some functions to be called by session.go. bootstrap.go: If a TiDB Server is started but the system is not yet initialized, the bootstrap.go file will initiate the system. See the following section for the detailed information. docs This package contains some brief documents of TiDB. See Documents for all the detailed documents. executorThis is the TiDB executor. A SQL statement will be transferred to the combination a series of executors (operators). The main interface exposed in this package is Executor: type Executor interface { // Returns the next row of data (If the result is empty, then there is no more data) Next() (*Row, error) // Close the current Executor and clean up Close() error //Change the result Schema from the executor, including the details of each Field Schema() expression.Schema } All kinds of executors implement this interface. The executing engine in TiDB adopts the Volcano model where the executors interact with each other through the above 3 interfaces. Each executor only needs to access the data through the Next interface and the meta data through the Schema interface. planThis is the core of the entire SQL layer. After a SQL statement is parsed to an abstract syntax tree (AST), the query plan is generated and optimized (including logical optimization and physical optimization) in this package.The following functions are also included in this package: validator.go: Validates the AST. preprocess.go: Currently, there is only name resolve. resolver.go`: Parses the name. To parse and bind the identifier of database/table/column/alias to the corresponding column or Field. typeinferer.go: Infers the type of the result. For SQL statements, the type of the result does not need inference. logical_plan_builder.go: Makes optimized logical query plans. physical_plan_builder.go: Makes the physical query plans based on the logical plans. privilegeThe authority control related interface which is implemented in the privilege/privileges directory. sessionctxStores the state information in the session, such as the session variables. The information can be obtained from the session. It is included in a separate directory for clear dependency and to avoid the problems of circular dependencies. tableThe table interface which is a layer of abstraction of the tables in the database. It provides many operations to the table such as getting the information of the column or reading a row of data. The implementation is in the table/tables directory.The directory also includes the abstraction of Column and Index. tidb-serverThe main.go file of the TiDB Server which is mainly the codes to start the server. serverThe implementation of the MySQL Protocol which is to parse the protocol and to pass the command/query. astThe SQL statement will be parsed to be an abstract syntax tree. The data structure is defined in the ast directory. Each node must implement the visitor interface and call the Accept method in the node to traverse the tree.If new syntax support is needed, besides adding the rule to parser, you also need to add the data structure to this directory. ddlThe related codes for asynchronous schema changes which is similar to the implementation in Google F1. domaindomain can be considered as a storage space where databases and tables are created. Somewhat like Name Space, the databases with the same name can exist in different domains. Domains bind with the information schema detail. expressionThe definition of the expressions. See the following for the most important interface: type Expression interface { ..... } The following lists the expressions that implement the interface: Scalar Function: Scalar Function expressions Aggregate Function: Aggregate Function expressions Column: Column expressions Const: Constant expressions infoschemaThe implementation of InformationSchema which provides the details of the db/table/column. kvKey-Value related interface definition and some of the implementations, including Retriever / Mutator / Transaction / Snapshot / Storage / Iterator, etc. A unified abstraction of the underlying Key-Value storages. modelThe DDL / DML related data structure supported by TiDB, including DBInfo / TableInfo / ColumnInfo / IndexInfo, etc. parserThe syntax parsing module, including lexical analysis (lexer.go) and syntax analysis (parser.y). The main interface to the external is Parse () which is to parse the SQL text into AST. storeThe implementation of the Key-Value store at the bottom. If you want to plug in a new storage engines, you can package the storage engine and put the code in this package. The new storage engine needs to implement the interface defined in the kv package.Currently, there are two storage engines: TiKV, a distributed storage engine, and localstore/{goleveldb/boltdb}, a stand-alone storage engine.For more information about the KV and store, see How to Plug in a New Storage Engine (Currently in Chinese). terrorThe error system for TiDB. For more information, see Detailed specification (Currently in Chinese). contextThe context interface. Session is the implementation of the context interface. The reason that we have an interface is to avoid the circular dependencies. All the state information of session can be accessed using this interface. inspectkvThe auxiliary check package for TiDB SQL data and Key-Value storage. In the future, it will be used to access TiKV from the external and will be re-defined and developed. metaThe definition of the metadata related constants and common functions for TiDB. In meta/autoid, an API is defined for ID auto-increment within a globally unique session. The meta information depends on this tool. mysqlMySQL related constant definitions. structureA layer of encapsulation on top of Key-Value which supports rich Key-Value types, such as string, list, hash, etc. The package is mainly used in asynchronous Schema changes. utilSome utility classes. The 7 package is very important because it contains the …"}, {"url": "https://pingcap.com/blog-cn/the-design-and-implementation-of-multi-raft/", "title": "TiKV 源码解析系列 - multi-raft 设计与实现", "content": " 概述 本文档主要面向 TiKV 社区开发者,主要介绍 TiKV 的系统架构,源码结构,流程解析。目的是使得开发者阅读文档之后,能对 TiKV 项目有一个初步了解,更好的参与进入 TiKV 的开发中。需要注意,TiKV 使用 Rust 语言编写,用户需要对 Rust 语言有一个大概的了解。另外,本文档并不会涉及到 TiKV 中心控制服务 Placement Driver(PD) 的详细介绍,但是会说明一些重要流程 TiKV 是如何与 PD 交互的。TiKV 是一个分布式的 KV 系统,它采用 Raft 协议保证数据的强一致性,同时使用 MVCC + 2PC 的方式实现了分布式事务的支持。架构 TiKV 的整体架构比较简单,如下:Placement Driver : Placement Driver (PD) 负责整个集群的管理调度。Node : Node 可以认为是一个实际的物理机器,每个 Node 负责一个或者多个 Store。Store : Store 使用 RocksDB 进行实际的数据存储,通常一个 Store 对应一块硬盘。Region : Region 是数据移动的最小单元,对应的是 Store 里面一块实际的数据区间。每个 Region 会有多个副本(replica),每个副本位于不同的 Store ,而这些副本组成了一个 Raft group。Raft TiKV 使用 Raft 算法实现了分布式环境下面数据的强一致性,关于 Raft,可以参考论文 “In Search of an Understandable Consensus Algorithm” 以及官网,这里不做详细的解释。简单理解,Raft 是一个 replication log + State Machine 的模型,我们只能通过 leader 进行写入,leader 会将 command 通过 log 的形式复制到 followers,当集群的大多数节点都收到了这个 log,我们就认为这个 log 是 committed,可以 apply 到 State Machine 里面。TiKV 的 Raft 主要移植 etcd Raft,支持 Raft 所有功能,包括: Leader election Log replicationLog compaction Membership changesLeader transfer Linearizable / Lease read 这里需要注意,TiKV 以及 etcd 对于 membership change 的处理,跟 Raft 论文是稍微有一点不一样的,主要在于 TiKV 的 membership change 只有在 log applied 的时候生效,这样主要的目的是为了实现简单,但有一个风险在于如果我们只有两个节点,要从里面移掉一个节点,如果一个 follower 还没收到 ConfChange 的 log entry,leader 就当掉并且不可恢复了,整个集群就没法工作了。所以通常我们都建议用户部署 3 个或者更多个奇数个节点。Raft 库是一个独立的库,用户也可以非常方便的将其直接嵌入到自己的应用程序,而仅仅只需要自行处理存储以及消息的发送。这里简单介绍一下如何使用 Raft,代码在 TiKV 源码目录的 /src/raft 下面。Storage 首先,我们需要定义自己的 Storage,Storage 主要用来存储 Raft 相关数据,trait 定义如下:pub trait Storage { fn initial_state(&self) -> Result<RaftState>; fn entries(&self, low: u64, high: u64, max_size: u64) -> Result<Vec<Entry>>; fn term(&self, idx: u64) -> Result<u64>; fn first_index(&self) -> Result<u64>; fn last_index(&self) -> Result<u64>; fn snapshot(&self) -> Result<Snapshot>; } 我们需要实现自己的 Storage trait,这里详细解释一下各个接口的含义:initial_state:初始化 Raft Storage 的时候调用,它会返回一个 RaftState,RaftState 的定义如下:pub struct RaftState { pub hard_state: HardState, pub conf_state: ConfState, } HardState 和 ConfState 是 protobuf,定义:message HardState { optional uint64 term = 1; optional uint64 vote = 2; optional uint64 commit = 3; } message ConfState { repeated uint64 nodes = 1; } 在 HardState 里面,保存着该 Raft 节点最后一次保存的 term 信息,之前 vote 的哪一个节点,以及已经 commit 的 log index。而 ConfState 则是保存着 Raft 集群所有的节点 ID 信息。在外面调用 Raft 相关逻辑的时候,用户需要自己处理 RaftState 的持久化。entries: 得到 [low, high) 区间的 Raft log entry,通过 max_size 来控制最多返回多少个 entires。term,first_index 和 last_index 分别是得到当前的 term,以及最小和最后的 log index。snapshot:得到当前的 Storage 的一个 snapshot,有时候,当前的 Storage 数据量已经比较大,生成 snapshot 会比较耗时,所以我们可能得在另一个线程异步去生成,而不用阻塞当前 Raft 线程,这时候,可以返回 SnapshotTemporarilyUnavailable 错误,这时候,Raft 就知道正在准备 snapshot,会一段时间之后再次尝试。需要注意,上面的 Storage 接口只是 Raft 库需要的,实际我们还会用这个 Storage 存储 raft log 等数据,所以还需要单独提供其他的接口。在 Raft storage.rs 里面,我们提供了一个 MemStorage,用于测试,大家也可以参考 MemStorage 来实现自己的 Storage。Config 在使用 Raft 之前,我们需要知道 Raft 一些相关的配置,在 Config 里面定义,这里只列出需要注意的:pub struct Config { pub id: u64, pub election_tick: usize, pub heartbeat_tick: usize, pub applied: u64, pub max_size_per_msg: u64, pub max_inflight_msgs: usize, } id: Raft 节点的唯一标识,在一个 Raft 集群里面,id 是不可能重复的。在 TiKV 里面,id 的通过 PD 来保证全局唯一。election_tick:当 follower 在 election_tick 的时间之后还没有收到 leader 发过来的消息,那么就会重新开始选举,TiKV 默认使用 50。heartbeat_tick: leader 每隔 hearbeat_tick 的时间,都会给 follower 发送心跳消息。默认 10。applied: applied 是上一次已经被 applied 的 log index。max_size_per_msg: 限制每次发送的最大 message size。默认 1MB。max_inflight_msgs: 限制复制时候最大的 in-flight 的 message 的数量。默认 256。这里详细解释一下 tick 的含义,TiKV 的 Raft 是定时驱动的,假设我们每隔 100ms 调用一次 Raft tick,那么当调用到 headtbeat_tick 的 tick 次数之后,leader 就会给 follower 发送心跳。RawNode 我们通过 RawNode 来使用 Raft,RawNode 的构造函数如下:pub fn new(config: &Config, store: T, peers: &[Peer]) -> Result<RawNode<T>> 我们需要定义 Raft 的 Config,然后传入一个实现好的 Storage,peers 这个参数只是用于测试,实际要传空。生成好 RawNode 对象之后,我们就可以使用 Raft 了。我们关注如下几个函数:tick: 我们使用 tick 函数定期驱动 Raft,在 TiKV,我们每隔 100ms 调用一次 tick。propose: leader 通过 propose 命令将 client 发过来的 command 写入到 raft log,并复制给其他节点。propose_conf_change: 跟 propose 类似,只是单独用来处理 ConfChange 命令。step: 当节点收到其他节点发过来的 message,主动调用驱动 Raft。has_ready: 用来判断一个节点是不是 ready 了。ready: 得到当前节点的 ready 状态,我们会在之前用 has_ready 来判断一个 RawNode 是否 ready。apply_conf_change: 当一个 ConfChange 的 log 被成功 applied,需要主动调用这个驱动 Raft。advance: 告诉 Raft 已经处理完 ready,开始后续的迭代。对于 RawNode,我们这里重点关注下 ready 的概念,ready 的定义如下:pub struct Ready { pub ss: Option<SoftState>, pub hs: Option<HardState>, pub entries: Vec<Entry>, pub snapshot: Snapshot, pub committed_entries: Vec<Entry>, pub messages: Vec<Message>, } ss: 如果 SoftState 变更,譬如添加,删除节点,ss 就不会为空。hs: 如果 HardState 有变更,譬如重新 vote,term 增加,hs 就不会为空。entries: 需要在 messages 发送之前存储到 Storage。snapshot: 如果 snapshot 不是 empty,则需要存储到 Storage。committed_entries: 已经被 committed 的 raft log,可以 apply 到 State Machine 了。messages: 给其他节点发送的消息,通常需要在 entries 保存成功之后才能发送,但对于 leader 来说,可以先发送 messages,在进行 entries 的保存,这个是 Raft 论文里面提到的一个优化方式,TiKV 也采用了。当外部发现一个 RawNode 已经 ready 之后,得到 Ready,处理如下: 持久化非空的 ss 以及 hs。 如果是 leader,首先发送 messages。 如果 snapshot 不为空,保存 snapshot 到 Storage,同时将 snapshot 里面的数据异步应用到 State Machine(这里虽然也可以同步 apply,但 snapshot 通常比较大,同步会 block 线程)。 将 entries 保存到 Storage 里面。 如果是 follower,发送 messages。 将 committed_entries apply 到 State Machine。 调用 advance 告知 Raft 已经处理完 ready。 Placement Driver 在继续之前,我们先简单介绍一下 Placement Driver(PD)。PD 是 TiKV 的全局中央控制器,存储整个 TiKV 集群的元数据信息,负责整个 TiKV 集群的调度,全局 ID 的生成,以及全局 TSO 授时等。PD 是一个非常重要的中心节点,它通过集成 etcd,自动的支持了分布式扩展以及 failover,解决了单点故障问题。关于 PD 的详细介绍,后续我们会新开一篇文章说明。在 TiKV 里面,跟 PD 的交互是放在源码的 pd 目录下,现在跟 PD 的交互都是通过自己定义的 RPC 实现,协议非常简单,在 pd/mod.rs 里面我们直接提供了用于跟 PD 进行交互的 Client trait,以及实现了 RPC Client。PD 的 Client trait 非常简单,多数都是对集群元信息的 set/get 操作,需要额外注意的几个:bootstrap_cluster:当我们启动一个 TiKV 服务的时候,首先需要通过 is_cluster_bootstrapped 来判断整个 TiKV 集群是否已经初始化,如果还没有初始化,我们就会在该 TiKV 服务上面创建第一个 region。region_heartbeat:定期 Region 向 PD 汇报自己的相关信息,供 PD 做后续的调度。譬如,如果一个 Region 给 PD 上报的 peers 的数量小于预设的副本数,那么 PD 就会给这个 Region 添加一个新的副本 Peer。store_heartbeat:定期 store 向 PD 汇报自己的相关信息,供 PD 做后续调度。譬如,Store 会告诉 PD 当前的磁盘大小,以及剩余空间,如果 PD 发现空间不够了,就不会考虑将其他的 Peer 迁移到这个 Store 上面。ask_split/report_split:当 Region 发现自己需要 split 的时候,就 ask_split 告诉 PD,PD 会生成新分裂 Region 的 ID ,当 Region 分裂成功之后,会 report_split 通知 PD。注意,后面我们会让 PD 支持 gRPC 协议,所以 Client API 到时候可能会有变更。Raftstore 因为 TiKV 目标是支持 100 TB+ 以上的数据,一个 Raft 集群是铁定没法支持这么多数据的,所以我们需要使用多个 Raft 集群,也就是 Multi Raft。在 TiKV 里面,Multi Raft 的实现是在 Raftstore 完成的,代码在 raftstore/store 目录。Region 因为我们要支持 Multi Raft,所以我们需要将数据进行分片处理,让每个 Raft 单独负责一部分数据。通常的数据分片算法就是 Hash 和 Range,TiKV 使用的 Range 来对数据进行数据分片。为什么使用 Range,主要原因是能更好的将相同前缀的 key 聚合在一起,便于 scan 等操作,这个 Hash 是没法支持的,当然,在 split/merge 上面 Range 也比 Hash 好处理很多,很多时候只会涉及到元信息的修改,都不用大范围的挪动数据。当然,Range 有一个问题在于很有可能某一个 Region 会因为频繁的操作成为性能热点,当然也有一些优化的方式,譬如通过 PD 将这些 Region 调度到更好的机器上面,提供 Follower 分担读压力等。总之,在 TiKV 里面,我们使用 Range 来对数据进行切分,将其分成一个一个的 Raft Group,每一个 Raft Group,我们使用 Region 来表示。Region 的 protobuf 协议定义如下:message Region { optional uint64 id = 1 [(gogoproto.nullable) = false]; optional bytes start_key = 2; optional bytes end_key = 3; optional RegionEpoch region_epoch = 4; repeated Peer peers = 5; } message RegionEpoch { optional uint64 conf_ver = 1 [(gogoproto.nullable) = false]; optional uint64 version = 2 [(gogoproto.nullable) = false]; } message Peer { optional uint64 id = 1 [(gogoproto.nullable) = false]; optional uint64 store_id = 2 [(gogoproto.nullable) = false]; } id:Region 的唯一表示,通过 PD 全局唯一分配。start_key, end_key:用来表示这个 Region 的范围 [start_key, end_key),对于最开始的 region,start 和 end key 都是空,TiKV 内部会特殊处理。region_epoch:当一个 Region 添加或者删除 Peer,或者 split 等,我们就会认为这个 Region 的 epoch 发生的变化,RegionEpoch 的 conf_ver 会在每次做 ConfChange 的时候递增,而 version 则是会在每次做 split/merge 的时候递增。peers:当前 Region 包含的节点信息。对于一个 Raft Group,我们通常有三个副本,每个副本我们使用 Peer 来表示,Peer 的 id 也是全局由 PD 分配,而 store_id 则表明这个 Peer 在哪一个 Store 上面。RocksDB / Keys Prefix 对于实际数据存储,无论是 Raft Meta,Log,还是 State Machine 的 data,我们都存到一个 RocksDB 实例里面。关于 RocksDB,可以详细参考 facebook/rocksdb。我们使用不同的前缀来对 Raft 以及 State Machine 等数据进行区分,具体可以参考 raftstore/store/keys.rs,对于 State Machine 实际的 data 数据,我们统一添加 ‘z’ 前缀。而对于其他会存在本地的元数 …"}, {"url": "https://pingcap.com/weekly/2017-01-01-tidb-weekly/", "title": "Weekly update (December 26 ~ January 01, 2017)", "content": " Weekly update in TiDB Last week, we landed 28 PRs in the TiDB repositories.Added Support the CHAR_LENGTH built-in function. Support the CRC32 built-in function. Support the LEAST built-in function. Fixed Fix a bug in Add Column with invalid default value. Fix a bug about parsing string to float. Fix a bug when using int and uint as join key. Fix a bug in MySQL Protocol layer about prepared statement. Improved Improve string to date parser. Improve TiDB schema lease checker. Refactor optimizer: #2321, #2322 Set a limitation on the quantity of the data in a single transaction. Improve mocked tikv: Split data in a table into multiple mocked regions. This will used in unit tests. Speed up creating table: In some cases, it is not necessary to wait a long time to create table. Use MySQL standard error code when meeting incorrect function argument count error. Find a better way to handle StoreNotMatch error. Refactor built-in function: #2343, #2344, #2362, #2367 Clean up tidb-server codes: #2356, #2358 New contributor Zyguan AndreMouche Weekly update in TiKV Last week, We landed 19 PRs in the TiKV repositories.Added Move raw_get to thread pool. Add ResourceKind for operator and don’t resend duplicated AddPeer response when the peer is still pending, see #449. Add member command for pd-ctl. Fixed Fix getting valid float. Improved Update default configuration to speed up scheduler. Don’t panic when receiving stale snapshot. Remove unnecessary region cache. Remove no used constraint feature. Exit with error message if clusert ID mismatches directly. Add replication section in configuration. "}, {"url": "https://pingcap.com/blog-cn/tikv-how-to-use-raft/", "title": "TiKV 源码解析系列 - 如何使用 Raft", "content": " 本系列文章主要面向 TiKV 社区开发者,重点介绍 TiKV 的系统架构,源码结构,流程解析。目的是使得开发者阅读之后,能对 TiKV 项目有一个初步了解,更好的参与进入 TiKV 的开发中。需要注意,TiKV 使用 Rust 语言编写,用户需要对 Rust 语言有一个大概的了解。另外,本系列文章并不会涉及到 TiKV 中心控制服务 Placement Driver(PD) 的详细介绍,但是会说明一些重要流程 TiKV 是如何与 PD 交互的。TiKV 是一个分布式的 KV 系统,它采用 Raft 协议保证数据的强一致性,同时使用 MVCC + 2PC 的方式实现了分布式事务的支持。 架构 TiKV 的整体架构比较简单,如下:Placement Driver : Placement Driver (PD) 负责整个集群的管理调度。 Node : Node 可以认为是一个实际的物理机器,每个 Node 负责一个或者多个 Store。 Store : Store 使用 RocksDB 进行实际的数据存储,通常一个 Store 对应一块硬盘。 Region : Region 是数据移动的最小单元,对应的是 Store 里面一块实际的数据区间。每个 Region会有多个副本(replica),每个副本位于不同的 Store ,而这些副本组成了一个 Raft group。Raft TiKV 使用 Raft 算法实现了分布式环境下面数据的强一致性,关于 Raft,可以参考论文 “In Search of an Understandable Consensus Algorithm” 以及官网,这里不做详细的解释。简单理解,Raft 是一个 replication log + State Machine 的模型,我们只能通过 leader 进行写入,leader 会将 command 通过 log 的形式复制到 followers,当集群的大多数节点都收到了这个 log,我们就认为这个 log 是 committed,可以 apply 到 State Machine 里面。TiKV 的 Raft 主要移植 etcd Raft,支持 Raft 所有功能,包括: Leader election Log replicationLog compaction Membership changesLeader transfer Linearizable / Lease read 这里需要注意,TiKV 以及 etcd 对于 membership change 的处理,跟 Raft 论文是稍微有一点不一样的,主要在于 TiKV 的 membership change 只有在 log applied 的时候生效,这样主要的目的是为了实现简单,但有一个风险在于如果我们只有两个节点,要从里面移掉一个节点,如果一个 follower 还没收到 ConfChange 的 log entry,leader 就当掉并且不可恢复了,整个集群就没法工作了。所以通常我们都建议用户部署 3 个或者更多个奇数个节点。Raft 库是一个独立的库,用户也可以非常方便的将其直接嵌入到自己的应用程序,而仅仅只需要自行处理存储以及消息的发送。这里简单介绍一下如何使用 Raft,代码在 TiKV 源码目录的 /src/raft 下面。Storage 首先,我们需要定义自己的 Storage,Storage 主要用来存储 Raft 相关数据,trait 定义如下:我们需要实现自己的 Storage trait,这里详细解释一下各个接口的含义:initial_state:初始化 Raft Storage 的时候调用,它会返回一个 RaftState,RaftState 的定义如下:HardState 和 ConfState 是 protobuf,定义:在 HardState 里面,保存着该 Raft 节点最后一次保存的 term 信息,之前 vote 的哪一个节点,以及已经 commit 的 log index。而 ConfState 则是保存着 Raft 集群所有的节点 ID 信息。在外面调用 Raft 相关逻辑的时候,用户需要自己处理 RaftState 的持久化。entries: 得到 [low, high) 区间的 Raft log entry,通过 max_size 来控制最多返回多少个 entires。term,first_index 和 last_index 分别是得到当前的 term,以及最小和最后的 log index。snapshot:得到当前的 Storage 的一个 snapshot,有时候,当前的 Storage 数据量已经比较大,生成 snapshot 会比较耗时,所以我们可能得在另一个线程异步去生成,而不用阻塞当前 Raft 线程,这时候,可以返回 SnapshotTemporarilyUnavailable 错误,这时候,Raft 就知道正在准备 snapshot,会一段时间之后再次尝试。需要注意,上面的 Storage 接口只是 Raft 库需要的,实际我们还会用这个 Storage 存储 raft log 等数据,所以还需要单独提供其他的接口。在 Raft storage.rs 里面,我们提供了一个 MemStorage,用于测试,大家也可以参考 MemStorage 来实现自己的 Storage。Config 在使用 Raft 之前,我们需要知道 Raft 一些相关的配置,在 Config 里面定义,这里只列出需要注意的:id: Raft 节点的唯一标识,在一个 Raft 集群里面,id 是不可能重复的。在 TiKV 里面,id 的通过 PD 来保证全局唯一。election_tick:当 follower 在 election_tick 的时间之后还没有收到 leader 发过来的消息,那么就会重新开始选举,TiKV 默认使用 50。heartbeat_tick: leader 每隔 hearbeat_tick 的时间,都会给 follower 发送心跳消息。默认 10。applied: applied 是上一次已经被 applied 的 log index。max_size_per_msg: 限制每次发送的最大 message size。默认 1MB。max_inflight_msgs: 限制复制时候最大的 in-flight 的 message 的数量。默认 256。这里详细解释一下 tick 的含义,TiKV 的 Raft 是定时驱动的,假设我们每隔 100ms 调用一次 Raft tick,那么当调用到 headtbeat_tick 的 tick 次数之后,leader 就会给 follower 发送心跳。RawNode 我们通过 RawNode 来使用 Raft,RawNode 的构造函数如下:我们需要定义 Raft 的 Config,然后传入一个实现好的 Storage,peers 这个参数只是用于测试,实际要传空。生成好 RawNode 对象之后,我们就可以使用 Raft 了。我们关注如下几个函数:tick: 我们使用 tick 函数定期驱动 Raft,在 TiKV,我们每隔 100ms 调用一次 tick。propose: leader 通过 propose 命令将 client 发过来的 command 写入到 raft log,并复制给其他节点。propose_conf_change: 跟 propose 类似,只是单独用来处理 ConfChange 命令。step: 当节点收到其他节点发过来的 message,主动调用驱动 Raft。has_ready: 用来判断一个节点是不是 ready 了。ready: 得到当前节点的 ready 状态,我们会在之前用 has_ready 来判断一个 RawNode 是否 ready。apply_conf_change: 当一个 ConfChange 的 log 被成功applied,需要主动调用这个驱动 Raft。advance: 告诉 Raft 已经处理完 ready,开始后续的迭代。对于 RawNode,我们这里重点关注下 ready 的概念,ready 的定义如下:ss: 如果 SoftState 变更,譬如添加,删除节点,ss 就不会为空。hs: 如果 HardState 有变更,譬如重新 vote,term 增加,hs 就不会为空。entries: 需要在 messages 发送之前存储到 Storage。snapshot: 如果 snapshot 不是 empty,则需要存储到 Storage。committed_entries: 已经被 committed 的 raft log,可以 apply 到 State Machine 了。messages: 给其他节点发送的消息,通常需要在 entries 保存成功之后才能发送,但对于 leader 来说,可以先发送 messages,在进行 entries 的保存,这个是 Raft 论文里面提到的一个优化方式,TiKV 也采用了。当外部发现一个 RawNode 已经 ready 之后,得到 Ready,处理如下: 持久化非空的 ss 以及 hs。 如果是 leader,首先发送 messages。 如果 snapshot 不为空,保存 snapshot 到 Storage,同时将 snapshot 里面的数据异步应用到 State Machine(这里虽然也可以同步 apply,但 snapshot 通常比较大,同步会 block 线程)。 将 entries 保存到 Storage 里面。 如果是 follower,发送 messages。 将 committed_entries apply 到 State Machine。 调用 advance 告知 Raft 已经处理完 ready。 #####-第一部分完结-"}, {"url": "https://pingcap.com/weekly/2016-12-26-tidb-weekly/", "title": "Weekly update (December 19 ~ December 25, 2016)", "content": " New Release TiDB RC1 is released!Weekly update in TiDB Last week, we landed 34 PRs in the TiDB repositories.Added Support the RPAD built-in function.. Support the show keys from table from database statement. Fixed Retry infinite times if the commit primary key times out. Do not push aggregation down to the memory tables. Fix a bug about the alter table statement. Improved Refactor the time type related code: #2259, #2280, #2284, #2289, #2292 Refactor optimizer: extract initialization related code into physical Initialization. Speed up the DDL statement. Avoid generating parser.go every time. Skip the constraint check for prewrite to improve the loading data speed. Speed up the add index statement. New contributor silentred Weekly update in TiKV Last week, We landed 14 PRs in the TiKV repositories.Added Add configuration to control the replica scheduling speed. Skip constraint check for prewrite to improve the loading data speed. Add region and store commands to pd-ctl. Add configuration to cache index and filter blocks in the block cache. Fixed Report snapshot sending status reliably to fix #1377. Store short value in write cf directly to save space and improve performance. Improved Remove unnecessary admin operators. Handle Raft ready append login one WriteBatch to reduce the CPU usage and improve performance. Remove the down peer first when scheduling replicas. "}, {"url": "https://pingcap.com/meetup/meetup-2016-12-24/", "title": "COISF 专场|PingCAP 第 35 期 NewSQL Meetup", "content": " COISF 专场|PingCAP 第 35 期 NewSQL Meetup 2016-12-24 张頔&黄梦龙 PingCAP PingCAPPingCAP ![]() 微信号pingcap2015功能介绍PingCAP 专注于新型"}, {"url": "https://pingcap.com/blog/2016-12-19-adding-built-in-function/", "title": "Adding Built-in Functions", "content": " This document describes how to add built-in functions to TiDB. Background The procedure to add a built-in function Example Background How is the SQL statement executed in TiDB?The SQL statement is parsed to an abstract syntax tree (AST) by the parser first and then uses Query Optimizer to generate an execution plan. The plan can then be executed to get the result. This process involves how to access the data in the table, and how to filter, calculate, sort, aggregate, and distinct the data, etc. For a built-in function, the most important part is to parse and to evaluate.For parsing, it is redundant work because you should know how to write YACC commands and how to modify TiDB syntax parser. But we have finished this work for you and syntax parsing of most built-in functions is done.As for evaluation, it should be finished in the TiDB expression evaluation framework. Each built-in function is considered as an expression indicated by ScalarFunction and obtains the corresponding function type and function signature through the function name and parameters to evaluate.The procedure discussed above is complicated for users who are not familiar with TiDB. We have finished syntax parsing and function signature confirmation of most unimplemented functions. But implementation is left empty. In other words, locating and completing the empty implementation makes a Pull Request (PR).The procedure to add a built-in function The following procedure describes how to add a built-in function. Locate the unimplemented function. Search for errFunctionNotExists in the expression directory of TiDB source code. You can find all the unimplemented functions. Choose a function you are interested in. Take the SHA2 function as an example:func (b *builtinSHA2Sig) eval(row []types.Datum) (d types.Datum, err error) { return d, errFunctionNotExists.GenByArgs("SHA2") } Implement the function signature.This step is to implement eval. For the function features, see MySQL documentation. For the specific implementation method, see the method of implemented functions. Add the type inference information to the typeinferer file.Add the type of the returned result of the function to handleFuncCallExpr() in the the plan/typeinferer.go file and make sure the result is consistent with the result in MySQL. See MySQL Const for the complete list of the type definition.Note: For most fuctions, you need to input the type of the returned result and obtain the length of the returned result. Add a unit test case.Add a unit test case for the function to the expression directory. Add a unit test case of typeinferer to the plan/typeinferer_test.go file. Run the make dev command and make sure all the test cases can pass. Example Take the Pull Request to add the SHA1() function as an example: Open the expression/builtin_encryption.go file and complete the evaluation of SHA1().func (b *builtinSHA1Sig) eval(row []types.Datum) (d types.Datum, err error) { // Evaluate the arguments. In most cases, you do not need to make any modification. args, err := b.evalArgs(row) if err != nil { return types.Datum{}, errors.Trace(err) } // See MySQL documentation for the meaning of each argument. // SHA/SHA1 function only accept 1 parameter arg := args[0] if arg.IsNull() { return d, nil } // The type of the argument value is changed. See "util/types/datum.go" for the function implementation. bin, err := arg.ToBytes() if err != nil { return d, errors.Trace(err) } hasher := sha1.New() hasher.Write(bin) data := fmt.Sprintf("%x", hasher.Sum(nil)) // Set the return value. d.SetString(data) return d, nil } Add a unit test case for the function implementation. See expression/builtin_encryption_test.go:var shaCases = []struct { origin interface{} crypt string }{ {"test", "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3"}, {"c4pt0r", "034923dcabf099fc4c8917c0ab91ffcd4c2578a6"}, {"pingcap", "73bf9ef43a44f42e2ea2894d62f0917af149a006"}, {"foobar", "8843d7f92416211de9ebb963ff4ce28125932878"}, {1024, "128351137a9c47206c4507dcf2e6fbeeca3a9079"}, {123.45, "22f8b438ad7e89300b51d88684f3f0b9fa1d7a32"}, } func (s *testEvaluatorSuite) TestShaEncrypt(c *C) { defer testleak.AfterTest(c)() // The tool for monitoring goroutine leak. You can just copy it. fc := funcs[ast.SHA] for _, test := range shaCases { in := types.NewDatum(test.origin) f, _ := fc.getFunction(datumsToConstants([]types.Datum{in}), s.ctx) crypt, err := f.eval(nil) c.Assert(err, IsNil) res, err := crypt.ToString() c.Assert(err, IsNil) c.Assert(res, Equals, test.crypt) } // test NULL input for sha var argNull types.Datum f, _ := fc.getFunction(datumsToConstants([]types.Datum{argNull}), s.ctx) crypt, err := f.eval(nil) c.Assert(err, IsNil) c.Assert(crypt.IsNull(), IsTrue) } Note: Besides conventional cases, you had better add some exceptional cases in which, for example, the input value is “nil” or the arguments of various types. Add the type inference information and the test case. See plan/typeinferer.go and plan/typeinferer_test.go:case ast.SHA, ast.SHA1: tp = types.NewFieldType(mysql.TypeVarString) chs = v.defaultCharset tp.Flen = 40{`sha1(123)`, mysql.TypeVarString, "utf8"}, {`sha(123)`, mysql.TypeVarString, "utf8"}, "}, {"url": "https://pingcap.com/weekly/2016-12-19-tidb-weekly/", "title": "Weekly update (December 12 ~ December 18, 2016)", "content": " Weekly update in TiDB Last week, we landed 32 PRs in the TiDB repositories.Added Add the FlagIgnoreTruncate/FlagTruncateAsWarning flag to control the behavior of truncated errors. Add the prompt text flag. Add the rawkv metrics to profile the rawkv API performance. Add a comparable varint encoding/decoding method to make encoded data smaller. Support the timediff built-in function. Support the following built-in functions: ln(), log(), log2(), log10(). Fixed A bug that ignores primary key’s unsigned attribute. A bug that ignores error in the distsql layer. Allow default value to be Null when the column has the auto_increament attribute to be compatible with MySQL 5.6. A bug in the insert statement that ignores error. Fix bugs in the cost-based optimization framework: #2243 Improved Refactor the time type related code: #2185, #2190, #2206, #2233, #2261 Remove the util/bytes package to clean up the code. Refactor the code to remove the evaluator.Eval() method: #2222, Improve test coverage for the util/segmentmap package. Recover from panics caused by malformated mysql packet to make tidb-server more robust. New contributor Bai Yang Weekly update in TiKV Last week, we landed 11 PRs in the TiKV repositories.Added Add a configuration to disable data sync to speed up loading data. Filter the pending peers for Placement Driver (PD) scheduler. Add pd-ctl to operate PD more easily. Fixed Update the advertise peer urls from etcd to fix #435. Improved Read and verify snapshot file in one step. Use a smaller interval to make Raft tick more accurate. Clean up the tombstone store to fix #401. Use delete_file_in_range when clean up the tombstone regions. "}, {"url": "https://pingcap.com/meetup/meetup-2016-12-17/", "title": "COISF 专场|PingCAP 第 34 期 NewSQL Meetup", "content": " COISF 专场|PingCAP 第 34 期 NewSQL Meetup 2016-12-17 覃左言&申砾 PingCAP PingCAPPingCAP ![]() 微信号pingcap2015功能介绍PingCAP 专注于新型"}, {"url": "https://pingcap.com/weekly/2016-12-12-tidb-weekly/", "title": "Weekly update (December 05 ~ December 11, 2016)", "content": " Weekly update in TiDB Last week, we landed 41 PRs in the TiDB repositories.Added Support the built-in function: str_to_date. Support built-in function schema(). Support pushing the case-when expression to TiKV. Support changing the type and name of a column. Add the `session_variablesandplugins` of memory table to infoschema. Make the union all operator run parallelly. Support explaining the union statement. Fixed A bug that causes infinite loop. A bug in the on duplicate… statement when updating the primary key (PK) Make the charset name case-insensitive. Forbid dropping columns with the auto_inc and PK attribute. Fix bugs in the parser. Improved Pass the filter to TiKV when scanning indexes. Allocate column/index IDs in the table space to make the IDs shorter. Weekly update in TiKV Last week, we landed 34 PRs in the TiKV repositories.Added Support online backup of the RocksDB data for tikv-ctl debugging. Add replication constraints to schedule replicas. Support GrantLeaderScheduler to transfer all leaders to one store. Support ShuffleLeaderScheduler to shuffle leaders in different stores. Support Circle CI for TiKV and Placement Driver (PD). Add the state filter argument to get the stores API. Fixed Use channel to fix the possible stale snapshot state, issue #1373. Report ServerIsBusy and let PD ignore the busy store when scheduling to fix #414. Improved Speed up the shutdown duration to reduce the close waiting time. Add retry when initializing the cluster ID. Support safe ConfChange to fix #1366. Report pending peers to PD to improve its scheduler. Bind ports lazily to avoid the message channel full error when starting up. "}, {"url": "https://pingcap.com/meetup/meetup-2016-12-10/", "title": "COISF 专场|PingCAP 第 33 期 NewSQL Meetup", "content": " COISF 专场|PingCAP 第 33 期 NewSQL Meetup 2016-12-10 王康&李康 PingCAP PingCAPPingCAP ![]() 微信号pingcap2015功能介绍PingCAP 专注于新型"}, {"url": "https://pingcap.com/blog/2016-12-07-Subquery-Optimization-in-TiDB/", "title": "Subquery Optimization in TiDB", "content": " MathJax.Hub.Config({ extensions: ["tex2jax.js"], jax: ["input/TeX", "output/HTML-CSS"], tex2jax: { inlineMath: [ ['$','$'], ["(",")"] ], displayMath: [ ['$$','$$'], ["[","]"] ], processEscapes: true }, "HTML-CSS": { availableFonts: ["TeX"] } }); Introduction to subqueries Subquery is a query within another SQL query. A common subquery is embedded within the FROM clause, for example:SELECT ID FROM (SELECT * FROM SRC) AS T The subexpressions in the FROM clauses can be processed very well by the general SQL optimizers. But when it comes to subqueries in the WHERE clause or the SELECT lists, it becomes very difficult to optimize because subqueries can be anywhere in the expression, e.g. in the CASE...WHEN... clauses.The subqueries that are not in the FROM clause are categorized as “correlated subquery” and “uncorrelated subquery”. Correlated subquery refers to a subquery with columns from outer references, for example:SELECT * FROM SRC WHERE EXISTS(SELECT * FROM TMP WHERE TMP.id = SRC.id) Uncorrelated subqueries can be pre-processed in the plan phase and be re-written to a constant. Therefore, this article is mainly focused on the optimization of correlated subqueries.Generally speaking, there are following three types of subqueries: Scalar Subquery like (SELECT...) + (SELECT...) Quantified Comparison like T.a = ANY(SELECT...) Existential Test like NOT EXISTS(SELECT...), T.a IN (SELECT...) For the simple subqueries like Existential Test, the common practice is to rewrite them to SemiJoin. But it is barely explored in the literature about the generic algorithm and what kind of subqueries need to remove the correlation. For those subqueries whose correlation cannot be removed, the common practice in databases is to execute in Nested Loop, which is called correlated execution.TiDB inherits the subquery strategy in SQL Server [1]. It introduces the Apply operator to use algebraic representation for subqueries which is called normalization, and then removes the correlation based on the cost information.The Apply operator The reason why subqueries are difficult to optimize is that a subquery cannot be represented as a logic operator like Projection or Join, which makes it difficult to find a generic algorithm for subquery transformation. So the first thing is to introduce a logical operation that can represent the subqueries: the Apply operator, which is also called d-Join[2]. The semantics of the Apply operator is:[ R A^{otimes} E = bigcuplimits_{rin R} ({r}otimes E®) ]where E represents a parameterized subquery. In every execution, the Apply operator gets an r record from the R relation and sends r to E as a parameter for the ⊗ operation of r and E(r). ⊗ is different based on different query types, usually it’s SemiJoin ∃.For the following SQL statement:SELECT * FROM SRC WHERE EXISTS(SELECT * FROM TMP WHERE TMP.id = SRC.id) the Apply operator representation is as follows:Because the operator above Apply is Selection, formally, it is:[ {SRC} A^exists sigma_{SRC.id=TMP.id}{TMP} ]For the EXISTS subquery in the SELECT list, and the data that cannot pass through the SRC.id=TMP.id equation, the output should be false. So OuterJoin should be used:[ pi_C({SRC} A^{LOJ} sigma_{SRC.id=TMP.id}{TMP}) ]The C Projection is to transform NULL to false. But the more common practice is: If the output of the Apply operator is directly used by the query predicate, it is converted to SemiJoin.Removing the correlation The introduction of the Apply operator enables us to remove the correlation of the subqueries. The two examples in the previous section can be transformed to:[ {SRC} exists_{sigma_{SRC.id = TMP.id}} {TMP} ]and[ {SRC} LOJ_{sigma_{SRC.id = TMP.id}} {TMP} ]Other rules to remove correlation can be formally represented as:(R A^{otimes} E= R {otimes}_{true} E), if no parameters in E resolved from R (1)(R A^{otimes} (sigma_pE) = R {otimes}_p E), if no parameters in E resolved from R (2)(R A^times (sigma_pE)=sigma_p(R A^times E) ) (3)(R A^times (pi_vE) = pi_{vbigcupmathrm{cols}®}(R A^times E) ) (4)(R A^times (E_1 bigcup E_2) = (R A^times E_1) bigcup (R A^times E_2) ) (5)(R A^times (E_1 - E_2) = (R A^times E_1) - (R A^times E_2) ) (6)(R A^times (E_1 times E_2) = (R A^times E_1) Join_{R.key} (R A^times E_2) ) (7)(R A^times (mathcal{G}_{A,F}E) = mathcal{G}_{Abigcup mathrm{attr}®,F} (R A^{times} E) ) (8)(R A^times (mathcal{G}^1_FE) = mathcal{G}_{Abigcup mathrm{attr}®,F’} (R A^{LOJ} E) ) (9)Based on the above rules, the correlation among all the SQL subqueries can be removed [3]. But the (5), (6), and (7) rules are seldom used because the the query cost is increased as a result of the rules about common expression. Take the following SQL statement as an example:SELECT C_CUSTKEY FROM CUSTOMER WHERE 1000000 < (SELECT SUM(O_TOTALPRICE) FROM ORDER WHERE O_CUSTKEY = C_CUSTKEY) The two “CUSTKEY”s are the primary keys. When the statement is transformed to Apply, it is represented as:[ sigma_{1000000<X}(CUSTOMER A^times mathcal{G}^1_{X=SUM(O_PRICE)}(sigma_{O_CUSTKEY=C_CUSTKEY}ORDERS)) ]Because of the primary keys, according to rule (9), it can be transformed to the following:[ sigma_{1000000<X} mathcal{G}_{C_CUSTKEY,X = SUM(O_PRICE)}(CUSTOMER A^{LOJ} sigma_{O_CUSTKEY=C_CUSTKEY}ORDERS) ]Note: If there are no primary keys in ORDERS, the (pi) operator should be added to allocate a unique key. Pay attention to the difference between rule (8) and rule (9). For the (mathcal{G}^1_F) aggregation function without the aggregation column, when the input is NULL, the output should be the default value of the F aggregation function. Therefore, the LeftOuterJoin should be used and a NULL record should be the output when the right table is NULL. In this case, based on rule (2), Apply can be completely removed. The statement can be transformed to a SQL statement with join: [ sigma_{1000000<X}mathcal{G}_{C_CUSTKEY,X=SUM(O_PRICE)}(CUSTOMER LOJ_{O_CUSTKEY=C_CUSTKEY}ORDERS) ]Furthermore, based on the simplification of OuterJoin, the statement can be simplified to:[ sigma_{1000000<X}mathcal{G}_{C_CUSTKEY,X=SUM(O_PRICE)}(CUSTOMER Join_{O_CUSTKEY=C_CUSTKEY}ORDERS) ]Theoretically, the above 9 rules have solved the correlation removal problem. But is correlation removal the best solution for all the scenarios? The answer is no. If the results of the SQL statement are small and the subquery can use the index, then the best solution is to use correlated execution. The Apply operator can be optimized to Segment Apply, which is to sort the data of the outer table according to the correlated key. In this case, the keys that are within one group won’t have to be executed multiple times. Of course, this is strongly related to the number of distinct values (NDV) of the correlated keys in the outer table. Therefore, the decision about whether to use correlation removal also depends on statistics. When it comes to this point, the regular optimizer is no longer applicable. Only the optimizer with the Volcano or Cascade Style can take both the logic equivalence rules and the cost-based optimization into consideration. Therefore, a perfect solution for subquery depends on an excellent optimizer framework.Aggregation and subquery In the previous section, the final statement is not completely optimized. The aggregation function above OuterJoin and InnerJoin can be pushed down[4]. If OutJoin cannot be simplified, the formal representation of the push-down rule is:[ mathcal{G_{A,F}}(S LOJ_p R)=pi_C(S LOJ_p(mathcal{G}_{A-attr(S),F}R)) ]The (pi_C) above Join is to convert NULL to the default value when the aggregation function accepts empty values. It is worth mentioning that the above formula can be applied only when the following three conditions are met: All the columns that are related to R within the p predicate are in the Group by column. The key of the S relation is in the Group by column. The aggregations in the (mathcal{G}) …"}, {"url": "https://pingcap.com/blog-cn/distributed-system-test-3/", "title": "分布式系统测试那些事儿 - 信心的毁灭与重建", "content": " 本话题系列文章整理自 PingCAP Infra Meetup 第 26 期刘奇分享的《深度探索分布式系统测试》议题现场实录。文章较长,为方便大家阅读,会分为上中下三篇,本文为下篇。 -接中篇- ScyllaDB 有一个开源的东西,是专门用来给文件系统做 Failure Injection 的, 名字叫做 CharybdeFS。如果你想测试你的系统,就是文件系统在哪不断出问题,比如说写磁盘失败了,驱动程序分配内存失败了,文件已经存在等等,它都可以测模拟出来。CharybdeFS: A new fault-injecting file system for software testingSimulate the following errors: disk IO error (EIO) driver out of memory error (ENOMEM) file already exists (EEXIST) disk quota exceeded (EDQUOT) 再来看看 Cloudera,下图是整个 Cloudera 的一个 Failure Injection 的结构。一边是 Tools,一边是它的整个的 Level 划分。比如说整个 Cluster, Cluster 上面有很多 Host,Host 上面又跑了各种 Service,整个系统主要用于测试 HDFS, HDFS 也是很努力的在做有效的测试。然后每个机器上部署一个 AgenTEST,就用来注射那些可能出现的错误。看一下它们作用有多强大。Cloudera: Simulate the following errors: Packets loss/corrupt/reorder/duplicate/delay Bandwidth limit: Limit the network bandwidth for the specified address and port. DNSFail: Apply an injection to let the DNS fail. FLOOD: Starts a DoS attack on the specified port. BLOCK: Blocks all the packets directed to 10.0.0.0/8 (used internally by EC2). SIGSTOP: Pause a given process in its current state. BurnCPU/BurnIO/FillDISK/RONLY/FIllMEM/CorruptHDFS HANG: Hang a host running a fork bomb. PANIC: Force a kernel panic. Suicide: Shut down the machine. 数据包是可以丢的,可以坏的,可以 reorder 的,比如说你发一个 A,再发一个 B,它可以给你 reorder,变成先发了 B 再发了 A,然后看你应用程序有没有正确的处理这种行为。接着发完一次后面再给你重发,然后可以延迟,这个就比较简单。目前这个里面的大部分,TiKV 都有实现,还有带宽的限制,就比如说把你带宽压缩成 1M。以前我们遇到一个问题很有意思,发现有人把文件存到 Redis 里面,但 Redis 是带多个用户共享的,一个用户就能把整个 Redis 带宽给打满了,这样其他人的带宽就很卡,那这种很卡的时候 Redis 可能出现的行为是什么呢?我们并不需要一个用户真的去把它打满,只要用这种工具,瞬间就能出现我把你的带宽限制到原来的 1%,假设别人在跟你抢带宽,你的程序行为是什么?马上就能出来,也不需要配很复杂的环境。这极大的提高了测试效率,同时能测试到很多 corner case。然后 DNS fail。那 DNS fail 会有什么样的结果?有测过吗?可能都没有想过这个问题,但是在一个真正的分布式系统里面,每一点都是有可能出错的。还有 FLOOD,假设你现在被攻击了,整个系统的行为是什么样的?然后一不小心被这个 IP table 给 block 了,该怎么办。这种情况我们确实出现过。我们一上来并发,两万个连接一打出去,然后发现大部分都连不上,后来一看 IP table 自动启用了一个机制,然后把你们都 block。当然我们后面查了半个小时左右,才把问题查出来。但这种实际上应该是在最开始设计的时候就应该考虑的东西。如果你的进程被暂停了,比如说大家在云上跑在 VM 里面,整个 VM 为了升级,先把你整个暂停了,升级完之后再把你恢复的时候会怎么样?那简单来讲,就是如果假设你程序是有 GC 的,GC 现在把我们的程序卡了五秒,程序行为是正常的吗?五十秒呢?这个很有意思的就是,BurnCPU,就是再写一个程序,把 CPU 全占了,然后让你这个现在的程序只能使用一小部分的 CPU 的时候,你程序的行为是不是正常的。正常来讲,你可能说我 CPU 不是瓶颈啊,我瓶颈在 IO,当别人跟你抢 CPU,把你这个 CPU 压的很低的时候,到 CPU 是瓶颈的时候,正常你的程序的这个行为是不是正常的?还有 IO,跟你抢读的资源,跟你抢写的资源,然后 filedisk 把磁盘写满,写的空间很少。比如说对数据库而言,你创建你的 redo log 的时候,都已经满了会怎么样?然后我突然把磁盘设为只读,就你突然一个写入会出错,但是你接下来正常的读写行为是不是对的?很典型的一个例子,如果一个数据库你现在写入,磁盘满了,那外面读请求是否就能正常响应。 Fill memory,就是瞬间把这个 memory 给压缩下来,让你下次 malloc 的时候可能分布不到内存。这个就和业务比较相关了,就是破坏 HDFS 的文件。其它的就是 Hang、Panic,然后还有自杀,直接关掉机器,整个系统的行为是什么样的?现在比较痛苦的一点是大家各自为政,每一家都做一套,但是没有办法做成一个通用的东西给所有的人去用。包括我们自己也做了一套,但是确实没有办法和其他的语言之间去 share,最早提到的那个 libfu 库实际上是在 C 语言写的,那所有 C 相关的都可以去 call 那个库。Distributed testing Namazu ZooKeeper: Found ZOOKEEPER-2212, ZOOKEEPER-2080 (race): (blog article) Etcd: Found etcdctl bug #3517 (timing specification), fixed in #3530. The fix also resulted a hint of #3611, Reproduced flaky tests {#4006, #4039} YARN: Found YARN-4301 (fault tolerance), Reproduced flaky tests{1978, 4168, 4543, 4548, 4556} 然后 Namazu。大家肯定觉得 ZooKeeper 很稳定呀, Facebook 在用、阿里在用、京东在用。大家都觉得这个东西也是很稳定的,直到这个工具出现了,然后轻轻松松就找到 bug 了,所有的大家认为的这种特别稳定的系统,其实 bug 都还挺多的,这是一个毁三观的事情,就是你觉得东西都很稳定,都很 stable,其实不是的。从上面,我们能看到 Namazu 找到的 Etcd 的几个 bug,然后 YARN 的几个 bug,其实还有一些别的。How TiKV use namazu Use nmz container / non-container mode to disturb cluster. Run container mode in CI for each commit. (1 hour) Run non-container mode for a stable version. (1 week+) Use extreme policy for process inspector Pick up some processes and execute them with SCHED_RR scheduler. others are executed with SCHED_BATCH scheduler Use [0, 30s] delay for filesystem inspector 接下来说一下 TiKV 用 Namazu 的一些经验。因为我们曾经在系统上、在云上面出现过一次写入磁盘花了五十几秒才完成的情况,所以我们需要专门的工具模拟这个磁盘的抖动。有时候一次写入可能确实耗时比较久,那这种时候是不是 OK 的。大家如果能把这种东西统统用上,我觉得还能为很多开源系统找出一堆 bug。稍微介绍一下我们现在运行的基本策略,比如说我们会用 0 到 30 秒的这个 delay (就是每一次你往文件系统的交互,比如说读或者写,那么我们会给你产生随机的 0 到 30 秒的 delay ),但我们正常应该还是需要去测三十秒到几分钟的延迟的情况,是否会让整个系统崩掉了。How TiKV simulate network transport Drop/Delay messages randomly Isolate Node Partition [1, 2, 3, 4, 5] -> [1, 2, 3] + [4, 5] Out of order messages Filter messages Duplicate and send redundant messages 怎么模拟网络呢?假设你有网络,里面有五台机器,那我现在想做一个脑裂怎么做?不能靠拔网线对吧?比如在 TiKV 的测试框架中,我们就可以直接通过 API 把 5 个节点脑裂成两部分,让 1, 2, 3 号节点互相联通,4, 5 号节点也能联通,这两个分区彼此是隔离的,非常的方便。其实原理很简单,这种情况是用程序自己去模拟,假如是你发的包,自动给你丢掉,或者直接告诉你 unreachable,那这个时候你就知道这个网络就脑裂了,然后你怎么做?就是只允许特定类型的消息进来,把其他的都丢掉,这样一来你可以保证有些 bug 是必然重现的。这个框架给了我们极大的信心用来模拟并重现各种 corner case,确保这些 corner case 在单元测试中每次都能被覆盖到。How to test Rocksdb Treat storage as a black box. Three steps(7*24): Fill data, Random kill -9 Restart Consistent check. Results: Found 2 bugs. Both fixed 然后说说我们怎么测 RocksDB。 RocksDB 在大家印象中是很稳定的,但我们最近发现了两个 bug。测的方法是这样的:我们往 RocksDB 里面填数据,然后随机的一段时间去把它 kill 掉,kill 掉之后我们重启,重新启动之后去检测我们刚才 fail 的 data 是不是一致的,然后我们发现两个可能造成数据丢失的 bug,但是官方的响应速度非常快,几天就都 fix 了。可是大家普遍运行的是这么 stable 的系统,为什么还会这么容易找到 bug?就说这个测试,如果是一直有这个测试的 cover,那么这两个 bug 可能很快就能够被发现。这是我们一个基本的,也就是当成一个纯黑盒的测。大家在测数据库的时候,基本也是当黑盒测。比如说 MySQL 写入数据,kill 掉,比如说我 commit 一个事务,数据库告诉我们 commit 成功,我把数据库 kill 掉,我再去查我刚才提交的数据一样能查到。这是一个正常的行为,如果查不到,说明整个系统有问题。More tools american fuzzy lop 其实还有一些更加先进的工具,大家平时觉得特别稳定的东西,都被摧残的不行。Nginx 、NGPD、tcpdump 、LibreOffice ,如果有用 Linux 的同学可能知道,还有 Flash、sqlite。这个东西一出来,当时大家很兴奋,说怎么一下子找了这么多 bug,为什么以前那么稳定的系统这么不堪一击,会觉得这个东西它还挺智能的。就比如说你程序里面有个 if 分支,它是这样的,假如你程序有一百条指令,它先从前面一直走,走到某条分支指令的时候,它是一直持续探索,一个分支走不下去,它会一直在这儿持续探索,再给你随机的输入,直到我探索进去了,我记下来了下次我知道我用这个输入可以进去特定的分支。那我可以再往下走,比如说你 if 分支进去之后里面还有 if ,那你传统手段可能探测不进去了但它可以,它记录一下,我这个可以进去,然后我重来,反正我继续输入这个,我再往里面走,一旦我探测到一个新的分支,我再记住,我再往里面走。所以它一出来的时候大家都说这个真厉害,一下发现这么多 bug。但最激动的不是这些人,最激动的是黑客,为什么?因为突然有很多栈溢出、堆溢出漏洞被发现了,然后就可以写一堆工具去攻击线上的这么多系统。所以很多的技术的推进在早期的时候是黑客做出来,但是他们的目的当然不一定是为了测试 bug,而是为了怎么黑一个系统进去,这是他们当时做的,所以这个工具也是非常强大、非常有意思的,大家可以拿去研究一下自己的系统。大家印象里面各种文件系统是很稳定的,可是当用 American fuzzy lop 来测试的时候,被惊呆了。 Btrfs 连 5 秒都没有坚持到就跪了,大家用的最多的 Ext4 是最坚挺的,也才抗了两个小时!!!再来说说 Google,Google 怎么做测试对外讲的不多,最近 Chrome team 开源了他们的 Fuzz 测试工具 OSS-Fuzz,这个工具强大的地方在于自动化做的极好: 发现 bug 后自动创建 issue bug 解决后自动 verify 更惊人的是 OSS-Fuzz 集群一周可以跑 ~4 trillion test cases 更多细节大家可以看这篇文章:Announcing OSS-Fuzz: Continuous Fuzzing for Open Source Software另外有些工具能让分布式系统开发人员的生活变得更美好一点。Tracing tools may help you Google Dapper Zipkin OpenTracing 还有 Tracing,比如说我一个 query 过来,然后经过这么多层,经过这么多机器,然后在不同的地方,不同环节耗时多久,实际上这个在分布式系统里面,有个专门的东西做 Tracing ,就是 distribute tracing tools。它可以用一条线来表达你的请求在各个阶段耗时多长,如果有几段,那么分到几个机器,分别并行的时候好了多长时间。大体的结构是这样的:这里是一个具体的例子:很清晰,一看就知道了,不用去看 log,这事其实一点也不新鲜,Google 十几年前就做了一个分布式追踪的工具。然后开源社区要做一个实现叫做 Zipkin,好像是 java 还是什么写的,又出了新的叫 OpenTracing,是 Go 写的。我们现在正准备上这个系统,用来追踪 TiDB 的请求在各个阶段的响应时间。最后想说一下,大家研究系统发现 bug 多了之后,不要对系统就丧失了信心,毕竟bug 一直在那里,只是从前没有发现,现在发现得多了,总体上新的测试方法让系统的质量比以前好了很多。好像有点超时了,先聊到这里吧,还有好多细节没法展开,下次再聊。-本系列完结- "}, {"url": "https://pingcap.com/meetup/meetup-2016-12-07/", "title": "分布式系统测试那些事儿——信心的毁灭与重建", "content": ""}, {"url": "https://pingcap.com/weekly/2016-12-05-tidb-weekly/", "title": "Weekly update (November 28 ~ December 04, 2016)", "content": " Weekly update in TiDB Last week, we landed 48 PRs in the TiDB repositories and 6 PRs in the TiDB docs repositories.Added Support the built-in function: str_to_date. Refactor the time structure: Introduce a TimeInternal interface to replace the go time representation. Add the raw Key-Value API and make TiKV a raw Key-Value engine. Add a bench tool for the raw Key-Value API. Support the PARTITION keyword: parsed but ignored. Support the Alter User statement to change user’s password. Support the set password = pwd; statement. Use circleci. Fixed Check duplicate column names when adding index. Check duplicate index columns when creating table. Fix a bug when join exists in subquery. Make the schema out of date error retry automatically within TiDB. Fix a typo in the INFORMATION_SCHEMA.COLUMNS table. Fix the date_format type infer bug. Do not prune the set variable expression in projection. Improved Update the template for new issue. Use the statement context to handle truncated error. Push the aggregate operator down under union all. Document change The following guides are updated: TiDB Docker Deployment Compatibility with MySQL Weekly update in TiKV Last week, we landed 22 PRs in the TiKV repositories.Added Support consistency check to find if data is corrupted or not dynamically. Add configuration to control the max running task count. Add the raw Key-Value API. Fixed Check the Placement Driver list to fix #1186. Check whether the term is stale for the Raft command to fix #1317. Schedule the log Garbage Collection by size to fix #1337. Improved Replace the score type with resource kind to calculate the scores more easily. Replace origin concept balance with schedule and simplify configurations. Use coordinator to control the speed of different schedulers. "}, {"url": "https://pingcap.com/meetup/meetup-2016-12-03/", "title": "【现场】COISF 专场 Meetup", "content": " 【现场】COISF 专场 Meetup 2016-12-03 COISF PingCAP PingCAPPingCAP ![]() 微信号pingcap2015功能介绍PingCAP 专注于新型分布式数据库的研发,是知名开源数据库 TiDB (GitHub 总计10000+ stars ) 背后的团队,总部设在北京,是国内第一家开源的新型分布式关系型数据库公司、国内领先的大数据技术和解决方案提供商。COISF Meetup今天是一期人数爆满的 Meetup。😊 作为 COISF 专场,感谢众多小伙伴与我们一起见证 COISF 的首次亮相。当然,首场参与是一定会有福利滴。这一期,我们邀请到了一位女神级讲师–百度网页搜索部工程师雷丽媛,为大家讲解百度文件系统的架构设计;另外,PingCAP 联合创始人崔秋也有出台,为大家深情回顾 TiDB 的发展历程 :)▌开场:COISF Opening Talk在本环节中,PingCAPCo-Founder 崔秋,百度搜索基础架构团队技术负责人颜世光,以及奇虎 360 基础架构组存储负责人陈宗志共同为大家介绍了 COISF 的由来和使命,并对目前基金会内的顶级项目进行了简单介绍。COISF(China Open Infrastructure Software Foundation ):中国开放基础软件基金会,其核心技术委员会由 PingCAP、百度、奇虎 360、小米(排名不分先后)等公司的基础软件项目团队组成,致力于促进和发展中国的新一代开源基础软件。目前基金会项目包括:Baidu/BFS、Baidu/Tera、PingCAP/TiDB、PingCAP/TiKV、Qihoo360/Zeppelin 等。我们认为,一方面开源是软件开发的未来,能更好地促进创新与合作;另一方面未来几十年中国的基础软件必将蓬勃发展,并在世界范围内扮演重要角色。但当前国内有很多优秀的开源软件, 因为文化和语言的藩篱没能融入西方社区, 无法获得足够的关注与支持,导致发展缓慢。我们通过建设中国统一的基础软件开发社区,甄选优秀的项目加入,集中优势资源促进这些项目的快速发展与成熟。COISF 的使命是:促进中国下一代开源基础软件生态系统的发展。▌Topic 1:百度文件系统-面向实时应用的分布式文件系统Speaker:雷丽媛,COISF BFS PMC,百度网页搜索部工程师,专注于分布式存储领域,目前负责百度结构化数据存储和分布式系统的相关工作。Content:百度的核心业务和数据库系统都依赖分布式文件系统作为底层存储,文件系统的可用性和性能对上层搜索业务的稳定性与效果有着至关重要的影响。现有的分布式文件系统(如HDFS等)是为离线批处理设计的,无法在保证高吞吐的情况下做到低延迟和持续可用,所以百度从搜索的业务特点出发,设计了百度文件系统。本场分享整体介绍了百度文件系统 BFS 的架构设计和子模块。▌Topic 2:TiDB - The Future of DatabaseSpeaker:崔秋,COISF TiDB PMC,PingCAP 联合创始人,重度开源爱好者,曾任职于搜狗、豌豆荚,长期从事广告系统基础组件相关的研究,现主要从事开源 NewSQL 数据库 TiDB/TiKV 相关的设计和研发工作。Content:NewSQL 不仅具有传统 SQL 和 ACID 的事务保证,同时还具有 NoSQL 的 Scale 能力, 这是一种世界前沿的数据库新技术。TiDB 以 Google Spanner/F1 作为理论参考,从零到一地完整实现这种面向未来的数据库。今天我们主要回顾 TiDB 的整个发展历程,从单机到分布式,从 Alpha 到 RC,从开源到社区,分享每一次架构演进背后的思考和感悟,以及每个不同阶段我们所做的取舍。最后,从客户的真实反馈中,我们一起探讨了 TiDB 的适用场景和最佳实践。COISF(China Open Infrastructure Software Foundation ):中国开放基础软件基金会,其核心技术委员会由 PingCAP、百度、奇虎 360、小米(排名不分先后)等公司的基础软件项目团队组成,致力于促进和发展中国的新一代开源基础软件。为了更好地推动国内开源社区的发展,COISF 专场 Meetup 将定期举办,在这里,我们希望大家不仅能学到技术干货,更能真正感受开源精神的魅力。赞赏长按二维码向我转账受苹果公司新规定影响,微信 iOS 版的赞赏功能被关闭,可通过二维码转账支持公众号。阅读原文 阅读**投诉微信扫一扫 关注该公众号即将打开”“小程序取消 打开"}, {"url": "https://pingcap.com/weekly/2016-11-28-tidb-weekly/", "title": "Weekly update (November 21 ~ November 27, 2016)", "content": " Weekly update in TiDB Last week, we landed 44 PRs in the TiDB repositories and 3 PRs in the TiDB docs repositories.Added Support creating anonymous index. Add the mailing list for TiDB users. Support the show events syntax. Fixed Enlarge the Time To Live (TTL)for large transactions. Parse float literal using the decimal parser. Prevent panic for malformed packets. Fix the behavior in the aggregate operator: for the select a, c from t groupby t.b statement, a and c should use the first row in the group. Add sequence number in binlog to preserve the original mutation order. Reset the current database after dropping the current database. Improved Prevent loading schema by multiple threads. Make unit test run faster. Make explain result clearer. Remove driver.go from the TiDB project to enable users to use the MySQL official driver. Document change Add the following new guides: TiDB Cluster Troubleshooting Guide TiKV Tuning Guide Weekly update in TiKV Last week, we landed 20 PRs in the TiKV repositories.Added Add and report the store labels to Placement Driver (PD). Add pending task metrics for Worker. Dump all the statistics about Column Family compaction and Database. Fixed Use fs2 to get disk states to fix #1318 Use the monotonic clock time to improve the safety of leader lease read, to fix #964. Check the format of the listening and advertise address to fix #1332. Get the first value no matter if it is Null in aggregation. Fix a Garbage Collection bug which deletes the latest deleted key before SafePoint. Stop attaching term to the MsgReadIndex message to fix #1240. Improved Clean up the command flags and configurations parsing. Abstract a Selector to schedule region peer. Split the Raft Ready handle to two handles: Append and Apply. Use larger Heartbeat and Election timeout to reduce the network pressure. Ignore outdated tasks in Coprocessor to fix #1305. "}, {"url": "https://pingcap.com/meetup/meetup-2016-11-26/", "title": "PingCAP 第 31 期 NewSQL Meetup", "content": " PingCAP 第 31 期 NewSQL Meetup 2016-11-26 黄华超&邓栓 PingCAP PingCAPPingCAP ![]() 微信号pingcap2015功能介绍PingCAP 专注于新型分布式数据库的研发,是知名开源数据库 TiDB (GitHub 总计10000+ stars ) 背后的团队,总部设在北京,是国内第一家开源的新型分布式关系型数据库公司、国内领先的大数据技术和解决方案提供商。NewSQL Meetup今天是 PingCAP 第 31 期 Meetup,主题是黄华超分享的《PD 的实现和演进》以及邓栓分享的《从容器和微服务的发展看基础架构变迁》。▌Topic 1:PD 的实现和演进Lecturer:黄华超,PingCAP 工程师,曾就职于微信、好赞科技,从事分布式存储相关工作,现负责 PingCAP PD 研发工作。Content:本次分享首先介绍了 PD 在 TiDB 集群的作用,以及集群是如何动态扩容缩容的。然后分别讲解了 PD 的各个功能是如何实现的,其中,着重分享了集群调度的相关设计和思考,以及新的标签调度功能。▌Topic 2:从容器和微服务的发展看基础架构变迁Lecturer:邓栓(Tennix),Rust 中文社区管理员,PingCAP SRE 工程师,负责 TiDB 与 Kubernetes 一体化整合部署方案。Content:近些年来容器和微服务的概念变得特别火热,越来越多的互联网公司开始尝试将以前的单体服务迁移到微服务,并且在实践中使用容器来部署服务,容器和微服务也催生了 DevOps,CaaS,Immutable infrastructure,Service orchestration 等概念。今天主要从容器和微服务角度谈了新技术应用和实践给开发者带来了哪些便利和挑战,基础架构发生了哪些改变,并尝试探讨了未来的应用服务会是什么样的架构。特别鸣谢:场地赞助-泰利驿站PingCAP Meetup"}, {"url": "https://pingcap.com/blog-cn/percolator-and-txn/", "title": "Percolator 和 TiDB 事务算法", "content": " 本文先概括的讲一下 Google Percolator 的大致流程。Percolator 是 Google 的上一代分布式事务解决方案,构建在 BigTable 之上,在 Google 内部 用于网页索引更新的业务,原始的论文在此。原理比较简单,总体来说就是一个经过优化的二阶段提交的实现,进行了一个二级锁的优化。TiDB 的事务模型沿用了 Percolator 的事务模型。 总体的流程如下:读写事务 1) 事务提交前,在客户端 buffer 所有的 update/delete 操作。 2) Prewrite 阶段:首先在所有行的写操作中选出一个作为 primary,其他的为 secondaries。PrewritePrimary: 对 primaryRow 写入 L 列(上锁),L 列中记录本次事务的开始时间戳。写入 L 列前会检查: 是否已经有别的客户端已经上锁 (Locking)。 是否在本次事务开始时间之后,检查 W 列,是否有更新 [startTs, +Inf) 的写操作已经提交 (Conflict)。 在这两种种情况下会返回事务冲突。否则,就成功上锁。将行的内容写入 row 中,时间戳设置为 startTs。将 primaryRow 的锁上好了以后,进行 secondaries 的 prewrite 流程: 类似 primaryRow 的上锁流程,只不过锁的内容为事务开始时间及 primaryRow 的 Lock 的信息。 检查的事项同 primaryRow 的一致。 当锁成功写入后,写入 row,时间戳设置为 startTs。3) 以上 Prewrite 流程任何一步发生错误,都会进行回滚:删除 Lock,删除版本为 startTs 的数据。4) 当 Prewrite 完成以后,进入 Commit 阶段,当前时间戳为 commitTs,且 commitTs> startTs : commit primary:写入 W 列新数据,时间戳为 commitTs,内容为 startTs,表明数据的最新版本是 startTs 对应的数据。 删除L列。 如果 primary row 提交失败的话,全事务回滚,回滚逻辑同 prewrite。如果 commit primary 成功,则可以异步的 commit secondaries, 流程和 commit primary 一致, 失败了也无所谓。事务中的读操作 检查该行是否有 L 列,时间戳为 [0, startTs],如果有,表示目前有其他事务正占用此行,如果这个锁已经超时则尝试清除,否则等待超时或者其他事务主动解锁。注意此时不能直接返回老版本的数据,否则会发生幻读的问题。 读取至 startTs 时该行最新的数据,方法是:读取 W 列,时间戳为 [0, startTs], 获取这一列的值,转化成时间戳 t, 然后读取此列于 t 版本的数据内容。 由于锁是分两级的,primary 和 seconary,只要 primary 的行锁去掉,就表示该事务已经成功 提交,这样的好处是 secondary 的 commit 是可以异步进行的,只是在异步提交进行的过程中 ,如果此时有读请求,可能会需要做一下锁的清理工作。"}, {"url": "https://pingcap.com/blog-cn/mvcc-in-tikv/", "title": "TiKV 的 MVCC(Multi-Version Concurrency Control)机制", "content": " 并发控制简介 事务隔离在数据库系统中有着非常重要的作用,因为对于用户来说数据库必须提供这样一个“假象”:当前只有这么一个用户连接到了数据库中,这样可以减轻应用层的开发难度。但是,对于数据库系统来说,因为同一时间可能会存在很多用户连接,那么许多并发问题,比如数据竞争(data race),就必须解决。在这样的背景下,数据库管理系统(简称 DBMS)就必须保证并发操作产生的结果是安全的,通过可串行化(serializability)来保证。虽然 Serilizability 是一个非常棒的概念,但是很难能够有效的实现。一个经典的方法就是使用一种两段锁(2PL)。通过 2PL,DBMS 可以维护读写锁来保证可能产生冲突的事务按照一个良好的次序(well-defined) 执行,这样就可以保证 Serializability。但是,这种通过锁的方式也有一些缺点: 读锁和写锁会相互阻滞(block)。 大部分事务都是只读(read-only)的,所以从事务序列(transaction-ordering)的角度来看是无害的。如果使用基于锁的隔离机制,而且如果有一段很长的读事务的话,在这段时间内这个对象就无法被改写,后面的事务就会被阻塞直到这个事务完成。这种机制对于并发性能来说影响很大。 多版本并发控制(Multi-Version Concurrency Control,以下简称 MVCC) 以一种优雅的方式来解决这个问题。在 MVCC 中,每当想要更改或者删除某个数据对象时,DBMS 不会在原地去删除或这修改这个已有的数据对象本身,而是创建一个该数据对象的新的版本,这样的话同时并发的读取操作仍旧可以读取老版本的数据,而写操作就可以同时进行。这个模式的好处在于,可以让读取操作不再阻塞,事实上根本就不需要锁。这是一种非常诱人的特型,以至于在很多主流的数据库中都采用了 MVCC 的实现,比如说 PostgreSQL,Oracle,Microsoft SQL Server 等。TiKV 中的 MVCC 让我们深入到 TiKV 中的 MVCC,了解 MVCC 在 TiKV 中是如何 实现 的。1. Timestamp Oracle(TSO) 因为TiKV 是一个分布式的储存系统,它需要一个全球性的授时服务,下文都称作 TSO(Timestamp Oracle),来分配一个单调递增的时间戳。 这样的功能在 TiKV 中是由 PD 提供的,在 Google 的 Spanner 中是由多个原子钟和 GPS 来提供的。2. Storage 从源码结构上来看,想要深入理解 TiKV 中的 MVCC 部分,src/storage 是一个非常好的入手点。 Storage 是实际上接受外部命令的结构体。pub struct Storage { engine: Box<Engine>, sendch: SendCh<Msg>, handle: Arc<Mutex<StorageHandle>>, } impl Storage { pub fn start(&mut self, config: &Config) -> Result<()> { let mut handle = self.handle.lock().unwrap(); if handle.handle.is_some() { return Err(box_err!("scheduler is already running")); } let engine = self.engine.clone(); let builder = thread::Builder::new().name(thd_name!("storage-scheduler")); let mut el = handle.event_loop.take().unwrap(); let sched_concurrency = config.sched_concurrency; let sched_worker_pool_size = config.sched_worker_pool_size; let sched_too_busy_threshold = config.sched_too_busy_threshold; let ch = self.sendch.clone(); let h = try!(builder.spawn(move || { let mut sched = Scheduler::new(engine, ch, sched_concurrency, sched_worker_pool_size, sched_too_busy_threshold); if let Err(e) = el.run(&mut sched) { panic!("scheduler run err:{:?}", e); } info!("scheduler stopped"); })); handle.handle = Some(h); Ok(()) } } start 这个函数很好的解释了一个 storage 是怎么跑起来的。3. Engine 首先是 Engine。 Engine 是一个描述了在储存系统中接入的的实际上的数据库的接口,raftkv 和 Enginerocksdb 分别实现了这个接口。4. StorageHandle StorageHanle 是处理从sendch 接受到指令,通过 mio 来处理 IO。接下来在Storage中实现了async_get 和async_batch_get等异步函数,这些函数中将对应的指令送到通道中,然后被调度器(scheduler)接收到并异步执行。Ok,了解完Storage 结构体是如何实现的之后,我们终于可以接触到在Scheduler 被调用的 MVCC 层了。当 storage 接收到从客户端来的指令后会将其传送到调度器中。然后调度器执行相应的过程或者调用相应的异步函数。在调度器中有两种操作类型,读和写。读操作在 MvccReader 中实现,这一部分很容易理解,暂且不表。写操作的部分是MVCC的核心。5. MVCC Ok,两段提交(2-Phase Commit,2PC)是在 MVCC 中实现的,整个 TiKV 事务模型的核心。在一段事务中,由两个阶段组成。Prewrite 选择一个 row 作为 primary row, 余下的作为 secondary row。 对primary row 上锁. 在上锁之前,会检查是否有其他同步的锁已经上到了这个 row 上 或者是是否经有在 startTS 之后的提交操作。这两种情况都会导致冲突,一旦都冲突发生,就会回滚(rollback)。 对于 secondary row 重复以上操作。Commit Rollback 在Prewrite 过程中出现冲突的话就会被调用。Garbage Collector 很容易发现,如果没有垃圾收集器(Gabage Collector) 来移除无效的版本的话,数据库中就会存有越来越多的 MVCC 版本。但是我们又不能仅仅移除某个 safe point 之前的所有版本。因为对于某个 key 来说,有可能只存在一个版本,那么这个版本就必须被保存下来。在TiKV中,如果在 safe point 前存在 Put 或者 Delete 记录,那么比这条记录更旧的写入记录都是可以被移除的,不然的话只有Delete,Rollback和Lock 会被删除。TiKV-Ctl for MVCC 在开发和 debug 的过程中,我们发现查询 MVCC 的版本信息是一件非常频繁并且重要的操作。因此我们开发了新的工具来查询 MVCC 信息。TiKV 将 Key-Value,Locks 和 Writes 分别储存在CF_DEFAULT,CF_LOCK,CF_WRITE中。它们以这样的格式进行编码 default lock write key z{encoded_key}{start_ts(desc)} z{encoded_key} z{encoded_key}{commit_ts(desc)} value {value} {flag}{primary_key}{start_ts(varint)} {flag}{start_ts(varint)} Details can be found here.因为所有的 MVCC 信息在 Rocksdb 中都是储存在 CF Key-Value 中,所以想要查询一个 Key 的版本信息,我们只需要将这些信息以不同的方式编码,随后在对应的 CF 中查询即可。CF Key-Values 的 表示形式。"}, {"url": "https://pingcap.com/weekly/2016-11-21-tidb-weekly/", "title": "Weekly update (November 14 ~ November 20, 2016)", "content": " Weekly update in TiDB Last week, we landed 30 PRs in the TiDB repositories, 3 PRs in the TiDB docs repositories.Added Add a session variable to skip unique constraint check: This could be used when migrating data. More metrics for statement counter. Fixed Use reserved keywords as the table/column name. Add missing comments in the show table status result. Fix a bug that gets duplicate auto_inc ID after truncating table.. Improved Make the Explain result more explicit. Tune the package size to be friendly for rocksdb. Use a better way to reload schema and reduce memory usage. Fetch schemas in a parallel way to make it faster when there are a huge number of schemas and tables. Document change Add the following new guides: Compatibility with MySQL. Reading data from history versions. Weekly update in TiKV Last week, we landed 19 PRs in the TiKV repositories.Fixed Check whether the message is discarded after proposing. Improved Still refactor cache to make it more easily to use, with PR 360, 382. Add lock Time To Live (TTL) for large transactions. Try updating the soft limit when requirement check fails. Support configuring fill cache. Limit the WriteBatch size for the ResolveLock and Garbage Collection commands. Clean up unnecessary filter args. Abstract a Selector to handle different strategies to select stores. Enlarge the latches size of the scheduler to reduce lock conflicts. "}, {"url": "https://pingcap.com/blog-cn/tidb-syncer/", "title": "解析 TiDB 在线数据同步工具 Syncer", "content": " TiDB 是一个完全分布式的关系型数据库,从诞生的第一天起,我们就想让它来兼容 MySQL 语法,希望让原有的 MySQL 用户 (不管是单机的 MySQL,还是多机的 MySQL Sharding) 都可以在基本不修改代码的情况下,除了可以保留原有的 SQL 和 ACID 事务之外,还可以享受到分布式带来的高并发,高吞吐和 MPP 的高性能。对于用户来说,简单易用是他们试用的最基本要求,得益于社区和 PingCAP 小伙伴们的努力,我们提供基于 Binary 和 基于 Kubernetes 的两种不同的一键部署方案来让用户可以在几分钟就可以部署起来一个分布式的 TiDB 集群,从而快速地进行体验。 当然,对于用户来说,最好的体验方式就是从原有的 MySQL 数据库同步一份数据镜像到 TiDB 来进行对比测试,不仅简单直观,而且也足够有说服力。实际上,我们已经提供了一整套的工具来辅助用户在线做数据同步,具体的可以参考我们之前的一篇文章:TiDB 作为 MySQL Slave 实现实时数据同步, 这里就不再展开了。后来有很多社区的朋友特别想了解其中关键的 Syncer 组件的技术实现细节,于是就有了这篇文章。首先我们看下 Syncer 的整体架构图, 对于 Syncer 的作用和定位有一个直观的印象。从整体的架构可以看到,Syncer 主要是通过把自己注册为一个 MySQL Slave 的方式,和 MySQL Master 进行通信,然后不断读取 MySQL Binlog,进行 Binlog Event 解析,规则过滤和数据同步。从工程的复杂度上来看,相对来说还是非常简单的,相对麻烦的地方主要是 Binlog Event 解析和各种异常处理,也是容易掉坑的地方。为了完整地解释 Syncer 的在线同步实现,我们需要有一些额外的内容需要了解。MySQL Replication 我们先看看 MySQL 原生的 Replication 复制方案,其实原理上也很简单:1)MySQL Master 将数据变化记录到 Binlog (Binary Log), 2) MySQL Slave 的 I/O Thread 将 MySQL Master 的 Binlog 同步到本地保存为 Relay Log 3)MySQL Slave 的 SQL Thread 读取本地的 Relay Log,将数据变化同步到自身MySQL Binlog MySQL 的 Binlog 分为几种不同的类型,我们先来大概了解下,也看看具体的优缺点。1)Row MySQL Master 将详细记录表的每一行数据变化的明细记录到 Binlog。 优点:完整地记录了行数据的变化信息,完全不依赖于存储过程,函数和触发器等等,不会出现因为一些依赖上下文信息而导致的主从数据不一致的问题。 缺点:所有的增删改查操作都会完整地记录在 Binlog 中,会消耗更大的存储空间。2)Statement MySQL Master 将每一条修改数据的 SQL 都会记录到 Binlog。 优点:相比 Row 模式,Statement 模式不需要记录每行数据变化,所以节省存储量和 IO,提高性能。 缺点:一些依赖于上下文信息的功能,比如 auto increment id,user define function, on update current_timestamp/now 等可能导致的数据不一致问题。3)Mixed MySQL Master 相当于 Row 和 Statement 模式的融合。 优点:根据 SQL 语句,自动选择 Row 和 Statement 模式,在数据一致性,性能和存储空间方面可以做到很好的平衡。 缺点:两种不同的模式混合在一起,解析处理起来会相对比较麻烦。MySQL Binlog Event 了解了 MySQL Replication 和 MySQL Binlog 模式之后,终于进入到了最复杂的 MySQL Binlog Event 协议解析阶段了。在解析 MySQL Binlog Eevent 之前,我们首先看下 MySQL Slave 在协议上是怎么和 MySQL Master 进行交互的。Binlog dump首先,我们需要伪造一个 Slave,向 MySQL Master 注册,这样 Master 才会发送 Binlog Event。注册很简单,就是向 Master 发送 COM_REGISTER_SLAVE 命令,带上 Slave 相关信息。这里需要注意,因为在 MySQL 的 replication topology 中,都需要使用一个唯一的 server id 来区别标示不同的 Server 实例,所以这里我们伪造的 slave 也需要一个唯一的 server id。Binlog Event对于一个 Binlog Event 来说,它分为三个部分,header,post-header 以及 payload。 MySQL 的 Binlog Event 有很多版本,我们只关心 v4 版本的,也就是从 MySQL 5.1.x 之后支持的版本,太老的版本应该基本上没什么人用了。Binlog Event 的 header 格式如下:4 bytes timestamp 1 bytes event type 4 bytes server-id 4 bytes event-size 4 bytes log pos 2 bytes flags header 的长度固定为 19,event type 用来标识这个 event 的类型,event size 则是该 event 包括 header 的整体长度,而 log pos 则是下一个 event 所在的位置。这个 header 对于所有的 event 都是通用的,接下来我们看看具体的 event。FORMAT_DESCRIPTION_EVENT在 v4 版本的 Binlog 文件中,第一个 event 就是 FORMAT_DESCRIPTION_EVENT,格式为:2 bytes binlog-version string[50] mysql-server version 4 bytes create timestamp 1 byte event header length string[p] event type header lengths 我们需要关注的就是 event type header length 这个字段,它保存了不同 event 的 post-header 长度,通常我们都不需要关注这个值,但是在解析后面非常重要的ROWS_EVENT 的时候,就需要它来判断 TableID 的长度了, 这个后续再说明。ROTATE_EVENT而 Binlog 文件的结尾,通常(只要 Master 不当机)就是 ROTATE_EVENT,格式如下:Post-header 8 bytes position Payload string[p] name of the next binlog 它里面其实就是标明下一个 event 所在的 binlog filename 和 position。这里需要注意,当 Slave 发送 Binlog dump 之后,Master 首先会发送一个 ROTATE_EVENT,用来告知 Slave下一个 event 所在位置,然后才跟着 FORMAT_DESCRIPTION_EVENT。其实我们可以看到,Binlog Event 的格式很简单,文档都有着详细的说明。通常来说,我们仅仅需要关注几种特定类型的 event,所以只需要写出这几种 event 的解析代码就可以了,剩下的完全可以跳过。TABLE_MAP_EVENT上面我们提到 Syncer 使用 Row 模式的 Binlog,关于增删改的操作,对应于最核心的ROWS_EVENT ,它记录了每一行数据的变化情况。而如何解析相关的数据,是非常复杂的。在详细说明 ROWS_EVENT 之前,我们先来看看 TABLE_MAP_EVENT,该 event 记录的是某个 table 一些相关信息,格式如下:post-header: if post_header_len == 6 { 4 bytes table id } else { 6 bytes table id } 2 bytes flags payload: 1 byte schema name length string schema name 1 byte [00] 1 byte table name length string table name 1 byte [00] lenenc-int column-count string.var_len[length=$column-count] column-def lenenc-str column-meta-def n bytes NULL-bitmask, length: (column-count + 8) / 7 table id 需要根据 post_header_len 来判断字节长度,而 post_header_len 就是存放到 FORMAT_DESCRIPTION_EVENT 里面的。这里需要注意,虽然我们可以用 table id 来代表一个特定的 table,但是因为 Alter Table 或者 Rotate Binlog Event 等原因,Master 会改变某个 table 的 table id,所以我们在外部不能使用这个 table id 来索引某个 table。TABLE_MAP_EVENT 最需要关注的就是里面的 column meta 信息,后续我们解析 ROWS_EVENT 的时候会根据这个来处理不同数据类型的数据。column def 则定义了每个列的类型。ROWS_EVENTROWS_EVENT 包含了 insert,update 以及 delete 三种 event,并且有 v0,v1 以及 v2 三个版本。 ROWS_EVENT 的格式很复杂,如下:header: if post_header_len == 6 { 4 table id } else { 6 table id } 2 flags if version == 2 { 2 extra-data-length string.var_len extra-data } body: lenenc_int number of columns string.var_len columns-present-bitmap1, length: (num of columns+7)/8 if UPDATE_ROWS_EVENTv1 or v2 { string.var_len columns-present-bitmap2, length: (num of columns+7)/8 } rows: string.var_len nul-bitmap, length (bits set in 'columns-present-bitmap1'+7)/8 string.var_len value of each field as defined in table-map if UPDATE_ROWS_EVENTv1 or v2 { string.var_len nul-bitmap, length (bits set in 'columns-present-bitmap2'+7)/8 string.var_len value of each field as defined in table-map } ... repeat rows until event-end ROWS_EVENT 的 table id 跟 TABLE_MAP_EVENT 一样,虽然 table id 可能变化,但是 ROWS_EVENT 和 TABLE_MAP_EVENT 的 table id 是能保证一致的,所以我们也是通过这个来找到对应的 TABLE_MAP_EVENT。 为了节省空间,ROWS_EVENT 里面对于各列状态都是采用 bitmap 的方式来处理的。首先我们需要得到 columns present bitmap 的数据,这个值用来表示当前列的一些状态,如果没有设置,也就是某列对应的 bit 为 0,表明该 ROWS_EVENT 里面没有该列的数据,外部直接使用 null 代替就成了。然后就是 null bitmap,这个用来表明一行实际的数据里面有哪些列是 null 的,这里最坑爹的是 null bitmap 的计算方式并不是 (num of columns+7)/8,也就是 MySQL 计算 bitmap 最通用的方式,而是通过 columns present bitmap 的 bits set 个数来计算的,这个坑真的很大。为什么要这么设计呢,可能最主要的原因就在于 MySQL 5.6 之后 Binlog Row Image 的格式增加了 minimal 和 noblob,尤其是 minimal,update 的时候只会记录相应更改字段的数据,比如我一行有 16 列,那么用 2 个 byte 就能搞定 null bitmap 了,但是如果这时候只有第一列更新了数据,其实我们只需要使用 1 个 byte 就能记录了,因为后面的铁定全为 0,就不需要额外空间存放了。bits set 其实也很好理解,就是一个 byte 按照二进制展示的时候 1 的个数,譬如 1 的 bits set 就是1,而 3 的 bits set 就是 2,而 255 的 bits set 就是 8 了。得到了 present bitmap 以及 null bitmap 之后,我们就能实际解析这行对应的列数据了,对于每一列,首先判断是否 present bitmap 标记了,如果为 0,则跳过用 null 表示,然后在看是否在 null bitmap 里面标记了,如果为 1,表明值为 null,最后我们就开始解析真正有数据的列了。但是,因为我们得到的是一行数据的二进制流,我们怎么知道一列数据如何解析?这里,就要靠 TABLE_MAP_EVENT 里面的 column def 以及 meta 了。 column def 定义了该列的数据类型,对于一些特定的类型,譬如 MYSQL_TYPE_LONG, MYSQL_TYPE_TINY 等,长度都是固定的,所以我们可以直接读取对应的长度数据得到实际的值。但是对于一些类型,则没有这么简单了。这时候就需要通过 meta 来辅助计算了。譬如对于 MYSQL_TYPE_BLOB 类型,meta 为 1 表明是 tiny blob,第一个字节就是 blob 的长度,2 表明的是 short blob,前两个字节为 blob 的长度等,而对于 MYSQL_TYPE_VARCHAR 类型,meta 则存储的是 string 长度。当然这里面还有最复杂的 MYSQL_TYPE_NEWDECIMAL, MYSQL_TYPE_TIME2 等类型,关于不同类型的 column 解析还是比较复杂的,可以单独开一章专门来介绍,因为篇幅关系这里就不展开介绍了,具体的可以参考官方文档。搞定了这些,我们终于可以完整的解析一个 ROWS_EVENT 了:)XID_EVENT 在事务提交时,不管是 Statement 还是 Row 模式的 Binlog,都会在末尾添加一个 XID_EVENT 事件代表事务的结束,里面包含事务的 ID 信息。QUERY_EVENTQUERY_EVENT 主要用于记录具体执行的 SQL 语句,MySQL 所有的 DDL 操作都记录在这个 event 里面。Syncer 介绍完了 MySQL Replication 和 MySQL Binlog Event 之后,理解 Syncer 就变的比较容易了,上面已经介绍过基本的架构和功能了,在 Syncer 中, 解析和同步 MySQL Binlog,我们使用的是我们首席架构师唐刘的 go-mysql 作为核心 lib,这个 lib 已经在 github 和 bilibili 线上使用了,所以是非常安全可靠的。所以这部分我们就跳过介绍了,感兴趣的话,可以看下 github 开源的代码。这里面主要介绍几个核心问题:MySQL Binlog 模式的选择 在 Syncer 的设计中,首先考虑的是可靠性问题,即使 Syncer 异常退出也可以直接重启起来,也不会对线上数据一致性产生影响。为了实现这个目标,我们必须处理数据同步的可重入问题。 对于 Mixed 模式来说,一个 insert 操作,在 Binlog 中记录的是 insert SQL,如果 Syncer 异常退出的话,因为 Savepoint 还没有来得及更新,会导致重启之后继续之前的 insert SQL,就会导致主键冲突问题,当然可以对 SQL 进行改写,将 insert 改成 replace,但是这里面就涉及到了 SQL 的解析和转换问题,处理起来就有点麻烦了。另外一点就是,最新版本的 MySQL 5.7 已经把 Row 模式作为默认的 Binlog 格式了。所以,在 Syncer 的实现中,我们很自然地选择 Row 模式作为 Binlog 的数据同步模式。Savepoint 的选取 对于 Syncer 本身来说,我们更多的是考虑让它尽可能的简单和高效,所以每次 Syncer 重启都要尽可能从上次同步的 Binlog Pos 的地方做类似断点续传的同步。如何选取 Savepoint 就是一个需要考虑的问题了。 对于一个 DML 操作来说(以 Insert SQL 操作举例来看),基本的 Binlog Event 大概是下面的样子:TABLE_MAP_EVENT QUERY_EVENT → begin WRITE_ROWS_EVENT XID_EVENT 我们从 MySQL Binlog Event 中可以看到,每个 Event 都可以获取下一个 Event 开始的 MySQL Binlog Pos 位置,所以只要获取这个 Pos 信息保存下来就可以了。但是我们需要考虑的是,TABLE_MAP_EVENT 这个 event 是不能被 save 的,因为对于 WRITE_ROWS_EVENT 来说,没有 TABLE_MAP_EVENT 基本上没有办法进行数据解析,所以为什么很多人抱怨 MySQL Binlog 协议不灵活,主要原因就在这里,因为不管是 TABLE_MAP_EVENT 还是 WRITE_ROWS_EVENT 里面都没有 Schema 相关的信息的,这个信息只能在某个地方保留起来,比如 MySQL Slave,也就是 MySQL Binlog 是没有办法自解析的。当然,对于 DDL 操作就比较简单了,DDL 本身就是一个 QUERY_EVENT。所以,Syncer 处于性能和安全性的考虑,我们会定期和遇到 DDL 的时候进行 Save。大家可能也注意到了,Savepoint 目前 …"}, {"url": "https://pingcap.com/meetup/meetup-2016-11-19/", "title": "PingCAP 第 30 期 NewSQL Meetup", "content": " PingCAP 第 30 期 NewSQL Meetup 2016-11-19 刘锦龙&刘寅 PingCAP PingCAPPingCAP ![]() 微信号pingcap2015功能介绍PingCAP 专注于新型分布式数据库的研发,是知名开源数据库 TiDB (GitHub 总计10000+ stars ) 背后的团队,总部设在北京,是国内第一家开源的新型分布式关系型数据库公司、国内领先的大数据技术和解决方案提供商。NewSQL Meetup今天是 PingCAP 第 30 期 Meetup,主题是墨迹天气气象算法负责人刘锦龙分享的《深度学习,众包数据与短时临近预报系统》以及刘寅分享的《谈谈 TiDB-Binlog 的设计》。▌Topic 1:深度学习,众包数据与短时临近预报系统Lecturer:刘锦龙,北大理论物理博士,墨迹天气气象算法负责人,负责墨迹相关天气预测算法的研发工作,主要方向为机器学习和深度学习。Content:深入介绍如何将深度学习的最新技术用于革新传统气象预测的一些研究和应用,以及如何处理从用户获取的众包反馈数据并进而改进天气预报的精准度。▌Topic 2:谈谈 TiDB-Binlog 的设计Lecturer:刘寅,PingCAP engineer,现负责 TiDB 商业产品开发和自动化运维。Content:随着TiDB的不断稳定和完善,我们也逐步开发了很多TiDB周边工具。今天主要介绍了TiDB-Binlog设计上的一些考量和实现细节。TiDB-Binlog 可实时记录TiDB的一切数据变化,可以用来做集群的实时备份和恢复,也可以将数据完整地实时同步到下游的异构数据平台。目前我们已经把TiDB-Binlog部署到真实客户的线上系统中,利用实时同步的特性保障了上线过程的可靠和数据安全。今天的分享着重介绍了Binlog的原理,以及生成、收集和还原的过程细节。特别鸣谢:场地赞助-泰利驿站PingCAP Meetup"}, {"url": "https://pingcap.com/blog/2016-11-17-mvcc-in-tikv/", "title": "MVCC in TiKV", "content": " Introduction to concurrency control Transaction isolation is important for database management system. Because database should provide an illusion that the user is the only one who connects to the database, which greatly simplifies application development. But, the concurrency controlling problems like data races must be resolved since there will be a lot of connections to the database. Due to this background, the database management system (DBMS) ensures that the resulting concurrent access patterns are safe, ideally by serializablity.Though serializablity is a great concept, it is hard to implement efficiently. A classical solution is a variant of Two-Phase Locking, aka 2PL. Using 2PL, the DBMS maintains read and write locks to ensure that conflicting transactions are executed in a well-defined order, which results in serializable execution schedules. But, locking, however, has several drawbacks: First, readers and writers block each other. Second, most transactions are read-only and therefore harmless from a transaction-ordering perspective. Using a locking-based isolation mechanism, no update transaction is allowed to change a data object that has been read by a potentially long-running read transaction and thus has to wait until the read transaction finishes. This severely limits the degree of concurrency in the system.Multi-Version Concurrency Control (MVCC) is an elegant solution for this problem, in which each update creates a new version of the data object instead of updating data objects in-place, such that concurrenct readers can still see the old version while the update transaction proceeds concurrently. Such stradegy can prevent read-only transactions from waiting, and in fact do not have to use locking at all. This is an extremely desirable property and the reason why many DBMS implements MVCC, e.g., PostgreSQL, Oracle, Microsoft SQL Server.MVCC in TiKV Let’s dive into TiKV’s MVCC implementation, located at src/storage.Timestamp Oracle(TSO) Since TiKV is a distributed storage system, it needs a globally unique time service, called Timestamp Oracle(TSO), to allocate a monotonic increasing timestamp. This function is provided in PD in TiKV, which is provided by TrueTime API by using multiple modern clock references(GPS and atomic locks) in Spanner. So keep in mind that every TS represents a monotonic increasing timestamp.Storage To dive into the Transaction part in TiKV, src/storage is a good beginning, which implements the entries. Storage is a struct that actually receives the get/Scan commands.pub struct Storage { engine: Box<Engine>, sendch: SendCh<Msg>, handle: Arc<Mutex<StorageHandle>>, } impl Storage { pub fn start(&mut self, config: &Config) -> Result<()> { let mut handle = self.handle.lock().unwrap(); if handle.handle.is_some() { return Err(box_err!("scheduler is already running")); } let engine = self.engine.clone(); let builder = thread::Builder::new().name(thd_name!("storage-scheduler")); let mut el = handle.event_loop.take().unwrap(); let sched_concurrency = config.sched_concurrency; let sched_worker_pool_size = config.sched_worker_pool_size; let sched_too_busy_threshold = config.sched_too_busy_threshold; let ch = self.sendch.clone(); let h = try!(builder.spawn(move || { let mut sched = Scheduler::new(engine, ch, sched_concurrency, sched_worker_pool_size, sched_too_busy_threshold); if let Err(e) = el.run(&mut sched) { panic!("scheduler run err:{:?}", e); } info!("scheduler stopped"); })); handle.handle = Some(h); Ok(()) } } This start function helps to explain how a storage runs.Engine Engine is the trait which describes the actual database used in storage system, which is implemented in raftkv and Enginerocksdb.StorageHandle StorageHandle is the struct that handles commands received from sendch powered by mio.Then the following functions like async_get and async_batch_get will send the corresponding commands to the channel, which can be got by the scheduler to execute asynchronously.All right, the MVCC protocol calling is exactly implemented in Scheduler. The storage receives commands from clients and sends commands as messages to the scheduler. Then the scheduler will process the command or call corresponding asynchronous function. There are two types of operations, reading and writing. Reading is implemented in MvccReader, which is easy to understand. Writing part is the core of MVCC implementation.MVCC Here comes the core of the transaction model of TiKV, which called 2-Phase Commit powered by MVCC. There are two stages in one transaction.Prewrite Select one row as the primary row, the others as the secondary rows. Lock the primary row. Before locking, it will check whether there is other locks on this row or whether there are some commits located after startTS. These two situations will lead to conflicts.If any of themhappens, rollback will be called. Repeat the operations on secondary row. Commit Write to the CF_WRITE with commitTS. Delete the corresponding lock. Rollback Rollback is called when there are conflicts during the prewrite.Garbage collector It is easy to predict that there will be more and more MVCC versions if there is no Garbage Collector to remove the invalid versions. But we cannot just simply removeall the versions before a safe point. Since there maybe only one version for a key, it will be kept. In TiKV, if there is any Put or Delete before the safe point, then all the latter writes can be deleted, otherwise only Delete, Rollback and Lock will be deleted.TiKV-Ctl for MVCC During developing and debugging, sometimes we need to know the MVCC version information.So we develop a new tool for searching the MVCC information. TiKV stores the Key-Values, Locks and Writes information in CF_DEFAULT, CF_LOCK, CF_WRITE. All the values of the CF are encoded as following: default lock write key z{encoded_key}{start_ts(desc)} z{encoded_key} z{encoded_key}{commit_ts(desc)} value {value} {flag}{primary_key}{start_ts(varint)} {flag}{start_ts(varint)} Details can be found here.Since all the MVCC version information is stored as CF Key-Values in RocksDB, to search for a Key’s version information, we just need to encode the key with different formats then search in the corresponding CF. The CF Key-Values are modeled by MvccKv."}, {"url": "https://pingcap.com/blog-cn/mpp-smp-tidb/", "title": "MPP and SMP in TiDB", "content": " 今天主要是想把我们 TiDB 做 SQL 性能优化的一些经验和一些思考,就此跟大家探讨一下。题目写的比较大,但是内容还是比较简单。我们做 TiDB 的 SQL 层时,一开始做的很简单,就是通过最简单的 KV 接口(Get/Set/Seek)去存数据、取数据,做一些非常直白、简单的计算。然而后来我们发现,这个方案在性能上不可接受,可能行不通,我们就重新思考了这个事情。TiDB 的目标是做一个 NewSQL 的 database ,什么是 NewSQL?从 Wikipedia 上我们看到 NewSQL 的定义『NewSQL is a class of modern relational database management systems that seek to provide the same scalable performance of NoSQL systems for online transaction processing (OLTP) read-write workloads while still maintaining the ACID guarantees of a traditional database system.』。首先NewSQL Database 需要能存储海量数据,这点就像一些 NoSQL 数据库一样。然后,能够提供事务的功能。所以 NewSQL 中的计算,主要有两个特点。第一个,就是数据是海量的,这跟 MySQL 传统数据有可能不一样,他们当然可以通过一些 sharding 的方式来进行处理,但是 sharding 之后会损失,比如说你不能跨节点做 Join,没有跨节点事务等。二是,在海量数据情况下,我们还需要对数据进行随时的取用,因为数据存在那,你算不出来就是对用户没有价值、没有意义的,所以我们需要在海量数据的前提下,能够随时把它计算出来。计算主要分两种任务,一种是 OLTP 的 query,就是简单的查询,通过一些索引,就能过滤到大部分数据,然后能够做一些简单的处理和计算。还有一种是 OLAP的 query,这个一般来说会涉及到大量的数据及复杂的 query,比如说 Join,SubQuery 以及 Aggregate 这样一些东西。并且在海量数据的情况下,很多传统数据库上的 OLTP 的 query,看起来可能更像一个 OLAP 的 query,因为涉及到的数据量会非常大。那么在这样一些背景下,我们应该怎么考虑 SQL 计算呢?简单来讲,我们需要想办法在海量数据上,对计算进行优化和提速。传统数据库的提速方法 传统数据库有很多提速的方法,有两种比较有名的,一个是 MPP,它的架构参见下图。计算数据是分在不同的节点上,并且很可能不在一台机器上,它们通过高速的网络连接,让每个节点都自己去处理数据,处理完数据之后再汇总在一起,最后给用户返回结果。这个架构最大的特点就是它是一种 share nothing 的架构,也就是说节点之间的计算是相互不知道的,然后他们只执行自己的事情,不需要去交换数据,这是一种架构。还有一种叫 SMP,这个跟 MPP 对应,它是一种 share everything 的架构。这种架构一般都是在一个 node 上、一个计算节点上进行,然后它们有多个 CPU 同时计算,它们会去通过总线去共享,比如说内存、IO 这样一些东西,这是一种 share everything 的一个架构。可以看到 MPP 和 SMP 这是两种传统数据库中用来提速的一些方案。我看到 PG(PostgreSQL) 最新的代码,他们已经支持了并行的处理,比如他们可以做并行 scan,他们可以去定义并发度,比如说 scan 一个表,他们利用多核这个特性,能够提速很多。当然这个肯定不是线性的,因为你去做并行,做数据交换,是有 overhead 的,这个 overhead 在你并行度太高的时候是挺大的。TiDB 说完传统数据,我们说一下 TiDB。TiDB 的架构如下图所示。虚框所标的是 TiDB SQL layer,它的最上层是 protocol layer ,就是解析 MySQL 协议。然后是 SQL layer,它主要负责 SQL 的解析、查询,查询计划的制定以及生成执行器。它会调用底下的接口来获取数据,然后进行 SQL 的运算。接下来这一层,可以看到,分两个接口,一个就是 KV 的 API ,就是我们会把数据映射为 KV,因为我们最底下一层是一个 KV 的 storage engine 。比如说一行数据我们会用 Row ID 加上 Table ID 加上 Database ID 这些来做一个 key,然后把这行里面的数据作为 value ,再扔到 KV 中,就转成一种 key-value 的模式。对于 index 来说,我们也是转成了 KV 的模式,因为我们的 KV 有一个特点,就是可以进行有序的 scan。比如说你要在某些 Column 上建了 index,我们就会把这个 Column 编码成一个 key,然后再加上 index ID、Table ID 之类的东西,也 send 到这个 KV 里面去。就是说我们的上层,你可以认为只通过这个 API 也是能够正确的获取到数据、访问数据的,大概就是这样一个架构。然后这里还有一个 DistSQL API,这个是我们分布式计算框架的对上层提供了一个抽象,后面我会详细介绍这个 API 。最下面一层,就是我们的 TiKV 。你可以把 TiKV 考虑成一个纯的分布式的带事务的 key-value engine 。为了支持我们分布式 SQL 的 API ,我们给它上面加了更多功能,在这里我们有参考 HBase 的 coprocessor 方案,然后提供一些 EndPoint 的功能,这样对上一层可以提供更丰富的语义。那么,我们怎么让 SQL 在 TiDB/TiKV 中跑的更快?这半年多我们一直在做这个事情。第一就是不管是 NewSQL 数据库还是传统数据库,我们肯定要对 optimizer 进行一些优化,在这方面我们做了特别多特别多的事情,包括常量折叠,后面还会做更多的,比如常量传播这些。然后 Join 怎么去选择,还有就是我们现在有一个 Cost Based Optimize 的一个框架,我们会考虑下层数据的统计信息,然后在统计信息的基础上,再制订查询计划,所以这是一个巨大的坑,我们正在努力的填它。我觉得 Google F1 这部分做的很好,它应该也做了挺多优化,但其它的数据库我觉得倒不一定有我们做的好,比如我看了一下 Spark,它的 Optimizor 比较简单,就是用了大概一部分 Rule 不断地去 Apply。我想主要的原因是 Spark 定位于做一个通用的计算框架,所以对底层的数据信息无法有细致的了解。除了优化器这块儿,确定一个查询计划之后,怎么去执行它,也是很重要的事情。就是说同样的一个计划,可能用不同的执行器执行起来会有不同的效果。因为我们做的是一个 NewSQL 数据库,数据是分布在很多很多节点上的,我们完全可以利用数据广泛分布的特点,提高整体的并行度。而且我们 TiDB SQL layer 是用 Go 来写的,Go 在多核机器上能够发挥并发优势,它的 Goroutine 调度的开销很小,我们可以建很多 Goroutine,利用现在 CPU 越来越多的这个特性,去提高计算的并行度。还有就是说像传统的,比如 MySQL 、PG 上的东西,它主要还是访问内存、访问硬盘这样的一些开销。但对 TiDB 来说,它很大一部分都耗在网络上了,就是说你发一个请求过去,拿到数据,要走一遍网络,这还是有挺大开销的。所以我们一个很重要的目的就是让整个数据的流程尽可能快起来,尽可能的平滑,把网络这种开销尽可能的搞掉。先讲一下,本次分享的标题叫 “MPP and SMP in TiDB” 主要是说我们有一个并行的、分布式的计算框架,怎么用这个计算框架来提高我们 SQL 计算的并行度,还有就是我们提供了coprocessor ,刚才介绍了,是从 HBase 来的。上图中的 Regions 是 TiKV 的一个 region servers ,我们可以在这里面插入一些代码,让它能够执行我们给它定义的一些任务。大家可以先看上图,整个的分层大概就是这样一个流程。它的最上面是执行器,就是我们经过 SQL Optimizer 之后生成执行计划,而后我们会根据执行计划生成这个执行器。接下来是刚才说的 DistSQL API,它会调用我们的 TiClient,就是说是一个 TiKV 的 Client,通过它来访问 TiKV,通过 Rpc 发送请求。它还有一个很重要的功能就是能获取数据分布在哪儿。因为一个表会分成很多 KV,这些 KV 是散列在很多很多 TiKV server 上的,它很重要的功能就是干这个事情,就相当于数据路由,是它一个重要的任务。最下面就是 region server ,这中间可以认为是网络。这样分了几层之后,每一层都有它自己的任务,就是说我们每一层都抽的很薄。Executor 最重要的工作就是制定执行逻辑。就是说它要告诉下面你需要干什么事情。比如你是需要做 count ,还是需要计算 Where ,它理解的是 SQL 逻辑。DistSQL API 是两层之间的封装,就是说我们下面除了 TiKV 之外,还可以接其它的存储引擎,只要你满足我们这个接口的定义就可以。然后 DistSQL API 把上下隔离了,它提供了一个 API ,这个 API 稍后我会详细介绍一下。然后 TiKV Client 就是数据路由,数据的分发,比如说请求失败了怎么办,它干的就是数据请求发送的。Regions 这一层存储了数据,它需要利用上层传下来这个计算逻辑,在这个数据上进行计算。大概就是这些层,每一层只干了自己的事情,不需要关心下一层的实现。这个 API 就是刚才上面那个 DistSQL 提供的对外最重要的一个接口,叫 Select。它有几个参数一个是 client。就是说只要你的 KV 引擎满足带事务、满足 KV 接口,并且满足这个 client 的一些接口,就可以接入 TiDB。有一些其他的厂商跟我们合作,在他们的 KV 上也能 run 我们这个分布式的 SQL ,这是相当于是 KV 的 Client。第二个,就是 SelectRequest。这个东西是由上层执行器构造出来的,它把计算上的逻辑,比如说一些表达式要不要排序、要不要做聚合,所有的信息都放在 req 里边,是一个 Protobuf 结构,然后发给 Select 接口,它会扔到下层,最后扔到那个 region server 上进行计算。还有 concurrency int。这个其实只是个建议,它的作用是提示下层要不要并发的去请求数据。因为我们数据是分在很多 region server 上的,所以要考虑去以多大并发度去发。然后,KeepOrder 这个参数是这样的,就是说下层是有很多 region server 的,我们要把请求发在很多 region server 上,但先发的结果不一定先返回来,因为有网络延迟、计算的延迟,所以这个顺序是不能预先设定好的。但是并不是所有的计算任务都依赖于数据的顺序,大多数情况下从拿到第一个结果开始就可以计算了,你就需要把结果先返回上来。在另一些情况下,我们需要下面按某一种顺序返回结果的,比如说 SQL 语句中有 OrderBy,并且对应的列上有索引,那么制定出来的查询计划很有可能就是首先扫描索引,然后依赖于索引的顺序对数据进行排序,因为索引是有序的,可以节约掉排序的时间。假设我们按照扫索引的顺序给你返回数据的话,你就可以不用后续自己去排了,这个 sort 已经帮你做好了。这个时候,就需要下层数据,下层的这个接口对你返回的数据是按照某个 key 有序的,所以这里就加了一个 KeepOrder 。当你不需要下层数据有序的时候,你就可以把这个设为 false ,假设这是 TiKV ,然后这是 TiDB,假设这个请求发了好几个 region server,虽然这个 TiKV 你可以认为是一个大的 key 的空间,并且按照 key 有序,假设某个后面的 key range 的请求先返回,如果你不要求下层返回有序,你完全可以把这个请求的结果先返回到上面进行计算,让整个计算过程能够更快。接着这个接口返回了一个数据结构,叫 SelectResult ,这个结构可以认为它是一个迭代器,因为我们下层是有很多 TiKV ,然后每个结果是一个 PartialResult。上层封装了一个 SelectResult ,就是一个 PartialResult 的迭代器。通过这个的 next 方法可以拿到下一个 PartialResult ,但是具体的下一个 PartialResult 是哪个的 region server ,是不一定的,就像我刚才说的,取决于你要不要 KeepOrder 。 SelectResult 的内部实现你可以认为是个 pipeline。我们会并发的去往各个 region server 发数据,但是可能有的先返回给你了,有的后返回给你了。虽然某个 region 存储数据的 key 的范围比另外一个 region 的小,但是要不要先把某个 region 的结果返回给你,是由你这个 KeepOrder 决定的。然后如果你是不要 KeepOrder ,那我们就是一个 channel,也就是有数据返回了就往里扔,扔完之后就可以对上返回了。然后这个 API 返回的是 SelectResult 。如果你是要求下面有序,那么这里会对这个 request 建一个slice ,假如前面的没返回来,是不会把后面的 request 返回给你的。主要是定义了这样一个语义,我们就可以很方便的决定下面的这个行为。这个地方,我们是做了一些优化的。当 KeepOrder 为 false 的时候,如果它先到了一部分,你可以先处理那一部分。就是说这个 KeepOrder 是 true 还是 false,影响了最下面一层的返回逻辑。比如你不要这个 KeepOrder ,那么我给一堆 KV server 发了request 之后,这个 response 是扔到一个统一的 channel 里面的,谁先返回就把谁的扔进来,然后外面调用 next 就已经拿到了。但如果你是 KeepOrder 为 true ,我下面所有的 request 按照这个 key 的顺序建了一个 slice,然后你调这个的 next 的时候,它是遍历这个 slice,就是如果前面那个 result 没拿到,它是不会往后面走的,即使后面 response 已经到了,它也不会给你返回的。这个接口还是挺重要的。举个例子吧,来看一下我们怎么去做这个分布式的 SQL ,比如 select * from t where age > 20 and age < 30。在这里, t 这个数据可能分布在很多 region 上,我们会把要扫描 t 这个表的信息以及这个 filter,整个推到 region server 上进行计算,然后 Executor 构造的就是比如说我要扫哪个表,它的表的信息是什么。通过这个表的信息,下层就能去构造 KV,Ti-Client 就能通过这些 KV 找到这个表的数据分布在哪些 region 上面,然后它就会把这个请求发在这些 region 上面,同时在 selecter request 信息里面也会带上我要做 filter 的那个 condition,它会把要查询的表的元信息等都发到存储个表数据的 region server 上。然后它再利用表的信息把数据拿出来并过一遍 filter,只有过了这个 filter 的数据,之后才会返回给 TiDB。这样一方面能够增加这个计算并行度,因为我们可能有很多 region server 存储这个数据,当然只有有这个数据的 region server 我们才会发请求过去。第二,你把 filter 推下去很重要的好处就是,只有过了这个 filter 才能返回,这样返回你的数量是减小了很多,你就能减小无意义的网络传输。据我们在 Google 那边了解的情况是,他们好像不太care这个事儿,因为他们内部网络实在太快了,他们可以直接把所有数据 load 过来,在这边去算,可以认为整个 IPC 就是一台巨大的机器。就像所有的机器都通过总线连起来,有这种感觉,它就不考虑效率问题。所以他们的效率我觉得还是值得考虑。但大部分用户可能是用一些廉价的 PC,我们这个方案其实是更好的一个方案。这是比较简单的一种。我们还有分布式 aggregate,这种是更好搞的,就假设我们把这个 ability 也推下去,比如说 count,然后你在这边过完 filter,你只需要每个 region 计算自己上的结果,给我返回一个这边的计数就可以了,然后我在 TiDB Server 再把这个 partial result 制成一个 final result ,比如说你这边是五个,这边十个,这边二十个,那我加起来直接算个 sum 返回给你就可以了,这是它最大的好处。刚才是介绍了一下我们 TiDB 的一个分布式的计算框架,然后下面我们介绍一下之前我们做这两项工作,就是把这个 Join 让它变得更快一些。最开始的时候,TiDB 进行 Join 运算非常慢,其实这也是 MySQL 的缺陷,MySQL 只支持 look up Join ,它是说你先取一个表的数据,然后用每一行数据去另一个表拿数据,这个在数据量大的时候是很慢的。所以我们支持了 Hash Join。Hash Join 的话比如说你有一个大一个小两个表,大表在千万量级,其实也不是特别大,内存还是能放下的。你可以用一个小表去建一个 Hash 表,然后再从大表去读数据,读数据的时候你可以去 Hash 表中拿数据,待拿到 Join on 那个条件能对应上那个小表的数据,再算,再过一些 filter ,看看要不要输出这一行,然后对外返回结果。为了让它算的更快,我们最近干了一些工作。第一,我们读小表的数据和读大表的数据,是可以并行来搞的,你可以想象成两条数据流。因为我们网络延迟是比较大的,所以我们想让数据尽可能的平滑、平顺地去流动,对于 Join 读取 DataSource 有两个事情要做,第一个是读小表数据,第二个是读大表数据,我们读小表数据可以用一个单独的线程来做,然后它就会发请求去读小表数据。拿到小表数据之后,拿到一行,然后它就可以对这行扔到一个 Hash 表中,算一个 key 。与此同时,我们可以新建另一个线程,它在这同时去读大表的数据,读完大表的数据之后,它再扔给一堆 worker,这堆 worker 就是做 Join 这个事的。就比如说它把数据虽然发到这些 worker,这些 worker 拿到大表的一行,算出 Join 的 key ,然后它去 Hash 表中去拿到对应的小表的数据,再看能不能过这个 Join 的 filter,最后再输出结果。这个时候,整个数据可以看到,已经尽可能的去并行,不会因为比如说小表数据没读到,就阻碍大表拿数据。当然,这个中间还有个同步的问 …"}, {"url": "https://pingcap.com/meetup/meetup-2016-11-15/", "title": "MPP and SMP in TiDB", "content": " MPP and SMP in TiDB 原创2016-11-15 申砾 PingCAP PingCAPPingCAP ![]() 微信号pingcap2015功能介绍PingCAP 专注于新型"}, {"url": "https://pingcap.com/blog/2016-11-15-Travelling-Back-in-Time-and-Reclaiming-the-Lost-Treasures/", "title": "Travelling Back in Time and Reclaiming the Lost Treasures", "content": " About the History Read feature in TiDB Data is the core and is a matter of life and death for every business. So ensuring the data safety is the top priority of every database. From a macro point of view, the safety of data is not only about whether a database is stable enough that no data is lost, but also about whether a sufficient and convenient solution is in place when data is lost because of the business or human errors, for example, to solve the anti-cheat problem in the game industry or to meet the audit requirements in the financing business. If a proper mechanism is enabled in the database level, it will reduce the workload and the complexity of business development significantly.The traditional solution is to backup data in full volume periodically, in days or daily. These backups are to restore the data in case of accidents. But to restore data using backups is very costly because all the data after the backup time will be lost, which might be the last thing you want. In addition, the storage and computing overhead for full backups is no small cost for every company.But this kind of situation cannot be avoided completely. To err is human. For every fast iterative business, it is impossible for the code of the application to be fully tested. Fault data might be written because of the bug in the application logic or the activity of malicious users. When the issue is spotted, you can roll back the application to the earlier version immediately, but the fault data remains in the database.What can do you when things like this happen? The only thing you know is that the data is faulted. But what is the correct data? You have no idea. It would be great if you could go back in time and find the lost data.The History Read feature of TiDB supports reading the history versions and is specially tailored for this requirement and scenario. All the data before the faulted version can be accessed and therefore the damage can be minimized.How to use the History Read feature? It is very easy to use this feature. You can simply use the following Set statement:set @@tidb_snapshot = "2016-10-10 09:30:11.123" The name of the session variable is tidb_snapshot which is defined in TiDB. The value is a time string with precision of milliseconds. When this statement is executed, the data read by all the read requests issued from this client is at the set time and the write operation is not allowed because the history cannot be changed. If you want to exit the History Read mode and read the latest data, you can just execute the following Set statement:set @@tidb_snapshot = "" which sets the tidb_snapshot variable to be an empty string.It doesn’t matter even if there are Schema changes after the set time in history because TiDB will use the Schema of the set time in history for the SQL request.Comparing the History Read feature in TiDB with the similar features in other databases There is no such feature in MySQL. In other databases such as Oracle and PostgreSQL, this feature is called Temporal Table, which is a SQL standard. To use this feature, you need to use the special table creating grammar for the Temporal Table which has two more fields than the original table. The two extra fields are to store the valid time and are maintained by the system. When the original table is updated, the system inserts the data of the old version into the Temporal Table. When you need to retrieve the history data, you can use a special grammar to set the time in history and get the result.Compared with the similar features of other databases, the History Read feature in TiDB has the following advantages: - It is supported by default in the system. If it is not supported by default, usually we won’t create a Temporal Table on purpose. But when we actually need it, it might not there. - It is very easy to use. No extra table or special grammar is needed. - It provides a global snapshot instead of a view from individual table. - Even if operations like Drop Table and Drop Database are executed, old data can still be retrieved in TiDB.The implementation of the History Read feature in TiDB Multi-version Concurrency Control (MVCC) Note: The implementation in this document is a simplified version and does not involve the distributed transactions. The implementation in TiDB is more complex than this. We will provide the detailed implementation of the transaction model later. Stay tuned!TiDB is on top of TiKV. The storage engine at the bottom level for TiKV is RocksDB where data is stored in Key-Value pairs. A row in a table in the SQL layer needs to be encoded twice to get the final Key in RocksDB: The Key after the first-pass encoding includes table ID and record ID. Using this Key can locate this specific row. Based on the Key from the first encoding, the final Key after the second-pass encoding includes a globally monotone increasing timestamp which is the time it is written. All the Keys carry a globally unique timestamp, which means that the new writes cannot override the old ones. Even for the delete operations, the write is just a mark to delete, but the actual data is still there. The multiple versions of the data in the same row co-exist in RocksDB according to the time sequence.When a Read transaction starts, a timestamp is allocated from the time allocator of the cluster. For this transaction, all the data written before this timestamp is visible while the data written after the transaction is invisible. In this way, the transaction can guarantee the Repeatable Read isolation level.When a Read request is issued from TiDB to TiKV, the timestamp is carried by the request. When TiKV gets the timestamp, it compares the timestamp and the time of the different versions of the row to find the latest version that is no later than this timestamp and returns it to TiDB.This is the simplified version of how TiDB implements MVCC.Originally, TiDB reads data based on the historical time which is automatically obtained by the system as a transaction starts. Setting the tidb_snapshot session variable is merely enabling TiDB to read data using the time specified by the user to replace the time automatically obtained by the system.You might wonder that if all the versions are kept, will the space occupied by the data inflate indefinitely?This leads to how TiDB collects garbage.The Garbage Collection (GC) mechanism in TiDB TiDB collects garbage periodically and removes the data versions that are too old from RockDB. Therefore, the space occupied by the data won’t inflate indefinitely.Then how old will the data to be removed? The expiration time of the GC is controlled by configuring a parameter. You can set it to be 10 mins, 1 hour, 1 day or never. Therefore the History Read feature of TiDB is limited and only the data after the GC expiration time can be read. You might want to set the time to be as long as possible but this is not without any cost. The longer the expiration time, the more space will be occupied, and the Read performance will degrade. It depends on the business type and requirements as to how to configure the expiration time. If the data is very important and data safety is the top priority or there are very few data updates, it is recommended to set the expiration time to be long; if the data is not very important and the data updates are very frequent, it is recommended to set the expiration time to be short.Summary The History Read feature of TiDB exposes the native TiDB reading mechanism and allows users to use it in the simplest way. We hope this feature can help users create more values."}, {"url": "https://pingcap.com/weekly/2016-11-14-tidb-weekly/", "title": "Weekly update (November 07 ~ November 13, 2016)", "content": " Last week, we landed 25 PRs in the TiDB repositories and 5 PRs in the TiDB docs repositories.Weekly update in TiDB Added Support the Alter table modify column statement. Support the Drop view statement: parsed but ignored. Add metrics for the transaction size. A tool for testing the SQL performance. Fixed A bug in the show create table statement. A few bugs in optimizer: #1962, #1963, #1966, #1975, #1977. Improved Improve the cost-based optimizer. Document change Adjust the README structure to include the document list Add the following new guides: Data migration from MySQL to TiDB Overview of the monitoring framework Monitoring a TiDB cluster Compatibility with MySQL Weekly update in TiKV Last week, we landed 23 PRs in the TiKV repositories.Added Resolve locks in batches to avoid generating a huge Raft log when a transaction rolls back. Add applying snapshot count to enhance the Placement Driver (PD) balance, with PR 1278, 381. Check the system configuration before startup. Fixed Add a start flag to check whether a balance starts or not to fix issue 343. Fix the data inconsistency bug when applying snapshot and committed logs at same time. Improved Refactor cache to access easily, with PR 359, 379. Update RocksDB config to let user configure it more easily. Slow down Raft heartbeat and election interval to reduce the system pressure. Check the PD list to ensure the address has a valid format. Improve tikv-ctl, with PR 1273, 1281, 1295. "}, {"url": "https://pingcap.com/meetup/meetup-2016-11-12/", "title": "PingCAP 第 29 期 NewSQL Meetup", "content": " PingCAP 第 29 期 NewSQL Meetup 2016-11-12 王振涛&张金鹏 PingCAP PingCAPPingCAP ![]() 微信号pingcap2015功能介绍PingCAP 专注于新型分布式数据库的研发,是知名开源数据库 TiDB (GitHub 总计10000+ stars ) 背后的团队,总部设在北京,是国内第一家开源的新型分布式关系型数据库公司、国内领先的大数据技术和解决方案提供商。NewSQL Meetup今天是 PingCAP 第 29 期 Meetup,主题是映客服务端架构师王振涛分享的《映客直播服务端架构优化之路》以及张金鹏分享的《MySQL 与 TiDB 的事务机制》。▌ ****Topic 1:映客直播服务端架构优化之路Lecture:王振涛,南开大学计算机硕士毕业,曾先后供职于腾讯、搜狗等互联网公司,拥有多年的服务端研发、面向服务体系结构设计经验,专注于解决海量数据存储和计算带来的分布式、高并发、强一致性等技术难题和挑战。2016 年初加入映客直播,担任服务端架构师,主要负责映客基础平台架构设计、评审和用户体系的研发工作,经历了映客业务快速发展、构建高可用大容量基础服务体系的过程,对分布式计算、微服务、分布式数据库架构、高可用高并发系统设计等方面都有较深刻的理解和实践经验。Content:1、介绍了映客服务端架构演进历程;2、关于服务端技术选型的探索和思考;3、移动直播典型应用场景分析。▌ ****Topic 2:MySQL 与 TiDB 的事务机制Lecture:张金鹏,PingCAP 核心成员,前百度资深研发工程师/京东数据库专家,《MariaDB 原理和实现》作者。Content:在 MySQL 的 InnoDB 存储引擎中,进行写操作时,会将数据修改前的状态纪录在 Undo Log 中,一旦事务,失败利用 Undo Log 来进行回滚,保证事务的原子性。同时 InnoDB 利用 Undo Log 实现了多版本并发控制,InnoDB 的读取操作是不加锁的,事务只能读取到事务开始时已提交的纪录。由于 MySQL 是单机数据库,所有很方便的纪录所有活跃的事务 ID,Purge 线程根据当前活跃的事务情况来定期清理 Undo Log 中过期版本的数据。InnoDB 的事务支持 read uncommitted、read committed、repeatable read、serializable 四种事务隔离级别,InnoDB 通过 next-key lock 来解决 repeatable read 隔离级别下的幻读现象。由于 TiDB 是分布式的数据库,情况变的复杂一些。TiDB 的事务参考的是 Google 的 percolator 模型,通过 PD 获取单调递增的时间戳来作为事务编号。TiDB 的写分为 prewrite 和 commit 两个阶段。如果一个事务写入多行,会选取一行作为 primary row,当 prewrite 阶段成功后会 commit primary row,其他 row 根据 primary row 的提交结果选择提交或者回滚,以保证整个事务的原子性。TiDB 同时实现了 SI 和 SSI 两种事务隔离级别。特别鸣谢:场地赞助-泰利驿站PingCAP Meetup"}, {"url": "https://pingcap.com/blog-cn/distributed-system-test-2/", "title": "分布式系统测试那些事儿 - 错误注入", "content": " 本话题系列文章整理自 PingCAP Infra Meetup 第 26 期刘奇分享的《深度探索分布式系统测试》议题现场实录。文章较长,为方便大家阅读,会分为上中下三篇,本文为中篇。 -接上篇- 当然测试可能会让你代码变得没有那么漂亮,举个例子:这是知名的 Kubernetes 的代码,就是说它有一个 DaemonSetcontroller,这 controller 里面注入了三个测试点,比如这个地方注入了一个 handler ,你可以认为所有的注入都是 interface。比如说你写一个简单的 1+1=2 的程序,假设我们写一个计算器,这个计算器的功能就是求和,那这就很难注入错误。所以你必须要在你正确的代码里面去注入测试逻辑。再比如别人 call 你的这个 add 的 function,然后你是不是有一个 error?这个 error 的问题是它可能永远不会返回一个 error,所以你必须要人肉的注进去,然后看应用程序是不是正确的行为。说完了加法,再说我们做一个除法。除法大家知道可能有处理异常,那上面是不是能正常处理呢?上面没有,上面写着一个比如说 6 ÷ 3,然后写了一个 test,coverage 100%,但是一个除零异常,系统就崩掉了,所以这时候就需要去注入错误。大名鼎鼎的 Kubernetes 为了测试各种异常逻辑也采用类似的方式,这个结构体不算长,大概是十几个成员,然后里面就注入了三个点,可以在里面注入错误。那么在设计 TiDB 的时候,我们当时是怎么考虑 test 这个事情的?首先一个百万级的 test 不可能由人肉来写,也就是说你如果重新定义一个自己的所谓的 SQL 语法,或者一个 query language,那这个时候你需要构建百万级的 test,即使全公司去写,写个两年都不够,所以这个事情显然是不靠谱的。但是除非说我的 query language 特别简单,比如像 MongoDB 早期的那种,那我一个“大于多少”的这种,或者 equal 这种条件查询特别简单的,那你确实是不需要构建这种百万级的 test。但是如果做一个 SQL 的 database 的话,那是需要构建这种非常非常复杂的 test 的。这时候这个 test 又不能全公司的人写个两年,对吧?所以有什么好办法呢?MySQL 兼容的各种系统都是可以用来 test 的,所以我们当时兼容 MySQL 协议,那意味着我们能够取得大量的 MySQL test。不知道有没有人统计过 MySQL 有多少个 test,产品级的 test 很吓人的,千万级。然后还有很多 ORM, 支持 MySQL 的各种应用都有自己的测试。大家知道,每个语言都会 build 自己的 ORM,然后甚至是一个语言的 ORM 都有好几个。比如说对于 MySQL 可能有排第一的、排第二的,那我们可以把这些全拿过来用来测试我们的系统。但对于有些应用程序而言,这时候就比较坑了。就是一个应用程序你得把它 setup 起来,然后操作这个应用程序,比如 WordPress,而后再看那个结果。所以这时候我们为了避免刚才人肉去测试,我们做了一个程序来自动化的 Record—Replay。就是你在首次运行的时候,我们会记录它所有执行的 SQL 语句,那下一次我再需要重新运行这个程序的时候怎么办?我不需要运行这个程序了,我不需要起来了,我只需要把它前面记录的 SQL record 重新回放一遍,就相当于是我模拟了程序的整个行为。所以我们在这部分是这样做的自动化。那么刚刚说了那么多,实际上做的是什么?实际上做的都是正确路径的测试,那几百万个 test 也都是做的正确的路径测试,但是错误的路径怎么办?很典型的一个例子就是怎么做 Fault injection。硬件比较简单粗暴的模拟网络故障可以拔网线,比如说测网络的时候可以把这个网线拔掉,但是这个做法是极其低效的,而且它是没法 scale 的,因为这个需要人的参与。然后还有比如说 CPU,这个 CPU 的损坏概率其实也挺高的,特别是对于过保了的机器。然后还有磁盘,磁盘大概是三年百分之八点几的损坏率,这是一篇论文里面给出的数据。我记得 Google 好像之前给过一个数据,就是 CPU、网卡还有磁盘在多少年之内的损坏率大概是什么样的。还有一个大家不太关注的就是时钟。先前,我们发现系统时钟是有回跳的,然后我们果断在程序里面加个监测模块,一旦系统时钟回跳,我们马上把这个检测出来。当然我们最初监测出这个东西的时候,用户是觉得不可能吧,时钟还会有回跳?我说没关系,先把我们程序开了监测一下,然后过段时间就检测到,系统时钟最近回跳了。所以怎么配 NTP 很重要。然后还有更多的,比如说文件系统,大家有没有考虑过你写磁盘的时候,磁盘出错会怎么办?好,写磁盘的时候没有出错,成功了,然后磁盘一个扇区坏了,读出来的数据是损坏的,怎么办?大家有没有 checksum ?没有 checksum 然后我们直接用了这个数据,然后直接给用户返回了,这个时候可能是很要命的。如果这个数据刚好存的是个元数据,而元数据又指向别的数据,然后你又根据元数据的信息去写入另外一份数据,那就更要命了,可能数据被进一步破坏了。所以比较好的做法是什么? Fault injection Hardware disk error network card cpu clock Software file system network & protocol Simulate everything 模拟一切东西。就是磁盘是模拟的,网络是模拟的,那我们可以监控它,你可以在任何时间、任何的场景下去注入各种错误,你可以注入任何你想要的错误。比如说你写一个磁盘,我就告诉你磁盘满了,我告诉你磁盘坏了,然后我可以让你 hang 住,比如 sleep 五十几秒。我们确实在云上面出现过这种情况,就是我们一次写入,然后被 hang 了为 53 秒,最后才写进去,那肯定是网络磁盘,对吧?这种事情其实是很吓人的,但是肯定没有人会想说我一次磁盘写入然后要耗掉 53 秒,但是当 53 秒出现的时候,整个程序的行为是什么?TiDB 里面用了大量的 Raft,所以当时出现一个情况就是 53 秒,然后所有的机器就开始选举了,说这肯定是哪儿不对,重新把 leader 都选出来了,这时候卡 53 秒的哥们说“我写完了”,然后整个系统状态就做了一次全新的迁移。这种错误注入的好处是什么?就是知道当出错的时候,你的错误能严重到什么程度,这个事情很重要,就是 predictable,整个系统要可预测的。如果没有做错误路径的测试,那很简单的一个问题,现在假设走到其中一条错误路径了,整个系统行为是什么?这一点不知道是很吓人的。你不知道是否可能破坏数据;还是业务那边会 block 住;还是业务那边会 retry?以前我遇到一个问题很有意思,当时我们在做一个消息系统,有大量连接会连这个,一个单机大概是连八十万左右的连接,就是做消息推送。然后我记得,当时的 swap 分区开了,开了是什么概念?当你有更多连接打进来的时候,然后你内存要爆了对吧?内存爆的话会自动启用 swap 分区,但一旦你启用 swap 分区,那你系统就卡成狗了,外面用户断连之后他就失败了,他得重连,但是重连到你正常程序能响应,可能又需要三十秒,然后那个用户肯定觉得超时了,又切断连接又重连,就造成一个什么状态呢?就是系统永远在重试,永远没有一次成功。那这个行为是不是可以预测?这种错误当时有没有做很好的测试?这都是非常重要的一些教训。硬件测试以前的办法是这样的(Joke):假设我一个磁盘坏了,假设我一个机器挂了,还有一个假设它不一定坏了也不一定挂了,比如说它着火了会怎么样?前两个月吧,是瑞士还是哪个地方的一个银行做测试,那哥们也挺逗的,人肉对着服务器这样吹气,来看监控数据那个变化,然后那边马上开始报警。这还只是吹气而已,那如果更复杂的测试,比如说你着火从哪个地方开始烧,先烧到硬盘、或者先烧到网卡,这个结果可能也是不一样的。当然这个成本很高,然后也不是能 scale 的一种方案,同时也很难去复制。这不仅仅是硬件的监控,也可以认为是做错误的注入。比如说一个集群我现在烧掉一台会怎么样?着火了,很典型的嘛,虽然重要的机房都会有这种防火、防水等各种的策略,但是真的着火的时候怎么办?当然你不能真去烧,这一烧可能就不止坏一台机器了,但我们需要使用 Fault injection 来模拟。我介绍一下到底什么是 Fault injection。给一个直观的例子,大家知道所有人都用过 Unix 或者 Linux 的系统,大家都知道,很多人习惯打开这个系统第一行命令就是 ls 来列出目录里面的文件,但是大家有没有想过一个有意思的问题,如果你要测试 ls 命令实现的正确性,怎么测?如果没有源代码,这个系统该怎么测?如果把它当成一黑盒这个系统该怎么测?如果你 ls 的时候磁盘出现错误怎么办?如果读取一个扇区读取失败会怎么办?这个是一个很好玩的工具,推荐大家去玩一下。就是当你还没有做更深入的测试之前,可以先去理解一下到底什么是 Fault injection,你就可以体验到它的强大,一会我们用它来找个 MySQL 的 bug。libfiu - Fault injection in userspaceIt can be used to perform fault injection in the POSIX API without having to modify the application’s source code, that can help to test failure handling in an easy and reproducible way.那这个东西主要是用来 Hook 这些 API 的,它很重要的一点就是它提供了一个 library ,这个 library 也可以嵌到你的程序里面去 hook 那些 API。就比如说你去读文件的时候,它可以给你返回这个文件不存在,可以给你返回磁盘错误等等。最重要的是,它是可以重来的。举一个例子,正常来讲我们敲 ls 命令的时候,肯定是能够把当前的目录显示出来。这个程序干的是什么呢?就是 run,指定一个参数,现在是要有一个 enable_random,就是后面所有的对于 IO 下面这些 API 的操作,有 5% 的失败率。那第一次是运气比较好,没有遇到失败,所以我们把整个目录列出来了。然后我们重新再跑一次,这时候它告诉我有一次读取失败了,就是它 read 这个 directory 的时候,遇到一个 Bad file descriptor,这时候可以看到,列出来的文件就比上面的要少了,因为有一条路径让它失败了。接下来,我们进一步再跑,发现刚列出来一个目录,然后下次读取就出错了。然后后面再跑一次的时候,这次运气也比较好,把这整个都列出来了,这个还只是模拟的 5% 的失败率。就是有 5% 的概率你去 read、去 open 的时候会失败,那么这时候可以看到 ls 命令的行为还是很 stable 的,就是没有什么常见的 segment fault 这些。大家可能会说这个还不太好玩,也就是找找 ls 命令是否有 bug 嘛,那我们复现 MySQL bug 玩一下。Bug #76020InnoDB does not report filename in I/O error message for readsfiu-run -x -c “enable_random name=posix/io/*,probability=0.05” bin/mysqld –basedir=/data/ushastry/server/mysql-5.6.24 –datadir=/data/ushastry/server/mysql-5.6.24⁄76020 –core-file –socket=/tmp/mysql_ushastry.sock –port=150002015-05-20 19:12:07 31030 [ERROR] InnoDB: Error in system call pread(). The operating system error number is 5.2015-05-20 19:12:07 7f7986efc720 InnoDB: Operating system error number 5 in a file operation.InnoDB: Error number 5 means ‘Input/output error’.2015-05-20 19:12:07 31030 [ERROR] InnoDB: File (unknown):‘read’ returned OS error 105. Cannot continue operation这是用 libfiu 找到的 MySQL 的一个 bug,这个 bug 是这样的,bug 编号是 76020,是说 InnoDB 在出错的时候没有报文件名,那用户给你报了错,你这时候就傻了对吧?这个到底是什么地方出错了呢?然后这个地方它怎么出来的?你可以看到它还是用我们刚才提到的 fiu-run,然后来模拟,模拟的失败概率还是这么多,可以看到,我们的参数一个没变,这时把 MySQL 启动,然后跑一下,出现了,可以看到 InnoDB 在报的时候确实没有报 filename ,File : ‘read’ returned OS error,然后这边是 auto error,你不知道是哪一个文件名。换一个思路来看,假设没有这个东西,你复现这个 bug 的成本是什么?大家可以想想,如果没有这个东西,这个 bug 应该怎么复现,怎么让 MySQL 读取的东西出错?正常路径下你让它读取出错太困难了,可能好多年没出现过。这时我们进一步再放大一下,这个在 5.7 里面还有,也是在 MySQL 里面很可能有十几年大家都没怎么遇到过的,但这种 bug 在这个工具的辅助下,马上就能出来。所以 Fault injection 它带来了很重要的一个好处就是让一个东西可以变得更加容易重现。这个还是模拟的 5% 的概率。这个例子是我昨天晚上做的,就是我要给大家一个直观的理解,但是分布式系统里面错误注入比这个要复杂。而且如果你遇到一个错误十年都没出现,你是不是太孤独了? 这个电影大家可能还有印象,威尔史密斯主演的,全世界就一个人活着,唯一的伙伴是一条狗。实际上不是的,比我们痛苦的人大把的存在着。举 Netflix 的一个例子,下图是 Netflix 的系统。他们在 2014 年 10 月份的时候写了一篇博客,叫《 Failure Injection Testing 》,是讲他们整个系统怎么做错误注入,然后他们的这个说法是 Internet Scale,就是整个多数据中心互联网的这个级别。大家可能记得 Spanner 刚出来的时候他们叫做 Global Scale,然后这地方可以看到,蓝色是注射点,黑色的是网络调用,就是所有这些请求在这些情况下面,所有这些蓝色的框框都有可能出错。大家可以想一想,在 Microservice 系统上,一个业务调用可能涉及到几十个系统的调用,如果其中一个失败了会怎么样?如果是第一次第一个失败,第二次第二个失败,第三次第三个失败是怎么样的?有没有系统做过这样的测试?有没有系统在自己的程序里面去很好的验证过是不是每一个可以预期的错误都是可预测的,这个变得非常的重要。这里以 cache 为例,就说每一次访问 Cassandra 的时候可能出错,那么也就给了我们一个错误的注入点。然后我们谈谈 OpenStack.OpenStack fault-injection library:https://pypi.python.org/pypi/os-faults/0.1.2大名鼎鼎的 OpenStack 其实也有一个 Failure Injection Library,然后我把这个例子也贴到这里,大家有兴趣可以看一下这个 OpenStack 的 Failure Injection。这以前大家可能不太关注,其实大家在这一点上都很痛苦, OpenStack 现在还有一堆人在骂,说稳定性太差了,其实他们已经很努力了。但是整个系统确实是做的异乎寻常的复杂,因为组件太多。如果你出错的点特别多,那可能会带来另外一个问题,就是出错的点之间还能组合,就是先 A 出错,再 B 出错,或者 AB 都出错,这也就几种情况,还好。那你要是有十万个错误的点,这个组合怎么弄?当然现在还有新的论文在研究这个,2015 年的时候好像有一篇论文,讲的就是会探测你的程序的路径,然后在对应的路径下面去注入错误。再来说 Jepsen.Jepsen: Distributed Systems Safety Analysis大家所有听过的知名的开源分布式系统基本上都被它找出来过 bug。但是在这之前大家都觉得自己还是很 OK 的,我们的系统还是比较稳定的,所以当新的这个工具或者新的方法出现的时候,就比如说我刚才提到的那篇能够线性 Scale 的去查错的那篇论文,那个到时候查错力就很惊人了,因为它能够自动帮你探测。另外我介绍一个工具 Namazu,后面讲,它也很强大。这里先说Jepsen, 这货算是重型武器了,无论是 ZooKeeper、MongoDB 以及 Redis 等等,所有这些全部都被找出了 bug,现在用的所有数据库都是它找出的 bug,最大的问题是小众语言 closure 编写的,扩展起来有点麻烦。我先说说 Jepsen 的基本原理,一个典型使用 Jepsen 的测试通过会在一个 control node上面运行相关的 clojure 程序,control node 会使用 ssh 登陆到相关的系统 node(jepsen 叫做 db node)进行一些测试操作。当我们的分布式系统启动起来之后,control node 会启动很多进程,每一个进程都能使用特定的 client 访问到我们的分布式系统。一个 generator 为每一个进程生成一系列的操作,比如 get/set/cas,让其执行。每一个操作都会被记录到 history 里面。在执行操作的同时,另一个 nemesis 进程会尝试去破坏这个分布式系统,譬如使用 iptable 断开网络连接等,当所有操作执行完毕之后,jepsen 会使用一个 checker 来分析验证系统的行为是否符合预期。PingCAP 的首席架构师唐刘写过两篇文章介绍我们实际怎么用 Jepsen 来测试 TiDB,大家可以搜索一下,我这里就不详细展开了。 FoundationDB It is difficult to be deterministic Random Disk Size File Length Time Multithread FoundationDB 这就是前辈了,2015 …"}, {"url": "https://pingcap.com/meetup/meetup-2016-11-10/", "title": "分布式系统测试那些事儿——错误注入", "content": ""}, {"url": "https://pingcap.com/blog/2016-11-09-Deep-Dive-into-TiKV/", "title": "A Deep Dive into TiKV", "content": " Table of Content About TiKV Architecture Protocol Raft Placement Driver (PD) Transaction Coprocessor Key processes analysis Key-Value operation Membership Change Split About TiKV TiKV (The pronunciation is: /‘taɪkeɪvi:/ tai-K-V, etymology: titanium) is a distributed Key-Value database which is based on the design of Google Spanner, F1, and HBase, but it is much simpler without dependency on any distributed file system.Architecture Placement Driver (PD): PD is the brain of the TiKV system which manages the metadata about Nodes, Stores, Regions mapping, and makes decisions for data placement and load balancing. PD periodically checks replication constraints to balance load and data automatically. Node: A physical node in the cluster. Within each node, there are one or more Stores. Within each Store, there are many Regions. Store: There is a RocksDB within each Store and it stores data in local disks. Region: Region is the basic unit of Key-Value data movement and corresponds to a data range in a Store. Each Region is replicated to multiple Nodes. These multiple replicas form a Raft group. A replica of a Region is called a Peer. Protocol TiKV uses the Protocol Buffer protocol for interactions among different components. Because Rust doesn’t support gRPC for the time being, we use our own protocol in the following format:Message: Header + Payload Header: | 0xdaf4(2 bytes magic value) | 0x01(version 2 bytes) | msg_len(4 bytes) | msg_id(8 bytes) | The data of Protocol Buffer is stored in the Payload part of the message. At the Network level, we will first read the 16-byte Header. According to the message length (msg_len) information in the Header, we calculate the actual length of the message, and then read the corresponding data and decode it.The interaction protocol of TiKV is in the kvproto project and the protocol to support push-down is in the tipb project. Here, let’s focused on the kvproto project only.About the protocol files in the kvproto project: msgpb.proto: All the protocol interactions are in the same message structure. When a message is received, we will handle the message according to its MessageType. metapb.proto: To define the public metadata for Store, Region, Peer, etc. raftpb.proto: For the internal use of Raft. It is ported from etcd and needs to be consistent with etcd. raft_serverpb.proto: For the interactions among the Raft nodes. raft_cmdpb.proto: The actual command executed when Raft applies. pdpb.proto: The protocol for the interaction between TiKV and PD. kvrpcpb.proto: The Key-Value protocol that supports transactions. mvccpb.proto: For internal Multi-Version Concurrency Control (MVCC). coprocessor.proto: To support the Push-Down operations. There are following ways for external applications to connect to TiKV: For the simple Key-Value features only, implement raft_cmdpb.proto. For the Transactional Key-Value features, implement kvrpcpb.proto. For the Push-Down features, implement coprocessor.proto. See tipb for detailed push-down protocol. Back to the TopRaft TiKV uses the Raft algorithm to ensure the data consistency in the distributed systems. For more information, see https://raft.github.io/.The Raft in TiKV is completely migrated from etcd. We chose etcd Raft because it is very simple to implement, very easy to migrate and it is production proven.The Raft implementation in TiKV can be used independently. You can apply it in your project directly.See the following details about how to use Raft: Define its own storage and implement the Raft Storage trait. See the following Storage trait interface: // initial_state returns the information about HardState and ConfState in Storage fn initial_state(&self) -> Result<RaftState>; // return the log entries in the [low, high] range fn entries(&self, low: u64, high: u64, max_size: u64) -> Result<Vec<Entry>>; // get the term of the log entry according to the corresponding log index fn term(&self, idx: u64) -> Result<u64>; // get the index from the first log entry at the current position fn first_index(&self) -> Result<u64>; // get the index from the last log entry at the current position fn last_index(&self) -> Result<u64>; // generate a current snapshot fn snapshot(&self) -> Result<Snapshot>; Create a raw node object and pass the corresponding configuration and customized storage instance to the object. About the configuration, we need to pay attention to election_tick and heartbeat_tick. Some of the Raft logics step by periodical ticks. For every Tick, the Leader will decide if the frequency of the heartbeat elapsing exceeds the frequency of the heartbeat_tick. If it does, the Leader will send heartbeats to the Followers and reset the elapse. For a Follower, if the frequency of the election elapsing exceeds the frequency of the election_tick, the Follower will initiate an election. After a raw node is created, the tick interface of the raw node will be called periodically (like every 100ms) and drives the internal Raft Step function. If data is to be written by Raft, the Propose interface is called directly. The parameters of the Propose interface is an arbitrary binary data which means that Raft doesn’t care the exact data content that is replicated by it. It is completely up to the external logics as how to handle the data. If it is to process the membership changes, the propose_conf_change interface of the raw node can be called to send a ConfChange object to add/remove a certain node. After the functions in the raw node like Tick and Propose of the raw node are called, Raft will initiate a Ready state. Here are some details of the Ready state:There are three parts in the Ready state: The part that needs to be stored in Raft storage, which are entries, hard state and snapshot. The part that needs to be sent to other Raft nodes, which are messages. The part that needs to be applied to other state machines, which are committed_entries. After handling the Ready status, the Advance function needs be called to inform Raft of the next Ready process.In TiKV, Raft is used through mio as in the following process: Register a base Raft tick timer (usually 100ms). Every time the timer timeouts, the Tick of the raw node is called and the timer is re-registered. Receive the external commands through the notify function in mio and call the Propose or the propose_conf_change interface. Decide if a Raft is ready in the mio tick callback (Note: The mio tick is called at the end of each event loop, which is different from the Raft tick.). If it is ready, proceed with the Ready process. In the descriptions above, we covered how to use one Raft only. But in TiKV, we have multiple Raft groups. These Raft groups are independent to each other and therefore can be processed following the same approach.In TiKV, each Raft group corresponds to a Region. At the very beginning, there is only one Region in TiKV which is in charge of the range (-inf, +inf). As more data comes in and the Region reaches its threshold (64 MB currently), the Region is split into two Regions. Because all the data in TiKV are sorted according to the key, it is very convenient to choose a Split Key to split the Region. See Split for the detailed splitting process.Of course, where there is Split, there is Merge. If there are very few data in two adjacent Regions, these two regions can merge to one big Region. Region Merge is in the TiKV roadmap but it is not implemented yet.Back to the TopPlacement Driver Placement Driver (PD) is in charge of the managing and scheduling of the whole TiKV cluster. It is a central service and we have to ensure that it is highly available and stable.The first issue to be resolved is the single point of failure of PD. Our solution is to start multiple PD servers. These servers elect a Leader through the election mechanism in etcd and the leader provides services to the outside. If the leader is …"}, {"url": "https://pingcap.com/weekly/2016-11-07-tidb-weekly/", "title": "Weekly update (October 31 ~ November 06, 2016)", "content": " Weekly update (October 31 ~ November 06, 2016) Last week, we landed 42 PRs in the TiDB repositories and 29 PRs in the TiKV repositories.New release TiDB Beta 4 Weekly update in TiDB Added The aggregation info to the explain statement. Support the show processlist syntax. TiDB supports mydumper now. Support the show create database statement. Support the buildin function from_unixtime. Push down the aggregation operator to the position before join. Get cluster ID from Placement Driver. Fixed A bug in parser that misses the recognize identifier with leading digits. A bug in the load data command. Improved The performance of the DropTable statement. The performance of the AddIndex statement. The query metrics. Weekly update in TiKV Added Multiversion concurrency control (MVCC) support for tikv-ctl. Support -v/--version to print the version information. Metrics for MVCC key versions and deleted key versions. Use random cluster ID to bootstrap clusters to avoid wrong joining cluster by the users, with PR 370, 1257 Fixed Panic directly if the RocksDB writes fail to fix 1262. Add the start time for store monitor to fix 1207. Return the ‘no leader’ error to avoid panic when calling the GetLeader API with no leader. Improved Skip values for scan. Make cache code cleaner, with PR 365, 366, 367. Allow liner reverse seek in the lock column family. Separate compaction to a different thread worker. Avoid filling block cache when scanning. Include the snapshot size in the used_size store. Dump the RocksDB statistics with the SIGUSR1 signal. "}, {"url": "https://pingcap.com/meetup/meetup-2016-11-05/", "title": "PingCAP 第 28 期 NewSQL Meetup", "content": " PingCAP 第 28 期 NewSQL Meetup 2016-11-05 时延军&韩飞 PingCAP PingCAPPingCAP ![]() 微信号pingcap2015功能介绍PingCAP 专注于新型分布式数据库的研发,是知名开源数据库 TiDB (GitHub 总计10000+ stars ) 背后的团队,总部设在北京,是国内第一家开源的新型分布式关系型数据库公司、国内领先的大数据技术和解决方案提供商。NewSQL Meetup今天是 PingCAP 第28 期 Meetup,主题是 TalkingData 数据经理时延军分享的《Spark 架构设计要点剖析》以及韩飞分享的《Performing group-by before join》。▌ ****Topic 1:Spark 架构设计要点剖析Lecture:时延军,TalkingData 数据经理,负责领域工程数据平台架构和研发,曾在 COMODO 中国负责基础数据平台建设,在车语传媒考拉 FM 负责后端数据平台架构(支持离线+实时分析处理)。推崇工程师文化,热爱开源,乐于分享,兴趣广泛,熟悉大数据技术生态,擅长软件系统架构、分布式计算系统设计。Content:1、RDD 特性,RDD 是如何抽象数据集的;2、详解 Spark 基本架构;3、Spark 内部核心组件及其交互;4、逻辑执行计划与物理执行计划;5、Spark 资源管理与任务调度。▌ ****Topic2:Performing group-by before joinLecture:韩飞,PingCAP 研发工程师(PingCAP SQL 小王子),TiDB SQL Optimizer 主要作者,专注于 SQL 优化技术。前阿里云研发工程师,参与开发 ODPS SQL 查询优化器 Lot。Content:Efficient processing of aggregation queries is essential for decision support applications. This talk introduces a class of query trans-formations, called eager aggregation that allows a query optimizer to push group-by operations down the query tree. Eager aggregation partially pushes a group-by past a join.特别鸣谢:场地赞助-泰利驿站PingCAP Meetup"}, {"url": "https://pingcap.com/blog-cn/tidb-as-mysql-slave/", "title": "TiDB 作为 MySQL Slave 实现实时数据同步", "content": " 由于 TiDB 本身兼容绝大多数的 MySQL 语法,所以对于绝大多数业务来说,最安全的切换数据库方式就是将 TiDB 作为现有数据库的从库接在主 MySQL 库的后方,这样对业务方实现完全没有侵入性下使用 TiDB 对现有的业务进行备份,应对未来数据量或者并发量增长带来的单点故障风险,如需上线 TiDB,也只需要简单的将业务的主 MySQL 地址指向 TiDB 即可。下面我们详细介绍了如何将 MySQL 的数据迁移到 TiDB,并将 TiDB 作为 MySQL 的 Slave 进行数据同步。这里我们假定 MySQL 以及 TiDB 服务信息如下:+------------------+-------------+----------------------------------------+ | Name | Address | Port | User | Password | +------------------+-------------+----------------------------------------+ | MySQL | 127.0.0.1 | 3306 | root | | | TiDB | 127.0.0.1 | 4000 | root | | +------------------+-------------+--------+-----------+-------------------+ 使用 checker 进行 Schema 检查 在迁移之前,我们可以使用 TiDB 的 checker 工具,checker 是我们开发的一个小工具,用于检测目标 MySQL 库中的表的表结构是否支持无缝的迁移到 TiDB,TiDB 支持绝大多数的 MySQL 常用的原生数据类型,所以大多数情况 checker 的返回应该是 ok。如果 check 某个 table schema 失败,表明 TiDB 当前并不支持,我们不能对该 table 里面的数据进行迁移。checker 包含在 TiDB 工具集里面,我们可以直接下载。下载 TiDB 工具集 Linux # 下载 tool 压缩包 wget http://download.pingcap.org/tidb-tools-latest-linux-amd64.tar.gz wget http://download.pingcap.org/tidb-tools-latest-linux-amd64.sha256 # 检查文件完整性,返回 ok 则正确 sha256sum -c tidb-tools-latest-linux-amd64.sha256
# 解开压缩包 tar -xzf tidb-tools-latest-linux-amd64.tar.gz cd tidb-tools-latest-linux-amd64 使用 checker 检查的一个示范 在 MySQL 的 test database 里面创建几张表,并插入数据: USE test; CREATE TABLE t1 (id INT, age INT, PRIMARY KEY(id)) ENGINE=InnoDB; CREATE TABLE t2 (id INT, name VARCHAR(256), PRIMARY KEY(id)) ENGINE=InnoDB; INSERT INTO t1 VALUES (1, 1), (2, 2), (3, 3); INSERT INTO t2 VALUES (1, "a"), (2, "b"), (3, "c"); 使用 checker 检查 test database 里面所有的 table ./bin/checker -host 127.0.0.1 -port 3306 -user root test 2016/10/27 13:11:49 checker.go:48: [info] Checking database test 2016/10/27 13:11:49 main.go:37: [info] Database DSN: root:@tcp(127.0.0.1:3306)/test?charset=utf8 2016/10/27 13:11:49 checker.go:63: [info] Checking table t1 2016/10/27 13:11:49 checker.go:69: [info] Check table t1 succ 2016/10/27 13:11:49 checker.go:63: [info] Checking table t2 2016/10/27 13:11:49 checker.go:69: [info] Check table t2 succ 使用 checker 检查 test database 里面某一个 table 这里,假设我们只需要迁移 table t1。./bin/checker -host 127.0.0.1 -port 3306 -user root test t1 2016/10/27 13:13:56 checker.go:48: [info] Checking database test 2016/10/27 13:13:56 main.go:37: [info] Database DSN: root:@tcp(127.0.0.1:3306)/test?charset=utf8 2016/10/27 13:13:56 checker.go:63: [info] Checking table t1 2016/10/27 13:13:56 checker.go:69: [info] Check table t1 succ Check database succ! 一个无法迁移的 table 例子 我们在 MySQL 里面创建如下表:CREATE TABLE t_error ( c timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) ) ENGINE=InnoDB DEFAULT CHARSET=latin1; 使用 checker 进行检查,会报错,表明我们没法迁移 t_error 这张表。./bin/checker -host 127.0.0.1 -port 3306 -user root test t_error 2016/10/27 13:19:28 checker.go:48: [info] Checking database test 2016/10/27 13:19:28 main.go:37: [info] Database DSN: root:@tcp(127.0.0.1:3306)/test?charset=utf8 2016/10/27 13:19:28 checker.go:63: [info] Checking table t_error 2016/10/27 13:19:28 checker.go:67: [error] Check table t_error failed with err: line 1 column 56 near ") ON UPDATE CURRENT_TIMESTAMP(3) ) ENGINE=InnoDB DEFAULT CHARSET=latin1" github.com/pingcap/tidb/parser/yy_parser.go:111: github.com/pingcap/tidb/parser/yy_parser.go:124: /home/jenkins/workspace/WORKFLOW_TOOLS_BUILDING/go/src/github.com/pingcap/tidb-tools/checker/checker.go:122: parse CREATE TABLE `t_error` ( `c` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 error /home/jenkins/workspace/WORKFLOW_TOOLS_BUILDING/go/src/github.com/pingcap/tidb-tools/checker/checker.go:114: 2016/10/27 13:19:28 main.go:68: [error] Check database test with 1 errors and 0 warnings. 使用 mydumper/myloader 全量导入数据 我们使用 mydumper 从 MySQL 导出数据,然后用 myloader 将其导入到 TiDB 里面。注意,虽然我们也支持使用 MySQL 官方的 mysqldump 工具来进行数据的迁移工作,但相比于 mydumper/myloader,性能会慢很多,对于大量数据的迁移会花费很多时间,这里我们并不推荐。mydumper/myloader 是一个更强大的数据迁移工具,具体可以参考 https://github.com/maxbube/mydumper。下载 Binary Linux # 下载 mydumper 压缩包 wget http://download.pingcap.org/mydumper-linux-amd64.tar.gz wget http://download.pingcap.org/mydumper-linux-amd64.sha256 # 检查文件完整性,返回 ok 则正确 sha256sum -c mydumper-linux-amd64.sha256
# 解开压缩包 tar -xzf mydumper-linux-amd64.tar.gz cd mydumper-linux-amd64 从 MySQL 导出数据 我们使用 mydumper 从 MySQL 导出数据,如下:./bin/mydumper -h 127.0.0.1 -P 3306 -u root -t 16 -F 128 -B test -T t1,t2 -o ./var/test 上面,我们使用 -B test 表明是对 test 这个 database 操作,然后用 -T t1,t2 表明只导出 t1,t2 两张表。-t 16 表明使用 16 个线程去导出数据。-F 128 是将实际的 table 切分成多大的 chunk,这里就是 128MB 一个 chunk。注意:在阿里云一些需要 super privilege 的云上面,mydumper 需要加上 --no-locks 参数,否则会提示没有权限操作。给 TiDB 导入数据 我们使用 myloader 将之前导出的数据导入到 TiDB。./bin/myloader -h 127.0.0.1 -P 4000 -u root -t 16 -q 1 -d ./var/test 这里 -q 1 表明每个事务包含多少个 query,默认是 1000,我们这里使用 1 就可以了。导入成功之后,我们可以用 MySQL 官方客户端进入 TiDB,查看:mysql -h127.0.0.1 -P4000 -uroot mysql> show tables; +----------------+ | Tables_in_test | +----------------+ | t1 | | t2 | +----------------+ mysql> select * from t1; +----+------+ | id | age | +----+------+ | 1 | 1 | | 2 | 2 | | 3 | 3 | +----+------+ mysql> select * from t2; +----+------+ | id | name | +----+------+ | 1 | a | | 2 | b | | 3 | c | +----+------+ 使用 syncer 增量导入数据实现数据和 MySQL 实时同步 上面我们介绍了如何使用 mydumper/myloader 将 MySQL 的数据全量导入到 TiDB,但如果后续 MySQL 的数据有更新,我们仍然希望快速导入,使用全量的方式就不合适了。TiDB 提供 syncer 工具能方便的将 MySQL 的数据增量的导入到 TiDB 里面。syncer 也属于 TiDB 工具集,如何获取可以参考 下载 TiDB 工具集。假设我们之前已经使用 mydumper/myloader 导入了 t1 和 t2 两张表的一些数据,现在我们希望这两张表的任何更新,都是实时的同步到 TiDB 上面。MySQL 开启 binlog 在使用 syncer 之前,我们必须保证: MySQL 开启 binlog 功能,参考 Setting the Replication Master Configuration Binlog 格式必须使用 row format,这也是 MySQL 5.7 之后推荐的 binlog 格式,可以使用如下语句打开: SET GLOBAL binlog_format = ROW; 获取同步 position 我们通过 show master status 得到当前 binlog 的 position,syncer 的初始同步位置就是从这个地方开始。show master status; +------------------+----------+--------------+------------------+-------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +------------------+----------+--------------+------------------+-------------------+ | mysql-bin.000003 | 1280 | | | | +------------------+----------+--------------+------------------+-------------------+ 我们将 position 相关的信息保存到一个 syncer.meta 文件里面,用于 syncer 的同步:# cat syncer.meta binlog-name = "mysql-bin.000003" binlog-pos = 1280 注意:syncer.meta 只需要第一次使用的时候配置,后续 syncer 同步新的 binlog 之后会自动将其更新到最新的 position。启动 syncer syncer 的配置文件 config.toml:log-level = "info" server-id = 101 # meta 文件地址 meta = "./syncer.meta" worker-count = 1 batch = 1 pprof-addr = ":10081" [from] host = "127.0.0.1" user = "root" password = "" port = 3306 [to] host = "127.0.0.1" user = "root" password = "" port = 4000 启动 syncer:./bin/syncer -config config.toml 2016/10/27 15:22:01 binlogsyncer.go:226: [info] begin to sync binlog from position (mysql-bin.000003, 1280) 2016/10/27 15:22:01 binlogsyncer.go:130: [info] register slave for master server 127.0.0.1:3306 2016/10/27 15:22:01 binlogsyncer.go:552: [info] rotate to (mysql-bin.000003, 1280) 2016/10/27 15:22:01 syncer.go:549: [info] rotate binlog to (mysql-bin.000003, 1280) 在 MySQL 插入新的数据 INSERT INTO t1 VALUES (4, 4), (5, 5); 登录到 TiDB 查看:mysql -h127.0.0.1 -P4000 -uroot -p mysql> select * from t1; +----+------+ | id | age | +----+------+ | 1 | 1 | | 2 | 2 | | 3 | 3 | | 4 | 4 | | 5 | 5 | +----+------+ syncer 每隔 30s 会输出当前的同步统计,如下2016/10/27 15:22:31 syncer.go:668: [info] [syncer]total events = 1, insert = 1, update = 0, delete = 0, total tps = 0, recent tps = 0, binlog name = mysql-bin.000003, binlog pos = 1280. 2016/10/27 15:23:01 syncer.go:668: [info] [syncer]total events = 2, insert = 2, update = 0, delete = 0, total tps = 0, recent tps = 0, binlog name = mysql-bin.000003, binlog pos = 1538. 可以看到,使用 syncer,我们就能自动的将 MySQL 的更新同步到 TiDB。"}, {"url": "https://pingcap.com/meetup/meetup-2016-11-01/", "title": "How to write a good commit message", "content": " How to write a good commit message 原创2016-11-01 金坤 PingCAP PingCAPPingCAP ![]() 微信号pingcap2015功能介绍PingCAP 专注于新型"}, {"url": "https://pingcap.com/blog-cn/distributed-system-test-1/", "title": "分布式系统测试那些事儿 - 理念", "content": " 本话题系列文章整理自 PingCAP NewSQL Meetup 第 26 期刘奇分享的《深度探索分布式系统测试》议题现场实录。文章较长,为方便大家阅读,会分为上中下三篇,本文为上篇。 今天主要是介绍分布式系统测试。对于 PingCAP 目前的现状来说,我们是觉得做好分布式系统测试比做一个分布式系统更难。就是你把它写出来不是最难的,把它测好才是最难的。大家肯定会觉得有这么夸张吗?那我们先从一个最简单的、每个人都会写的 Hello world 开始。A simple “Hello world” is a miracle We should walk through all of the bugs in: Compiler Linker VM (maybe) OS 其实这个 Hello world 能够每次都正确运行已经是一个奇迹了,为什么呢?首先,编译器得没 bug,链接器得没 bug ;然后我们可能跑在 VM 上,那 VM 还得没 bug;并且 Hello world 那还有一个 syscall,那我们还得保证操作系统没有 bug;到这还不算吧,我们还得要硬件没有 bug。所以一个最简单程序它能正常运行起来,我们要穿越巨长的一条路径,然后这个路径里面所有的东西都不能出问题,我们才能看到一个最简单的 Hello world。但是分布式系统里面呢,就更加复杂了。比如大家现在用的很典型的微服务。假设你提供了一个微服务,然后在微服务提供的功能就是输出一个 Hello world ,然后让别人来 Call。A RPC “Hello world” is a miracle We should walk through all of the bugs in: Coordinator (zookeeper, etcd) RPC implementation Network stack Encoding/Decoding library Compiler for programming languages or [protocol buffers, avro, msgpack, capn] 那么我们可以看一下它的路径。我们起码需要依赖 Coordinator 去做这种服务发现,比如用 zookeeper,etcd ,大家会感觉是这东西应该很稳定了吧?但大家可以去查一下他们每一次 release notes,里边说我们 fix 了哪些 bug,就是所有大家印象中非常稳定的这些东西,一直都在升级,每一次升级都会有 bug fix。但换个思路来看,其实我们也很幸运,因为大部分时候我们没有碰到那个 bug,然后 RPC 的这个实现不能有问题。当然如果大家深度使用 RPC,比如说 gRPC,你会发现其实 bug 还是挺多的,用的深一点,基本上就会发现它有 bug。还有系统网络协议栈,去年 TCP 被爆出有一个 checksum 问题,就是 Linux 的 TCP 协议栈,这都是印象中永远不会出问题的。再有,编解码,大家如果有 Go 的经验的话,可以看一下 Go 的 JSON 历史上从发布以来更新的记录,也会发现一些 bug。还有更多的大家喜欢的编解码,比如说你用 Protocol buffers、Avro、Msgpack、Cap’n 等等,那它们本身还需要 compiler 去生成一个代码,然后我们还需要那个 compiler 生成的代码是没有 bug 的。然后这一整套下来,我们这个程序差不多是能运行的,当然我们没有考虑硬件本身的 bug。其实一个正确的运行程序从概率上来讲(不考虑宇宙射线什么的这种),已经是非常幸运的了。当然每一个系统都不是完善的,那通常情况下,为什么我们这个就运行的顺利呢?因为我们的测试永远都测到了正确的路径,我们跑一个简单的测试一定是把正确的路径测到了,但是这中间有很多错误路径其实我们都没有碰到。然后我不知道大家有没有印象,如果写 Go 程序的时候,错误处理通常写成 if err != nil,然后 return error ,不知道大家写了多少。那其它程序、其它的语言里就是 try.catch,然后里面各种 error 处理。就是一个真正完善的系统,最终的错误处理代码实际上通常会比你写正常逻辑代码还要多的,但是我们的测试通常 cover 的是正确的逻辑,就是实际上我们测试的 cover 是一小部分。那先纠正几个观念,关于测试的。就是到底怎么样才能得到一个好的、高质量的程序,或者说得到一个高质量的系统?Who is the tester ? Quality comes from solid engineering. Stop talking and go build things. Don’t hire too many testers. Testing is owned by the entire team. It is a culture, not a process. Are testers software engineers? Yes. Hiring good people is the first step. And then keep them challenged. 我们的观念是说先有 solid engineering 。我觉得这个几乎是勿庸置疑的吧,不知道大家的经验是什么?然后还有一个就是不扯淡,尽快去把东西 build 起来,然后让东西去运转起来。我前一段时间也写了一个段子,就是:“你是写 Rust 的,他是写 Java 的,你们这聊了这么久,人家 Rust (编译速度慢) 的程序已经编译过了,你 Java 还没开始写。”原版是这样的:“你是砍柴的,他是放羊的,你们聊了一天,他的羊吃饱了,你的柴呢?”然后最近还有一个特别有争议的话题:CTO 应该干嘛。就是 CTO 到底该不该写代码,这个也是众说纷纭。因为每一个人都受到自己环境的局限,所以每个人的看法都是不一样的。那我觉得有点像,就是同样是聊天,然后不同人有不同的看法。Test automation Allow developers to get a unit test results immediately. Allow developers to run all unit tests in one go. Allow code coverage calculations. Show the testing evolution on the dashboards. Automate everything. 我们现在很有意思的一个事情是,迄今为止 PingCAP 没有一个测试人员,这是在所有的公司看来可能都是觉得不可思议的事情,那为什么我们要这么干?因为我们现在的测试已经不可能由人去测了。究竟复杂到什么程度呢?我说几个基本数字大家感受一下:我们现在有六百多万个 Test,这是完全自动化去跑的。然后我们还有大量从社区收集到的各种 ORM Test,一会我会提到这一点。就是这么多 Test 已经不可能是由人写出来的了,以前的概念里面是 Test 是由人写的,但实际上 Test 不一定是人写的,Test 也是可以由机器生成的。举个例子,如果给你一个合法的语法树,你按照这个语法树去做一个输出,比如说你可以更换变量名,可以更换它的表达式等等,你可以生成很多的这种 SQL 出来。Google Spanner 就用到这个特性,它会有专门的程序自动生成符合 SQL 语法的语句,然后再交给系统去执行。如果执行过程中 crash 了,那说明这个系统肯定有 bug。但是这地方又蹦出另外一个问题,就是你生成了合法的 SQL 语句,但是你不知道它语句执行的结构,那你怎么去判断它是不是对的?当然业界有很聪明的人。我把它扔给几个数据库同时跑一下,然后取几个大家一致的结果,那我就认为这个结果基本上是对的。如果一个语句过来,然后在我这边执行的结果和另外几个都不一样,那说明我这边肯定错了。就算你是对的,可能也是错的,因为别人执行下来都是这个结果,你不一样,那大家都会认为你是错的。所以说在测试的时候,怎么去自动生成测试很重要。去年,在美国那边开始流行一个新的说法,叫做 “怎么在你睡觉的时候发现 bug”。那么实际上测试干的很重要的事情就是这个,就是自动化测试是可以在你睡觉的时候发现 bug。好像刚才我们还提到 fault injection ,好像还有 fuzz testing。然后所有测试的人都是工程师,因为只有这样你才不会甩锅。这是我们现在坚信的一个事情,就是所有的测试必须要高度的自动化,完全不由人去干预。然后很重要的一个就是雇最优秀的人才,同时给他们挑战,就是如果没有挑战,这些人才会很闲,精力分散,然后很难合力出成绩。因为以现在这个社会而言,很重要一个特性是什么?就是对于复杂性工程需要大量的优秀人才,如果优秀的人才力不往一处使力的话,这个复杂性工程是做不出来的。我今天看了一下龙芯做了十年了,差不多是做到英特尔凌动处理器的水平。他们肯定是有很优秀的人才,但是目前还得承认,我们在硬件上面和国外的差距还比较大,其实软件上面的差距也比较大,比如说我们和 Spanner 起码差了七年,2012 年 Spanner 就已经大规模在 Google 使用了,对这些优秀的作品,我们一直心存敬仰。我刚才已经反复强调过自动化这个事情。不知道大家平时写代码 cover 已经到多少了?如果 cover 一直低于 50%,那就是说你有一半的代码没有被测到,那它在线上什么时候都有可能出现问题。当然我们还需要更好的方法去在上线之前能够把线上的 case 回放。理论上你对线上这个回放的越久你就越安全,但是前提是线上代码永远不更新,如果业务方更新了,那就又相当于埋下了一个定时炸弹。比如说你在上面跑两个月,然后业务现在有一点修改,然而那两个又没有 cover 住修改,那这时候可能有新的问题。所以要把所有的一切都自动化,包括刚才的监控。比如说你一个系统一过去,然后自动发现有哪些项需要监控,然后自动设置报警。大家觉得这事是不是很神奇?其实这在 Google 里面是司空见惯的事情,PingCAP 现在也正在做。Well… still not enough ? Each layer can be tested independently. Make sure you are building the right tests. Don’t bother great people unless the testing fails. Write unit tests for every bug. 这么多还是不够的,就是对于整个系统测试来讲,你可以分成很多层、分成很多模块,然后一个一个的去测。还有很重要的一点,就是早期的时候我们发现一个很有意思的事情。就是我们 build 了大量 Test,然后我们的程序都轻松的 pass 了大量的 Test,后来发现我们一个 Test 是错的,那意味着什么?意味着我们的程序一直是错的,因为 Test 会把你这个 cover 住。所以直到后来我们有一次觉得自己写了一个正确的代码,但是跑出来的结果不对,我们这时候再去查,发现以前有一个 Test 写错了。所以一个正确的 Test 是非常重要的,否则你永远被埋在错误里面,然后埋在错误里面感觉还特别好,因为它告诉你是正确的。还有,为什么要自动化呢?就是你不要去打扰这些聪明人。他们本身很聪明,你没事别去打扰他们,说“来,你过来给我做个测试”,那这时候不断去打扰他们,是影响他们的发挥,影响他们做自己的挑战。这一条非常重要,所有出现过的 bug,历史上只要出现过一次,你一定要写一个 Test 去 cover 它,那这个法则大家应该已经都清楚了。我看今天所在的人的年龄,应该《圣斗士星矢》是看过的,对吧?这个圣斗士是有一个特点的,所有对他们有效的招数只能用一次,那这个也是一样的,就保证你不会被再次咬到,就不会再次被坑到。我印象中应该有很多人 fix bug 是这样的:有一个 bug 我 fix 了,但没有 Test,后来又出现了,然后这时候就觉得很奇怪,然后积累的越多,最后就被坑的越惨。这个是目前主流开源社区都在坚持的做法,基本没有例外。就是如果有一个开源社区说我发现一个 bug,我没有 Test 去 cover 它,这个东西以后别人是不敢用的。Code review At least two LGTMs (Looks good to me) from the maintainers. Address comments. Squash commit logs. Travis CI/Circle CI for PRs. 简单说一下 code review 的事情,它和 Test 还是有一点关系,为什么?因为在 code review 的时候你会提一个新的 pr,然后这个 pr 一定要通过这个 Test。比如说典型的 Travis CI,或者 CircleCI 的这种 Test。为什么要这样做呢?因为要保证它被 merge 到 master 之前你一定要发现这个问题,如果已经 merge 到 master 了,首先这不好看,因为你要 revert 掉,这个在 commit 记录上是特别不好看的一个事情。另外一个就是它出现问题之前,你就先把它发现其实是最好的,因为有很多工具会根据 master 自动去 build。比如说我们会根据 master 去自动 build docker 镜像,一旦你代码被 commit 到 master,然后 docker 镜像就出来了。那你的用户就发现,你有新的更新,我要马上使用新的,但是如果你之前的 CI 没有过,这时候就麻烦了,所以 CI 没过,一定不能进入到 CD 阶段。Who to blame in case of bugs? The entire team.另外一个观念纠正一下,就是出现 bug 的时候,责任是谁的?通常我见过的很多人都是这样,就说“这个 bug 跟我没关系,他的模块的 bug”。那 PingCAP 这边的看法不一样,就是一旦出现 bug,这应该是整个 team 的责任,因为你有自己的 code review 机制,至少有两个以上的人会去看它这个代码,然后如果这个还出现问题,那一定不是一个人的问题。除了刚才说的发现一些 bug,还有一些你很难定义,说这是不是 bug,怎么系统跑的慢,这算不算 bug,怎么对 bug 做界定呢?我们现在的界定方式是用户说了算。虽然我们觉得这不是 bug,这不就慢一点吗,但是用户说了这个东西太慢了,我们不能忍,这就是 bug,你就是该优化的就优化。然后我们团队里面出现过这样的事情,说“我们这个已经跑的很快了,已经够快了”,对不起,用户说慢,用户说慢就得改,你就得去提升。总而言之,标准不能自己定,当然如果你自己去定这个标准,那这个事就变成“我这个很 OK 了,我不需要改了,可以了。”这样是不行的。Profiling Profile everything, even on production once-in-a-lifetime chance Bench testing 另外,在 Profile 这个事情上面,我们强调一个,即使是在线上,也需要能做 Profile,其实 Profile 的开销是很小的。然后很有可能是这样的,有一次线上系统特别卡,如果你把那个重启了,你可能再也没有机会复现它了,那么对于这些情况它很可能是一辈子发生一次的,那一次你没有抓住它,你可能再也没有机会抓住它了。当然我们后面会介绍一些方法,可以让这个能复现,但是有一些确实是和业务相关性极强的,那么可能刚好又碰到一个特别的环境才能让它出现,那真的可能是一辈子就那么一次的,你一定要这次抓住它,这次抓不住,你可能永远就抓不住了。因为有些犯罪它一辈子只犯一次,它犯完之后你再也没有机会抓住它了。Embed testing to your design Design for testing or Die without good tests Tests may make your code less beautiful 再说测试和设计的关系。测试是一定要融入到你的设计里面,就是在你设计的时候就一定要想这个东西到底应该怎么去测。如果在设计的时候想不到这个东西应该怎么测,那这个东西就是正确性实际上是没法验证的,这是非常恐怖的一件事情。我们把测试的重要程度看成这样的:你要么就设计好的测试,要么就挂了,就没什么其它的容你选择。就是说在这一块我们把它的重要性放到一个最高的程度。未完待续… "}, {"url": "https://pingcap.com/weekly/2016-10-31-tidb-weekly/", "title": "Weekly update (October 24 ~ October 30, 2016)", "content": " Weekly update (October 24 ~ October 30, 2016) Last week, we landed 24 PRs in the TiDB repositories and 28 PRs in the TiKV repositories.Notable changes to TiDB Support coalesce/case when pushing down on local storage。 Support showing indexes in the table syntax. Split eval.go into some smaller files to make code cleaner. Fix a bug about truncating data. Fix the mysql version number format. Fix a bug about dropping the nonexist foreign key. Fix a bug in the parser where hexadecimal was parsed as string. Add comments for executor package to improve code readability. Add a command line flag to print binary version. Add a command line flag to prevent cartesian product. Notable changes to TiKV Compact region automatically after deleting lots of keys. Remove the rocksdb DSN for the tikv-server command flag. Use an atomic value to control the snapshot progress. Add timer for latch waiting. Check the region range before replicating a peer. Make sure the callback command is called. Coprocessor supports the multiply operator. Coprocessor supports the case whenoperator. Record the last compacted index to speed up compacting the Raft log. Notable changes to Placement Driver Refactor store/region cache to make code clearer, including PR 353, 365, 366. Support the GetPDMembers API. New contributors Librazy "}, {"url": "https://pingcap.com/meetup/meetup-2016-10-29/", "title": "PingCAP 第 27 期 NewSQL Meetup", "content": " PingCAP 第 27 期 NewSQL Meetup 2016-10-29 付力力&刘寅 PingCAP PingCAPPingCAP ![]() 微信号pingcap2015功能介绍PingCAP 专注于新型分布式数据库的研发,是知名开源数据库 TiDB (GitHub 总计10000+ stars ) 背后的团队,总部设在北京,是国内第一家开源的新型分布式关系型数据库公司、国内领先的大数据技术和解决方案提供商。NewSQL Meetup今天是 PingCAP 第 27 期 Meetup,主题是神策数据联合创始人&首席架构师付力力分享的《Impala 在用户行为分析中的应用与优化》以及刘寅分享的《How we build CI/CD for TiDB at scale》。▌ ****Topic 1:Impala 在用户行为分析中的应用与优化多冷的天都不能阻止技术童鞋们浓厚的求知欲 :-DLecture:付力力,神策数据联合创始人&首席架构师,曾任百度、豌豆荚资深研发工程师,熟悉大规模数据处理、数据仓库、OLAP 数据库等领域。Content: 介绍用户行为分析的典型应用场景; 简单介绍 Impala 的架构和实现; 使用 Impala 进行用户行为分析的基本做法; 针对特定场景对 Impala 进行的一些优化和改造。 ▌ ****Topic 2:How we build CI/CD for TiDB at scaleLecture:刘寅,PingCAP engineer,现负责 TiDB 商业产品开发和自动化运维。Content:主要分享了我们如何为分布式数据库 TiDB 构建持续集成和持续交付平台,以支撑 TiDB 背后上千万的自动化测试 case,和多平台构建及发布。其中,重点介绍了以 Jenkins 为核心的开源工具,配合 Docker / Kubernetes 来搭建分布式可扩展的 CI/CD 系统。Jenkins 2.0 之后的 pipeline script 的支持极大地提升分布式构建的灵活性,我们可以明确定义整个构建过程的不同阶段,并且决定这些阶段运行在集群的某个节点上,让耗时的任务并行处理,极大缩短从代码提交到上线发布的周期。同时结合实际场景的例子,讲解了 jenkins 的一些实用技巧和我们遇到的坑。特别鸣谢:场地赞助-泰利驿站PingCAP Meetup"}, {"url": "https://pingcap.com/weekly/2016-10-24-tidb-weekly/", "title": "Weekly update (October 17 ~ October 23, 2016)", "content": " Weekly update (October 17 ~ October 23, 2016) Last week, we landed 30 PRs in the TiDB repositories and 26 PRs in the TiKV repositories.Notable changes to TiDB Set the concurrency for the SQL executor using the Set statement Convert the Limit+Sort operator to the TopN operator on local storage Fix the gotouinue leak problem Support the logic/bitwise operator on local storage Support creating user without password Eliminate common aggregation function Support the Drop User statement Fix bugs Notable changes to TiKV Provide a tool tikv-ctl to browse the internal data in RocksDB. Make the Raft column family configurable. Avoid deleting other regions’ data accidentally. Coprocessor supports minus, intdiv and mod operations. Support canceling a applying snapshot job which is in queue directly. Use get_region_by_id to check the stale region. Skip fetching unnecessary values to speed up the scan performance. Add flow control to fix issue 1190 Clean up temporary snapshot file when startup. Shrink the send buffer after sending a big query to avoid occupying too much memory. Notable changes to Placement Driver Add uptime to show the online time for a store. Embed metapb.Store into storeInfo to make the code cleaner. "}, {"url": "https://pingcap.com/meetup/meetup-2016-10-22/", "title": "PingCAP 第 26 期 NewSQL Meetup", "content": " PingCAP 第 26 期 NewSQL Meetup 2016-10-22 张成远&刘奇 PingCAP PingCAPPingCAP ![]() 微信号pingcap2015功能介绍PingCAP 专注于新型分布式数据库的研发,是知名开源数据库 TiDB (GitHub 总计10000+ stars ) 背后的团队,总部设在北京,是国内第一家开源的新型分布式关系型数据库公司、国内领先的大数据技术和解决方案提供商。NewSQL Meetup今天是 PingCAP 第 26 期 Meetup,主题是开源项目 speedy 作者张成远分享的《京东分布式数据库实践》以及刘奇分享的《深度探索分布式系统测试》。 我司 CEO 亲自出台,现场不时传来三观碎一地的声音┑( ̄Д  ̄)┍另外,本周初次试水直播 (✿◡‿◡)▌ ****Topic 1:京东分布式数据库实践Lecture:张成远,《Mariadb 原理与实现》作者,开源项目 speedy 作者。目前就职于京东数据库系统研发团队,负责京东分布式数据库系统架构与研发工作,主导了京东分布式数据库系统在公司的落地及大规模推广。擅长高性能服务器开发,擅长分布式数据库/存储/缓存等大规模分布式系统架构。Content: 介绍京东分布式数据库的设计与实现; 介绍去 oracle 的发展历程以及遇到的一些坑; 如何做到高效的运维监控等。 ▌ ****Topic 2:深度探索分布式系统测试现场已爆满,本张照片拍摄于门缝…Lecture:刘奇,PingCAP 联合创始人兼 CEO,先后创建了 Codis、TiDB/TiKV 等知名开源项目。现从事开源的分布式 NewSQL 数据库 TiDB/TiKV 开发。擅长高并发、大规模、分布式数据库系统架构设计。Content:主讲人自我点评称:“这是一次毁三观的分享”,因为这里定义了什么是及格的测试。如果您曾经认为自己的分布式系统测试做得非常好,听完之后,您会发现自己可能还远不到好的级别。分布式系统测试是很少被提及的话题,但分布式系统测试的困难甚至大于写一个分布式系统。一般大家普遍的看法是平时用得很多的分布式系统都是比较稳定的,然而当新的测试方法和工具出现时,可以发现很多新的 bug 或者极大的提高了测试的复现率。复现率是解决 bug 的基础,分布式系统 bug 的复现难度也远大于单机系统。本周刘奇和大家分享了分布式系统测试的一些困难,以及 PingCAP 和其它大型分布式系统的测试经验。为了方便未到现场的童鞋,后续小编会将本次分享内容整理成文档共享出来,让我们一起,毁~三~观~ :)PingCAP Meetup"}, {"url": "https://pingcap.com/blog-cn/talk-principles-practice/", "title": "Building a Reliable Large-Scale Distributed Database - Principles and Practice", "content": " 大家好,我叫申砾,是 PingCAP Tech Leader,负责 TiDB 技术相关的工作。我曾就职网易有道、360 搜索,主要在做垂直搜索相关的事情,现在主要关注分布式计算/存储领域。过去的一年半时间我在 PingCAP 做分布式关系数据库 TiDB。目前我们的整个项目已经开源了大概一年时间,获得了不少关注。在 Github 上 Star 数量超过 5k,并且 Contributor 数量为 50+,拥有一个活跃的社区,在国内和国际上都有一定的知名度。 今天主要想和大家分享一下我们在做一款开源的分布式数据库产品过程中得到的一些经验和体会,包括技术上、产品上以及开源社区方面的内容,不会涉及太多技术上的细节。数据库现状 近年来,随着移动互联网、物联网、人工智能等技术的兴起,我们已经进入了一个信息爆炸的大数据时代,需要处理和分析的数据越来越多,这些数据如何保存、如何应用是一个重要的问题。传统的 SQL 数据库一般通过中间件、分库分表等方案获得 Scale 的能力。但是这些方案仍然很难做到对应用透明且保证数据均匀分布,同时也无法支持一致性的跨节点事务、JOIN 等操作。在进行扩容的时候往往需要人工介入,随着集群规模的增大,维护和扩展的复杂度呈指数级上升。以 Google 的 BigTable 论文为开端,涌现出了一大批 NoSQL 方案。这些方案致力于解决扩展性,而牺牲一致性。如果采用 NoSQL 方案替换原有关系型数据库,往往要涉及大规模的业务重构,这相当于将数据库层的计算逻辑复杂度转嫁给业务层,同时还要损失掉事务等特性。以上两种方案都没有完美地解决高可用的问题,跨机房多活、故障恢复、扩容经常都需要繁重的人工介入。最近几年,人们希望有一种既有 SQL/NoSQL 的优点,又能避免他们的不足的新型数据库,于是提出了 NewSQL 的概念。Google 发布的 Spanner/F1,算是第一个真正在大规模业务上验证过的分布式数据库,向业界证明了 NewSQL 这条道路的正确性。TiDB 作为 Google Spanner/F1 的开源实现,正是业界盼望已久的 NewSQL 开源数据库。什么是 NewSQL 并不是所有号称 NewSQL 的数据库都是 NewSQL。我们认为作为 NewSQL 数据库需要有下面几点特性:首先是 Scale。这点上我想大家都深有体会,不管什么数据解决方案,最基本的要求就是能有足够的能力,保存用户所有的数据。第二是事务。ACID Transaction,这个东西如果业务不需要,就感觉不到;一旦你的业务有这种需求,就能体会到它的重要性了。事实证明这个需求是广泛存在的,Google 的 BigTable 没有提供事务,结果内部很多业务都有需求,于是各个组造了一堆轮子,Jeff Dean 看不下去,出来说他最大的错误就是没有给 BigTable 提供事务。第三是 SQL。SQL 作为一门古老的语言,在现在的技术领域内依然有强大的生命力,基本是流行的各种 NoSQL 上面都会有人来做一套 SQL-on-X。最近刚看到一个 2016 最佳编程语言榜单,SQL 依然能上榜。我想 SQL 在业界的应用还会延续很多很多年。第四是 Auto-failover / Self recovery / Survivability。Spanner 能够做到任何一个数据中心宕机,底层可以完全的 Auto-Failover,上层的业务甚至是完全无感知的。这个 Failover 的过程是完全不需要人工介入的。国内很多互联网公司也都在做这个,但是还没有那一家能做的特别好,比如光纤被挖断之后,大家发现支付工具无法支付了。除了业务不被中断这一好处之外,Auto-failover 还会极大地降低运维的成本,如 Google 这么牛的公司,在维护一百多个节点的 MySQL Sharding 的数据库的时候,都已经非常痛苦,宁可重新去写一个数据库,也不想去维护这个 database cluster。为了给业界提供 NewSQL 数据库,我们开发了 TiDB,提供如下特性: 无限水平扩展 分布式 ACID 事务 强一致 高可靠 提供 SQL 并且支持 MySQL 协议 TiDB 目前是世界上最受欢迎的开源 NewSQL 数据库之一,可能是国人发起和主要维护的最大也是 stars 数最多的开源的数据库项目。我们在开发 TiDB 过程中学到的东西 下面就和大家分享一下我们在开发这个项目过程中学到的一些东西。Always believe shit is about to happen 大家写程序的时候,总会做一些错误检查,处理异常情况,但是很多情况可能大家普遍不会想到,比如光纤被挖断、IDC 整个 down 掉,还有前几天的阿里云 IO 问题。这说明即使以这些顶级大厂的技术能力,依然不能保证基础设施不出问题。所以我们会特别强调 Auto-failover 的作用。我们的整个设计始终会考虑容灾。其中最重要的就是如何保存多副本,一份数据写足够多的副本并且使用健壮的副本分布策略,才能保证安全。Spanner 默认使用 5 副本,重要的数据使用 7 副本。传统的保存副本的方案是 Master-slave 模式。但是这并不是一个完美的方案。如果要在 master 和 slave 之间保持强一致,那么不但要担心效率问题 (速度取决于最慢的那个 slave),还需要考虑各种容错。比如如果写 Slave 失败了,如何处理,是否要回滚 Master?所以依靠 master-slave 实现可靠复制对性能和复杂度都有比较大的挑战。而如果不要做到强一致,那么就面临 master 挂掉之后,slave 和 master 之间数据还没有同步完成,造成丢数据的问题。Multi-Paxos / Raft 是一个更好的选择,采用这种方案,多数节点写成功即可成功,在保证可靠性的同时,尽可能的提升了复制效率。Don’t rely on humans 面对容灾,我们需要尽可能的将工作自动化,因为人会累,会犯错,但是机器不会。我们希望能提供一套自动的方案,来支撑业务的需求,抵御各种异常情况。比如做 Scale 的时候,只需要点击几下即可增加新节点,然后系统自动将部分数据迁移到新节点。发生灾难时,系统能够自动下线 down 掉的节点,并将数据迁移到其他的节点。Talk is cheap, show me the tests 其实做数据库这么长时间,我认为最难的事情是测试。首先我们做的是一个支持 SQL 的数据库,想一下 SQL 的各种语法、操作符、函数,如何进行测试?同时我们是一个分布式的数据库,做测试就更难了。一直困扰我们的问题就是如何对我们的产品进行测试,比如一个 PR 上来后,如何检查逻辑是否正确,是否影响性能,是否支持容错?我们不断的探索和实践,有了一些自己的方案:首先是单元测试。我们的 Code Review 规范明确的写了,如果改了逻辑、bug,没有单测不予 Review。第二是集成测试。我们为了验证逻辑正确性,引入了大量的集成测试,其中一大块是 MySQL 源代码中的 test,因为我们支持 MySQL 语法和协议,所以可以直接拿过来用,省掉了我们大量的时间,很难想象没有这些测试,代码会变成什么样子。除此之外还有大量的 ORM 框架自带的 Test,我们也会运行。我们精选出一批集成测试 case,每次提交 PR 之前必需要跑过。当 PR merge 后,我们内部的 CI 会自动运行,跑更多更耗时的测试。为了测试分布式场景下的系统容错能力,我们也引入了一些工具,比如 Jepson/Namazu,可以进行错误注入。很多知名的分布式系统都被这些工具找出来过 bug,比如 etcd/zookeeper。“All problems in computer science can be solved by another level of indirection” 在一年半的时间里,TiDB 从零开始,成长为一个庞大的项目。首先我们是实现了一个内存的数据库,在一个简单的 memkv 基础上,做了一个小的 SQL 层,然后慢慢的替换 memkv 为持久化存储。我们将 SQL 和存储引擎之间的接口进行了抽象。后续的分布式存储引擎,也依赖于这个接口。这样就屏蔽了下层存储引擎的差别。无论是 TiDB 还是 TiKV 我们在开发过程中始终遵循良好的分层+抽象的原则,有效的降低了开发的复杂度和耦合度,另外对测试也有很大的帮助,我们可以更容易的 mock 某一层,做更精细的控制。抽象是对抗大系统复杂性的有效武器。Don’t try to teach your user, just follow them 想要做一款成功的数据库产品,就需要让用户觉得方便好用。在这一点上,中间件或者 Sharding 方案往往需要侵入用户代码、或者是修改用户逻辑,在做扩容的时候,也要消耗用户大量的精力。我们要求 TiDB 能够尽可能的减少用户工作,可以一行代码都不用修改就能从单机 MySQL 迁移到 TiDB 上。并且要尽可能的和行业标准贴近,减少用户的工作量。Make it right, and then make it fast 我们大概用了一个月的时间,做了一个可以用的数据库,在接下来的工作中,我们准备了整套测试框架,然后不断的完善功能,保证每次都是对的,与此同时,我们还会调整架构,最终做出一个还算不错的数据库,但是初期性能并不好,比如我们和第一家客户去聊,然后测试一下,发现一个简单的 SQL 跑了 600s,但是我们并不气馁,经过半个月的优化,我们将这个 SQL 优化到了 60ms。之所以能这么快优化到这么好,是因为我们有良好的架构,清晰的分层,完善的测试。所以这里并不是说我们不需要做优化,而是不要过早优化。这种大型系统,应该在早期关注架构的正确性以及弹性,为后面的优化留下足够的操作空间,保证每个模块可以单独的去优化。Embrace the community TiDB 是一个开源的数据库,我们从第一天起就坚定的走拥抱社区的路线,希望能够成为整个大数据生态的一部分。我们通过开源社区获得了大量高质量的第三方库,提高开发进度。与此同时,我们也向开源社区贡献了很多代码,比如 Etcd、Rocksdb、go-hbase、go-mysql 等。客户在进行数据库技术选型时,如果使用一些闭源的产品,那么就很容易被绑死在某一个厂商,或者是某一个云上。而使用 TiDB 不会有这方面的困扰,无论是迁移过来还是从 TiDB 迁移到其他的产品,都很容易,也不会被某个特定的云厂商绑死。如果一个公司符合如下任何一种情况,TiDB 或许是一个很好的解决方案: 项目选型阶段。为了快速开发,简化生产力和运维,使用 TiDB,再也不用对数据库进行分库分表或者选用数据库中间件,TiDB 帮你搞定所有底层的跨节点的分布式事务、聚合查询难点,开发人员专注于业务设计,维护人员运维非常容易。 目前使用 MySQL 且数据量很大,但是查询速度特别慢。TiDB 是 MySQL 兼容的,且在大数据量性能大大优于 MySQL。 有跨数据中心数据强一致性需求或者自动运维需求。 Q&A 提问:TiDB 是否和其他的数据库(比如 MySQL、Oracle) 进行过性能对比? 申砾:我们内部用 Sysbench 做过对比,单套 TiDB 在写入能力上超过 MySQL,读取方面比 MySQL 略低。从整体上看,延迟会大于 MySQL,但是吞吐可以远高于 MySQL。我们正在不断提高性能,不久之后会对外发布性能测试结果。提问:TiDB 是如何支持跨机房容灾? 申砾:TiDB 使用 Raft 做复制,PD 是整个集群的管理节点。PD 会自动根据存储节点的 IDC 位置指定副本存放策略,保证同一个 Raft Group 中的副本分布在多个机房。提问:TiDB 是否会出商业版本? 申砾:是的,PingCAP 会提供 TiDB 的商业版。(含监控、部署、数据处理、调度及支持服务等)"}, {"url": "https://pingcap.com/blog-cn/time-travel/", "title": "回到过去,找回遗失的珍宝 - TiDB 的历史读功能", "content": " 数据作为业务的核心,关系着整个业务的生死,所以对于数据库来说,数据的安全性是放在首位的,从宏观角度来看,安全性不仅仅在于的数据库本身足够稳定不会主动的丢失数据,有的时候更是对业务本身甚至人为失误造成损失是否有足够且便捷的应对方案,例如在游戏行业中经常遇到的反作弊(作弊玩家回档)问题,对于金融业务的审计需求等等,如果在数据库层面上提供相关机制,会让业务开发的工作量和复杂度减少很多。传统的方案会定期备份数据,几天一次,甚至一天一次,把数据全量备份。当意外发生的时候,可以用来还原。但是用备份数据还原,代价还是非常大的,所有备份时间点后的数据都会丢失,你绝对不希望走到这一步。另外全量备份带来的存储和计算资源的额外开销,对于企业来说也是一笔不小的成本。可是这种事情是无法完全避免的,我们所有的人都会犯错。对于一个快速迭代的业务,应用的代码不可能做到全面充分的测试,很可能因为应用逻辑的 Bug 导致数据写错,或者被恶意用户找到 bug,当你发现问题时,可以立即把应用回滚到旧版本,但是写错的数据却会一直留在数据库里。出现这种问题的时候,你该怎么办?你只知道有些数据不对了,但是对的数据是什么,你不知道。如果能回到过去,找回之前的数据该多好。TiDB 针对这样的需求和场景支持历史版本的读取,所以可以将错误的版本之前的数据取出来,将损失降到最低。如何使用 TiDB 的历史读功能 使用这个功能非常简单,只需要执行一个 SET 语句:set @@tidb_snapshot = "2016-10-10 09:30:11.123"这个 session variable 的名字是 TiDB 里定义的 tidb_snapshot, 值是一个时间的字符串,精确到毫秒,执行了这个语句之后,之后这个客户端发出的所有读请求,读到的都是这个时间点看到的数据,这时是不能进行写操作的,因为历史是无法改变的。如果想退出历史读模式,读取最新数据,只需要再次执行一个 SET 语句:set @@tidb_snapshot = ""把 tidb_snapshot 设置成空字符串就可以了。即使在那个历史时间点后,发生了 Schema 更改也没有关系,TiDB 会使用当时的 Schema 执行 SQL 请求。TiDB 历史读功能和其他数据库的比较 这个功能 MySQL 并不支持,但是在其他的数据库里,比如 Oracle, PostgreSQL 里有类似的功能,叫做历史表(Temporial Table),是一个SQL 标准。使用的方法是需要你用特殊的建表语法,额外创建一张历史表,历史表比原表多了两个系统定义的字段,代表有效时间,这多出的两个字段是系统维护的。当原表更新数据的时候,系统会把旧版本数据插入到历史表里,当你查询历史数据时,需要用一个特殊的语法指定历史时间,得到需要的结果。TiDB 和其他数据库的历史表功能相比,主要有以下两个优势:1,系统默认支持如果不是默认的行为,我们通常不会特意去建一张历史表,到真正需要用到的时候,你会发现历史表没有创建。2,使用方便不需要额外建一张表,不需要用特殊的语法查询。3,全局视角,而不是以表为单位TiDB 即使执行了 Drop Table, Drop Database 这样的操作,也可以读到旧的数据。TiDB 的历史读功能的实现 MVCC 为了方便理解,我们这里把实现原理做了一下简化,去掉了分布式事务相关的部分,TiDB 真正的实现会复杂一些。如果想了解完整的实现细节,请持续关注 TiDB,我们会在后期逐步完善事务模型部分的文档帮助大家了解。TiDB 的底层是 TiKV, TiKV 底层的存储引擎是 RocksDB, 存储的都是基本的 Key/Value Pair。在 SQL 层的一张表的一行,经过两次编码后,才得到最终的,存在 RocksDB 里的 key。第一次编码得到的 Key,包含了 table ID 和 record ID,得到这个 key 可以定位到这一行。第二次编码在第一次编码的 Key 的基础上,添加一个全局递增的时间戳,这个时间戳就是数据写入的时间。所有的 Key 都带着一个全局唯一的时间戳,也就意味着,新的写入不会覆盖旧的写入,即使是删除操作,写入也只是一个删除标记,并没有真正的删数据。同一行数据的多个版本是同时存在 RocksDB 里,按照时间顺序,连续的排列在一起。当一个读事务开始时,会从一个集群的时间分配器获取一个时间戳,这个时间点之前写入的数据,对这个事务是可见的,这个时间点之后写入的数据,对这个事务是不可见的,所以这个事务可以保证 Repeatable Read 这个隔离级别。TiDB 在向 TiKV 发起读请求时会带上这个时间戳,在 TiKV 拿到这个时间戳后,会比较这个时间戳和这一行的多个版本,找到不大于这时间戳的最大的版本,返回给 TiDB。以上就是 TiDB MVCC 的简化版的原理。所以 TiDB 其实原本就是用一个历史时间来读取数据的,只不过这个历史时间是系统在事务开始时自动获取的当前时间。使用 tidb_snapshot 这个 session variable,实际上是用一个用户指定的时间取代系统自动获取的时间去读取数据。你可能会有一个疑问,如果所有的版本都保留,数据占用的空间会不会无限膨胀?这里就需要介绍 TiDB 的垃圾回收机制了。TiDB 的垃圾回收 TiDB 会定期执行垃圾回收的任务,把过老的旧版本删掉,真正的从 RocksDB 里删掉,这样空间就不会无限膨胀了。那么多久以前的老的数据会被删掉呢?这个 GC 的过期时间,是通过配置一个参数来控制的,你可以配置成十分钟,一个小时,一天或永远不回收。所以,TiDB 的历史读功能是有限制的,只能读取到 GC 过期时间之后的数据,你可能会希望把时间设置的尽量久,但是这也是有代价的,GC 过期时间设置的越久,空间占用的会越大,读性能也会有所下降,如何配置这个时间,就要看业务的类型和需求了。如果数据非常重要,安全是首要考虑的因素,或数据更新变动很少,建议把 GC 过期时间设置的长一点。如果数据不那么重要,或数据更新很频繁,建议把 GC 过期时间设置的短一点。总结 TiDB 的历史读功能,把 TiDB 原生的读取机制开放出来,让用户用最简单的方式使用,我们希望这个功能,可以给 TiDB 的用户创造更多的价值。"}, {"url": "https://pingcap.com/blog/2016-10-17-how-we-build-tidb/", "title": "How we build TiDB", "content": " This is the speech Max Liu gave at Percona Live Open Source Database Conference 2016. The slides are here. Speaker introduction Why another database? What to build? How to design? The principles or the philosophy Disaster recovery Easy to use The community and ecosystem Loose coupling – the logical architecture The alternatives How to develop The architecture TiKV core technologies TiKV software stack Placement Driver Raft MVCC Transaction TiDB core technologies Mapping table data to Key-Value store Predicate push-down Schema changes How to test? The future plan Speaker introduction First, about me. I am an infrastructure engineer and I am also the CEO of PingCAP. Currently, my team and I are working on two open source projects: TiDB and TiKV. Ti is short for Titanium, which is a chemical element known for its corrosion resistance and it is widely used in high-end technologies.So today we will cover the following topics: Why another database? What kind of database we want to build? How to design such a database, including the principles, the architecture, and design decisions? How to develop such a database, including the architecture and the core technologies for TiKV and TiDB? How to test the database to ensure the quality and stability? Back to the topWhy another database Before we start, let's go back to the very beginning and ask yourself a question: Why another database. We all know that there are many databases, such as the traditional Relational database and NoSQL. So why another one? Relational databases like MySQL, Oracle, PostgreSQL, etcetera: they are very difficult to scale. Even though we have sharding solutions, YouTube/vitess, MySQL proxy, but none of them supports distributed transactions and cross-node join. NoSQL like HBase, MongoDB, and Cassandra: They scale well, but they don't support SQL and consistent transactions. NewSQL, represented by Google Spanner and F1, which is as scalable as NoSQL systems and it maintains the ACID transactions. That's exactly what we need. Inspired by Spanner and F1, we are making a NewSQL database. Of course, it's open source. Back to the topWhat to build? So we are building a NewSQL database with the following features: First of all, it supports SQL. We have been using SQL for decades and many of our applications are using SQL. We cannot just give it up. Second, it must be very easy to scale. You can easily increase the capacity or balance the load by adding more machines. Third, it supports ACID transaction, which is one of the key features of relational database. With a strong consistency guarantee, developers can write correct logic with less code. Last, it is highly available in case of machine failures or even downtime of an entire data center. And it can recover automatically. In short, we want to build a distributed, consistent, scalable, SQL Database. We name it TiDB.Back to the topHow to design? Now we have a clear picture of what kind of database we want to build, the next step is how, how to design it, how to develop it and how to test it. In the next few slides, I am going to talk about how to design TiDB.In this section, I will introduce how we design TiDB, including the principles, the architecture and design decisions.Back to the topThe principles or the philosophy Before we design, we have several principles or philosophy in mind: TiDB must be user-oriented. It must ensure that no data is ever lost and the system can automatically recover from machine failures or even downtime of the entire datacenters. It should be easy to use. It should be cross-platform and can run on any environment, no matter it's on premise, cloud or container. As an open source project, we are dedicated to being an important part of the big community through our active engagement, contribution and collaboration. We need TiDB to be easy to maintain so we chose the loose coupling approach. We design the database to be highly layered with a SQL layer and a Key-Value layer. If there is a bug in SQL layer, we can just update the SQL layer. The alternatives: Although our project is inspired by Google Spanner and F1, we are different from those projects. When we design TiDB and TiKV, we have our own practices and decisions in choosing different technologies. Back to the topDisaster recovery The first and foremost design principle is to build a database where no data is lost. To ensure the safety of the data, we found that multiple replicas are just not enough and we still need to keep Binlog in both the SQL layer and the Key-Value layer. And of course, we must make sure that we always have a backup in case the entire cluster crashes.Back to the topEasy to use The second design principle is about the usability. After years of struggling among different workarounds and trade-offs, we are fully aware of the pain points of the users. So when it comes to us to design a database, we are going to make it easy to use and there should be no scary sharding keys, no partition, no explicit handmade local index or global index, and making scale transparent to the users.Back to the topCross-platform The database we are building also needs to be cross-platform. The database can run on the on premise devices. Here is a picture of TiDB running on a Raspberry Pi cluster with 20 nodes.It can also support the popular containers such as Docker. And we are making it work with Kubernetes. Of course, it can be run on any cloud platform, whether it's public, private or hybrid.Back to the topThe community and ecosystem The next design principle is about the community and ecosystem. We want to stand on the shoulders of the giants instead of creating something new and scary. TiDB supports MySQL protocol and is compatible with most of the MySQL drivers (ODBC, JDBC) and SQL syntax, MySQL clients and ORM, and the following MySQL management tools and bench tools.Back to the topetcd etcd is a great project. In our Key-Value store, TiKV, which I will dive deep into later, we have been working with the etcd team very closely. We share the Raft implementation, and we do code reviews on Raft module for each other.Back to the topRocksDB RocksDB is also a great project. It's mature, fast, tunable, and widely used in very large scale production environments, especially in facebook . TiKV uses RocksDB as it's local storage. While we were testing it in our system, we found some bugs. The RocksDB team fixed those bugs very quickly.Back to the topNamazu A few months ago, we need a tool to simulate slow, unstable disk, and the team member found Namazu. But at that time, Namazu didn't support hooking fsync. When the team member raised this request to their team, they responded immediately and implement the feature in just a few hours and they are very open to implement other features as well. We are deeply impressed by their responsiveness and their efficiency.Back to the topRust community The Rust community is amazing. Besides the good developing experience of using Rust, we also build the Prometheus driver in Rust to collect the metrics.We are so glad to be a part of this great family. So many thanks to the Rust team, gRPC, Prometheus and Grafana.Back to the topSpark connector We are using the Spark connector in TiDB. TiDB is great for small or medium queries and Spark is better for complex queries with lots of data. We believe we can learn a lot from the Spark community too, and of course we would like to contribute as much as possible.So overall, we'd like to be a part of the big open source community and would like to engage, contribute and collaborate to build great things together.Back to the topLoose coupling – the logical architecture This diagram shows the logical architecture of the database.As I mentioned earlier about our design principle, we are adopting the loose coupling approach. From the diagram, we can see that it is highly-layered. We have TiDB to work as the MySQL server, and TiKV …"}, {"url": "https://pingcap.com/weekly/2016-10-17-tidb-weekly/", "title": "Weekly update (October 01 ~ October 16, 2016)", "content": " Weekly update (October 01 ~ October 16, 2016) Last week, we landed 27 PRs in the TiDB repositories and 32 PRs in the TiKV repositories.Notable changes to TiDB Support projection elimination so that the executor can run faster when it is not necessary to have a projection layer. Write DDL binlog to file. Convert sort and limit to top-n in the query planning phrase. Support reading history data even if the schema changes. Add comments for the server package and the plan package. Add metrics for GC configuration. Verify the data for utf-8 columns. Fix bugs. Notable changes to TiKV Compact the lock column family periodically. Add random latency filter to simulate the transport test. Improve the datum test coverage. Cache the Raft log term to avoid calling rocksdb::get every time. Check the store ID before sending to raftstore and refresh expired store address for the resolve process to fix issue 1153. Add new regions’ meta in StaleEpoch error to fix issue 974. Coprocessor supports timezone for timestamp comparison. Notable changes to Placement Driver Ignore balancing the peer with on-going operation to fix TiKV issue 1084. "}, {"url": "https://pingcap.com/meetup/meetup-2016-10-15/", "title": "PingCAP 第 25 期 NewSQL Meetup", "content": " PingCAP 第 25 期 NewSQL Meetup 2016-10-15 武毅&张金鹏 PingCAP PingCAPPingCAP ![]() 微信号pingcap2015功能介绍PingCAP 专注于新型分布式数据库的研发,是知名开源数据库 TiDB (GitHub 总计10000+ stars ) 背后的团队,总部设在北京,是国内第一家开源的新型分布式关系型数据库公司、国内领先的大数据技术和解决方案提供商。NewSQL Meetup今天是 PingCAP 第 25 期 Meetup,顶着帝都的大雾霾,依然来了很多小伙伴。这一次我们有换新场地噢,但不变的是分享内容依然满满干货。本周的主题分别是百分点集团高级架构师武毅分享的《分布式数据处理在个性化系统的应用》以及张金鹏分享的《TiKV 性能优化》。▌ ****Topic 1:分布式数据处理在个性化系统的应用Lecture:武毅,现任百分点集团高级架构师,负责大数据平台基础架构的设计与研发,曾参与个性化推荐系统等多个大型系统的设计和开发。Linux 爱好者,活跃于 GitHub,Ubuntu 等社区,重点关注分布式技术,平台技术。Content:相信大家也都在各自的领域用到过不同的分布式存储/计算开源工具,本周我们分享了一些在运营个性化系统时使用分布式存储/计算工具遇到的坑和经验。▌ ****Topic 2:TiKV 性能优化Content:RocksDB 的 Column Families 之间会共享 WAL,但是又有各自的 memtables 和 sst files,共享 WAL 使得实现跨 CF 的 atomic 操作变成可能,不同 CF 的 memtables 和 sst files 是分离开的,这样我们可以将不同类型的数据分别存放在不同的 CF 内,根据数据的性质给 CF 定制不同配置,使数据的写入和访问达到最佳状态。在目前 TiKV 中,读命令只能发给 leader,以防读取到旧的状态,在之前的版本中通过走一次 Raft 来确定当前节点是否是 leader,引入 leader lease 之后,命令发送到在 lease 内的leader 上时,不需要再走一次 Raft 了,可以直接读取本地数据。当 RocksDB tombstone keys 太多的时候 seek 操作会非常慢,可以根据情况使用 iterator 的 upper bound 功能或者使用 RocksDB 的 singledelete 来解决这个问题.最后我们给出了一些与 MySQL 的性能对比数据。可以看出,我们在写入性能、聚合操作和一些复杂查询上已经完全超过 MySQL 了。✏️分享两张新场地的图片给你们!看~是不是宽敞又明亮 😊PingCAP Meetup"}, {"url": "https://pingcap.com/blog-cn/how-do-we-build-tidb/", "title": "How do we build TiDB", "content": " 首先我们聊聊 Database 的历史,在已经有这么多种数据库的背景下我们为什么要创建另外一个数据库;以及说一下现在方案遇到的困境,说一下 Google Spanner 和 F1,TiKV 和 TiDB,说一下架构的事情,在这里我们会重点聊一下 TiKV。因为我们产品的很多特性是 TiKV 提供的,比如说跨数据中心的复制,Transaction,auto-scale。再聊一下为什么 TiKV 用 Raft 能实现所有这些重要的特性,以及 scale,MVCC 和事务模型。东西非常多,我今天不太可能把里面的技术细节都描述得特别细,因为几乎每一个话题都可以找到一篇或者是多篇论文。但讲完之后我还在这边,所以详细的技术问题大家可以单独来找我聊。后面再说一下我们现在遇到的窘境,就是大家常规遇到的分布式方案有哪些问题,比如 MySQL Sharding。我们创建了无数 MySQL Proxy,比如官方的 MySQL proxy,Youtube 的 Vitess,淘宝的 Cobar、TDDL,以及基于 Cobar 的 MyCAT,金山的 Kingshard,360 的 Atlas,京东的 JProxy,我在豌豆荚也写了一个。可以说,随便一个大公司都会造一个MySQL Sharding的方案。为什么我们要创建另外一个数据库? 昨天晚上我还跟一个同学聊到,基于 MySQL 的方案它的天花板在哪里,它的天花板特别明显。有一个思路是能不能通过 MySQL 的 server 把 InnoDB 变成一个分布式数据库,听起来这个方案很完美,但是很快就会遇到天花板。因为 MySQL 生成的执行计划是个单机的,它认为整个计划的 cost 也是单机的,我读取一行和读取下一行之间的开销是很小的,比如迭代 next row 可以立刻拿到下一行。实际上在一个分布式系统里面,这是不一定的。另外,你把数据都拿回来计算这个太慢了,很多时候我们需要把我们的 expression 或者计算过程等等运算推下去,向上返回一个最终的计算结果,这个一定要用分布式的 plan,前面控制执行计划的节点,它必须要理解下面是分布式的东西,才能生成最好的 plan,这样才能实现最高的执行效率。比如说你做一个 sum,你是一条条拿回来加,还是让一堆机器一起算,最后给我一个结果。 例如我有 100 亿条数据分布在 10 台机器上,并行在这 10 台 机器我可能只拿到 10 个结果,如果把所有的数据每一条都拿回来,这就太慢了,完全丧失了分布式的价值。聊到 MySQL 想实现分布式,另外一个实现分布式的方案是什么,就是 Proxy。但是 Proxy 本身的天花板在那里,就是它不支持分布式的 transaction,它不支持跨节点的 join,它无法理解复杂的 plan,一个复杂的 plan 打到 Proxy 上面,Proxy 就傻了,我到底应该往哪一个节点上转发呢,如果我涉及到 subquery sql 怎么办?所以这个天花板是瞬间会到,在传统模型下面的修改,很快会达不到我们的要求。另外一个很重要的是,MySQL 支持的复制方式是半同步或者是异步,但是半同步可以降级成异步,也就是说任何时候数据出了问题你不敢切换,因为有可能是异步复制,有一部分数据还没有同步过来,这时候切换数据就不一致了。前一阵子出现过某公司突然不能支付了这种事件,今年有很多这种类似的 case,所以微博上大家都在说“说好的异地多活呢?”……为什么传统的方案在这上面解决起来特别的困难,天花板马上到了,基本上不可能解决这个问题。另外是多数据中心的复制和数据中心的容灾,MySQL 在这上面是做不好的。 在前面三十年基本上是关系数据库的时代,那个时代创建了很多伟大的公司,比如说 IBM、Oracle、微软也有自己的数据库,早期还有一个公司叫 Sybase,有一部分特别老的程序员同学在当年的教程里面还可以找到这些东西,但是现在基本上看不到了。 另外是 NoSQL。NoSQL 也是一度非常火,像 Cassandra,MongoDB 等等,这些都属于在互联网快速发展的时候创建这些能够 scale 的方案,但 Redis scale 出来比较晚,所以很多时候大家把 Redis 当成一个 Cache,现在慢慢大家把它当成存储不那么重要的数据的数据库。因为它有了 scale 支持以后,大家会把更多的数据放在里面。 然后到了 2015,严格来讲是到 2014 年到 2015 年之间,Raft 论文发表以后,真正的 NewSQL 的理论基础终于完成了。我觉得 NewSQL 这个理论基础,最重要的划时代的几篇论文,一个是谷歌的 Spanner,是在 2013 年初发布的,再就是 Raft 是在 2014 年上半年发布的。这几篇相当于打下了分布式数据库 NewSQL 的理论基础,这个模型是非常重要的,如果没有模型在上面是堆不起来东西的。说到现在,大家可能对于模型还是可以理解的,但是对于它的实现难度很难想象。前面我大概提到了我们为什么需要另外一个数据库,说到 Scalability 数据的伸缩,然后我们讲到需要 SQL,比如你给我一个纯粹的 key-velue 系统的 API,比如我要查找年龄在 10 岁到 20 岁之间的 email 要满足一个什么要求的。如果只有 KV 的 API 这是会写死人的,要写很多代码,但是实际上用 SQL 写一句话就可以了,而且 SQL 的优化器对整个数据的分布是知道的,它可以很快理解你这个 SQL,然后会得到一个最优的 plan,他得到这个最优的 plan 基本上等价于一个真正理解 KV 每一步操作的人写出来的程序。通常情况下,SQL 的优化器是为了更加了解或者做出更好的选择。另外一个就是 ACID 的事务,这是传统数据库必须要提供的基础。以前你不提供 ACID 就不能叫数据库,但是近些年大家写一个内存的 map 也可以叫自己是数据库。大家写一个 append-only 文件,我们也可以叫只读数据库,数据库的概念比以前极大的泛化了。另外就是高可用和自动恢复,他们的概念是什么呢?有些人会有一些误解,因为今天还有朋友在现场问到,出了故障,比如说一个机房挂掉以后我应该怎么做切换,怎么操作。这个实际上相当于还是上一代的概念,还需要人去干预,这种不算是高可用。未来的高可用一定是系统出了问题马上可以自动恢复,马上可以变成可用。比如说一个机房挂掉了,十秒钟不能支付,十秒钟之后系统自动恢复了变得可以支付,即使这个数据中心再也不起来我整个系统仍然是可以支付的。Auto-Failover 的重要性就在这里。大家不希望在睡觉的时候被一个报警给拉起来,我相信大家以后具备这样一个能力,5 分钟以内的报警不用理会,挂掉一个机房,又挂掉一个机房,这种连续报警才会理。我们内部开玩笑说,希望大家都能睡个好觉,很重要的事情就是这个。说完应用层的事情,现在很有很多业务,在应用层自己去分片,比如说我按照 user ID 在代码里面分片,还有一部分是更高级一点我会用到一致性哈希。问题在于它的复杂度,到一定程度之后我自动的分库,自动的分表,我觉得下一代数据库是不需要理解这些东西的,不需要了解什么叫做分库,不需要了解什么叫做分表,因为系统是全部自动搞定的。同时复杂度,如果一个应用不支持事务,那么在应用层去做,通常的做法是引入一个外部队列,引入大量的程序机制和状态转换,A 状态的时候允许转换到 B 状态,B 状态允许转换到 C 状态。举一个简单的例子,比如说在京东上买东西,先下订单,支付状态之后这个商品才能出库,如果不是支付状态一定不能出库,每一步都有严格的流程。Google Spanner / F1 说一下 Google 的 Spanner 和 F1,这是我非常喜欢的论文,也是我最近几年看过很多遍的论文。Google Spanner 已经强大到什么程度呢?Google Spanner 是全球分布的数据库,在国内目前普遍做法叫做同城两地三中心,它们的差别是什么呢?以 Google 的数据来讲,谷歌比较高的级别是他们有 7 个副本,通常是美国保存 3 个副本,再在另外 2 个国家可以保存 2 个副本,这样的好处是万一美国两个数据中心出了问题,那整个系统还能继续可用,这个概念就是比如美国 3 个副本全挂了,整个数据都还在,这个数据安全级别比很多国家的安全级别还要高,这是 Google 目前做到的,这是全球分布的好处。现在国内主流的做法是两地三中心,但现在基本上都不能自动切换。大家可以看到很多号称实现了两地三中心或者异地多活,但是一出现问题都说不好意思这段时间我不能提供服务了。大家无数次的见到这种 case,我就不列举了。Spanner 现在也提供一部分 SQL 特性。在以前,大部分 SQL 特性是在 F1 里面提供的,现在 Spanner 也在逐步丰富它的功能,Google 是全球第一个做到这个规模或者是做到这个级别的数据库。事务支持里面 Google 有点黑科技(其实也没有那么黑),就是它有 GPS 时钟和原子钟。大家知道在分布式系统里面,比如说数千台机器,两个事务启动先后顺序,这个顺序怎么界定(事务外部一致性)。这个时候 Google 内部使用了 GPS 时钟和原子钟,正常情况下它会使用一个 GPS 时钟的一个集群,就是说我拿的一个时间戳,并不是从一个 GPS 上来拿的时间戳,因为大家知道所有的硬件都会有误差。如果这时候我从一个上拿到的 GPS 本身有点问题,那么你拿到的这个时钟是不精确的。而 Google 它实际上是在一批 GPS 时钟上去拿了能够满足 majority 的精度,再用时间的算法,得到一个比较精确的时间。同时大家知道 GPS 也不太安全,因为它是美国军方的,对于 Google 来讲要实现比国家安全级别更高的数据库,而 GPS 是可能受到干扰的,因为 GPS 信号是可以调整的,这在军事用途上面很典型的,大家知道导弹的制导需要依赖 GPS,如果调整了 GPS 精度,那么导弹精度就废了。所以他们还用原子钟去校正 GPS,如果 GPS 突然跳跃了,原子钟上是可以检测到 GPS 跳跃的,这部分相对有一点黑科技,但是从原理上来讲还是比较简单,比较好理解的。最开始它 Spanner 最大的用户就是 Google 的 Adwords,这是 Google 最赚钱的业务,Google 就是靠广告生存的,我们一直觉得 Google 是科技公司,但是他的钱是从广告那来的,所以一定程度来讲 Google 是一个广告公司。Google 内部的方向先有了 Big table ,然后有了 MegaStore ,MegaStore 的下一代是 Spanner ,F1 是在 Spanner 上面构建的。TiDB and TiKV TiKV 和 TiDB 基本上对应 Google Spanner 和 Google F1,用 Open Source 方式重建。目前这两个项目都开放在 GitHub 上面,两个项目都比较火爆,TiDB 是更早一点开源的, 目前 TiDB 在 GitHub 上 有 4300 多个 Star,每天都在增长。 另外,对于现在的社会来讲,我们觉得 Infrastructure 领域闭源的东西是没有任何生存机会的。没有任何一家公司,愿意把自己的身家性命压在一个闭源的项目上。举一个很典型的例子,在美国有一个数据库叫 FoundationDB,去年被苹果收购了。 FoundationDB 之前和用户签的合约都是一年的合约。比如说,我给你服务周期是一年,现在我被另外一个公司收购了,我今年服务到期之后,我是满足合约的。但是其他公司再也不能找它服务了,因为它现在不叫 FoundationDB 了,它叫 Apple了,你不能找 Apple 给你提供一个 enterprise service。 TiDB 和 TiKV 为什么是两个项目,因为它和 Google 的内部架构对比差不多是这样的:TiKV 对应的是 Spanner,TiDB 对应的是 F1 。F1 里面更强调上层的分布式的 SQL 层到底怎么做,分布式的 Plan 应该怎么做,分布式的 Plan 应该怎么去做优化。同时 TiDB 有一点做的比较好的是,它兼容了 MySQL 协议,当你出现了一个新型的数据库的时候,用户使用它是有成本的。大家都知道作为开发很讨厌的一个事情就是,我要每个语言都写一个 Driver,比如说你要支持 C++,你要支持 Java,你要支持 Go 等等,这个太累了,而且用户还得改他的程序,所以我们选择了一个更加好的东西兼容 MySQL 协议,让用户可以不用改。一会我会用一个视频来演示一下,为什么一行代码不改就可以用,用户就能体会到 TiDB 带来的所有的好处。 这个图实际上是整个协议栈或者是整个软件栈的实现。大家可以看到整个系统是高度分层的,从最底下开始是 RocksDB ,然后再上面用 Raft 构建一层可以被复制的 RocksDB,在这一层的时候它还没有 Transaction,但是整个系统现在的状态是所有写入的数据一定要保证它复制到了足够多的副本。也就是说只要我写进来的数据一定有足够多的副本去 cover 它,这样才比较安全,在一个比较安全的 Key-value store 上面, 再去构建它的多版本,再去构建它的分布式事务,然后在分布式事务构建完成之后,就可以轻松的加上 SQL 层,再轻松的加上 MySQL 协议的支持。然后,这两天我比较好奇,自己写了 MongoDB 协议的支持,然后我们可以用 MongoDB 的客户端来玩,就是说协议这一层是高度可插拔的。TiDB 上可以在上面构建一个 MongoDB 的协议,相当于这个是构建一个 SQL 的协议,可以构建一个 NoSQL 的协议。这一点主要是用来验证 TiKV 在模型上面的支持能力。 这是整个 TiKV 的架构图,从这个看来,整个集群里面有很多 Node,比如这里画了四个 Node,分别对应了四个机器。每一个 Node 上可以有多个 Store,每个 Store 里面又会有很多小的 Region,就是说一小片数据,就是一个 Region 。从全局来看所有的数据被划分成很多小片,每个小片默认配置是 64M,它已经足够小,可以很轻松的从一个节点移到另外一个节点,Region 1 有三个副本,它分别在 Node1、Node 2 和 Node4 上面, 类似的Region 2,Region 3 也是有三个副本。每个 Region 的所有副本组成一个 Raft Group, 整个系统可以看到很多这样的 Raft groups。Raft 细节我不展开了,大家有兴趣可以找我私聊或者看一下相应的资料。因为整个系统里面我们可以看到上一张图里面有很多 Raft group 给我们,不同 Raft group 之间的通讯都是有开销的。所以我们有一个类似于 MySQL 的 group commit 机制 ,你发消息的时候实际上可以 share 同一个 connection , 然后 pipeline + batch 发送, 很大程度上可以省掉大量 syscall 的开销。另外,其实在一定程度上后面我们在支持压缩的时候,也有非常大的帮助,就是可以减少数据的传输。对于整个系统而言,可能有数百万的 Region,它的大小可以调整,比如说 64M、128M、256M,这个实际上依赖于整个系统里面当前的状况。比如说我们曾经在有一个用户的机房里面做过测试,这个测试有一个香港机房和新加坡的机房。结果我们在做复制的时候,新加坡的机房大于 256M 就复制不过去,因为机房很不稳定,必须要保证数据切的足够小,这样才能复制过去。如果一个 Region 太大以后我们会自动做 SPLIT,这是非常好玩的过程,有点像细胞的分裂。然后 TiKV 的 Raft 实现,是从 etcd 里面 port 过来的,为什么要从 etcd 里面 port 过来呢?首先 TiKV 的 Raft 实现是用 Rust 写的。作为第一个做到生产级别的 Raft 实现,所以我们从 etcd 里面把它用 Go 语言写的 port 到这边。 这个是 Raft 官网上面列出来的 TiKV 在里面的状态,大家可以看到 TiKV 把所有 Raft 的 feature 都实现了。 比如说 Leader Election、Membership Changes,这个是非常重要的,整个系统的 scale 过程高度依赖 Membership Changes,后面我用一个图来讲这个过程。后面这个是 Log Compaction,这个用户不太关心。 这是很典型的细胞分裂的图,实际上 Region 的分裂过程和这个是类似的。我们看一下扩容是怎么做的。 比如说以现在的系统假设,我们刚开始说只有三个节点,有 Region1 分别是在 1 、2、4,我用虚线连接起来代表它是 一个 Raft group ,大家可以看到整个系统里面有三个 Raft group,在每一个 Node 上面数据的分布是比较均匀的,在这个假设每一个 Region 是 64M ,相当于只有一个 Node 上面负载比其他的稍微大一点点。这是一个在线的视频。默认的时候,我们都是推荐 3 个副本或者 5 个副本的配置。Raft 本身有一个特点,如果一个 leader down 掉之后,其它的节点会选一个新的 leader,那么这个新的 leader 会把它还没有 commit 但已经 reply 过去的 log 做一个 commit ,然后会再做 apply,这个有点偏 Raft 协议,细节我不讲了。复制数据的小的 Region,它实际上是跨多个数据中心做的复制。这里面最重要的一点是永远不丢失数据,无论如何我保证我的复制一定是复制到 majority,任何时候我只要对外提供服务,允许外面写入数据一定要复制到 majority。很重要的一点就是恢复的过程一定要是自动化的,我前面已经强调过,如果不能自动化恢复,那么中间的宕机时间或者对外不可服务的时间,便不是由整个系统决定的,这是相对回到了几十年前的状态。MVCC MVCC 我稍微仔细讲一下这一块。MVCC 的好处,它很好支持 Lock-free 的 snapshot read ,一会儿我有一个图会展示 MVCC 是怎么做的。isolation level 就不讲了,MySQL 里面的级别是可以调的,我们的 TiKV 有 SI,还有 SI+lock,默认是支持 SI 的这种隔离级别,然后你写一个 select for update 语句,这个会自动的调整到 SI 加上 lock 这个隔离级别。这个隔离级别基本上和 SSI 是一致的。还有一个就是 GC 的问题,如果你的系统里面的数据产生了很多版本,你需要把这个比较老的数据给 GC 掉,比如说正常情况下我们是不删除数据的, 你写入一行,然后再写入一行,不断去 update 同一行的时候,每一次 update 会产生新的版本,新的版本就会在系统里存在,所以我们需要一个 GC 的模块把比较老的数据给 GC 掉,实际上这个 GC 不是 Go 里面的GC,不是 Java 的 GC,而是数据的 GC。 这是一个数据版本,大家可以看到我们的数据分成两块,一个是 meta, …"}, {"url": "https://pingcap.com/weekly/2016-09-30-tidb-weekly/", "title": "Weekly update (September 26 ~ September 30, 2016)", "content": " Weekly update (September 26 ~ September 30, 2016) Last week, we landed 17 PRs in the TiDB repositories and 13 PRs in the TiKV repositories.Notable changes to TiDB Make the GC alive time configurable so that users can keep the deleted data as long as they want. Add the metrics for all kinds of statements to provide more information for insights. Improve the kv package test coverage. Record the processed row count during DDL so that users can track the progress of DDL. Consider the limit clause in the cost based optimizer (CBO) framework. Add metrics for kv errors. Make truncate statement a DDL to convert the truncate operation into a drop table process followed by a create table process. Then TiDB can delete the truncated data with a background worker. Notable changes to TiKV Add a metric for Raft vote to monitor server’s stability. Improve the test coverage for scheduler, Raft. Check the stale snapshot to fix 1084. Reuse iterator to speed up scan. Remove delete_file_in_range to fix 1121. Notable changes to Placement Driver (PD) Add more metrics to monitor the server. "}, {"url": "https://pingcap.com/weekly/2016-09-26-tidb-weekly/", "title": "Weekly update (September 19 ~ September 25, 2016)", "content": " Weekly update (September 19 ~ September 25, 2016) Last week, we landed 20 PRs in the TiDB repositories and 24 PRs in the TiKV repositories.Notable changes to TiDB Support DML binlog. Support reading the history data. Add more metrics to distsql, DDL, and store. Replace the vendor tool with glide. Improve test coverage. Code cleanup. Improve the test code by splitting a big test file into smaller files. Notable changes to TiKV Port the read index feature from etcd. Add the upper bound mod support to the iterator to improve the seek performance. Support the recovery mode for RocksDB. Support adding/removing column families dynamically. Notable changes to Placement Driver (PD) Remove the watch leader mechanism for the clients becausse the PD server can proxy requests to the leader. Add the GetRegionByID command. "}, {"url": "https://pingcap.com/meetup/meetup-2016-09-24/", "title": "PingCAP 第 24 期 NewSQL Meetup", "content": " PingCAP 第 24 期 NewSQL Meetup 2016-09-24 杜川&杨哲 PingCAP PingCAPPingCAP ![]() 微信号pingcap2015功能介绍PingCAP 专注于新型分布式数据库的研发,是知名开源数据库 TiDB (GitHub 总计10000+ stars ) 背后的团队,总部设在北京,是国内第一家开源的新型分布式关系型数据库公司、国内领先的大数据技术和解决方案提供商。NewSQL Meetup今天是 PingCAP 第 24 期 Meetup,主题是阿里云 ODPS 研发工程师杜川分享的《LLVM 简介及其在大规模 OLAP 中的应用》以及来自小米云平台的杨哲分享的《阻塞访问数据库的相关问题》。▌ ****Topic 1:LLVM 简介及其在大规模 OLAP 中的应用Lecture:杜川,阿里云 ODPS 研发工程师,分布式数据库爱好者,重点关注 SQL 运行时优化以及 Code Generation 技术。Content:LLVM 是一个开源的编译器框架及生态链,已在工业界得到广泛的应用(著名的 Clang 编译器就是基于LLVM实现的)。因其前后端分离,模块化等优势,近年来被引入数据库领域,作为 JIT Code Generation 的工具,并吸引了越来越多的关注。本次分享介绍了 LLVM,及其在大规模 OLAP 中的应用。▌ ****Topic 2:阻塞访问数据库的相关问题Lecture:杨哲,id 杨肉或 yangzhe1991,现就职于小米云平台存储组。曾就职于网易有道、豌豆荚任资深工程师等职位。主要研究分布式数据库,在小米、有道、豌豆荚分别负责 HBase、Cassandra 和 Codis 的开发与维护。Content:分享了关于数据库若干问题的一些想法。PingCAP Meetup"}, {"url": "https://pingcap.com/weekly/2016-09-19-tidb-weekly/", "title": "Weekly update (September 12 ~ September 18, 2016)", "content": " Weekly update (September 12 ~ September 18, 2016) Last week, we landed 18 PRs in the TiDB repositories and 26 PRs in the TiKV repositories.Notable changes to TiDB Add the Prometheus metrics and support push. Support the streaming aggregation operator. Rename xapi to distsql to improve readability. Add git hash to the TiDB server status API. Improve test coverage in the abstract syntax tree (AST). Enable the division operator for the distributed SQL statements. Fix several bugs. Notable changes to TiKV Remove the stale peers that are out of region to fix 804. Ignore the tombstone stores when resolving the store address. Discard the droppable messages when channel is full to fix 1028. Capture the signal TERM/INT to close server gracefully. Capture the signal USR1 to log metrics. Support destroying regions asynchronously. Support the pushing metrics to Prometheus Push Gateway. Notable changes to Placement Driver Add the API document. Support the pushing metrics to Prometheus Push Gateway. "}, {"url": "https://pingcap.com/weekly/2016-09-12-tidb-weekly/", "title": "Weekly update (September 05 ~ September 11, 2016)", "content": " Weekly update (September 05 ~ September 11, 2016) Last week, we landed 20 PRs in the TiDB repositories and 32 PRs in the TiKV repositories..Notable changes to TiDB Support mydumper Use MySQL standard error code in the DDL execution results Use heap sort operator to handle the statements with Limit and Orderby Add support for the CLIENT_CONNECT_ATTRS Add the constant propagation support to the SQL optimizer Optimize the index scan executor to improve the performance Optimize the distributed SQL API protocol to improve the performance Fix several bugs. Notable changes to TiKV Add the divide operation support to Coprocessor. Switch to the prometheus metrics from the statsd metrics. Abort applying the snapshot if it conflicts with a new one to fix 1014. Ensure that the data from the last write before the GC Safe-Point time can’t be removed to fix 1021. Add the document for Scheduler. Calculate the used space correctly. Stop GC scan if there are no keys left to fix the endless-loop problem. Notable changes to Placement Driver Support store removing gracefully. Add the Admin API. Reduce the default min-capacity-used-ratio value for an earlier auto-balance. "}, {"url": "https://pingcap.com/blog-cn/talk-tidb-pattern/", "title": "演讲实录|黄东旭:分布式数据库模式与反模式", "content": " 我叫黄东旭,是 PingCAP 的联合创始人兼 CTO,也是本场论坛的主持人。我原来在 MSRA,后来到了网易、豌豆荚。跟在座的大部分数据分析师不太一样的是,我是一个数据库开发,虽然是 CTO,但是还在写代码。同时,我也是一些用的比较广泛的分布式的开源软件的作者。比如说我们做的 TiDB、TiKV 这些大型的分布式关系型数据库的项目。我们现在正在做一个 OLTP 的数据库,主要 focus 在大数据的关系型数据库的存储和可扩展性,还有关系的模型,以及在线交易型数据库上的应用。所以,今天整个数据库的模式和反模式,我都会围绕着如何在一个海量的并发,海量的数据存储的容量上,去做在线实时的数据库业务的一些模式来讲。并从数据库的开发者角度,来为大家分享怎样写出更加适合数据库的一些程序。基础软件的发展趋势 一开始我先简单介绍一下,现在我认为的一些基础软件上的发展趋势。开源 第一点,开源是一个非常大的趋势。大家可以看到一些比较著名的基础软件,基本都是开源的,比如 Docker,比如 k8s。甚至在互联网公司里面用的非常多的软件,像 MySQL、Hadoop 等这种新一代的大数据处理的数据库等基础软件,也大多是开源的。其实这背后的逻辑非常简单:在未来其实你很难去将你所有的技术软件都用闭源, 因为开源会慢慢组成一个生态,而并不是被某一个公司绑定住。比如国家经常说去 IOE,为什么?很大的原因就是基本上你的业务是被基础软件绑死的,这个其实是不太好的一个事情。而且现在跟过去二十年前不一样,无论是开源软件的质量,还是社区的迭代速度,都已经是今非昔比,所以基本上开源再也不是低质低量的代名词,在互联网公司已经被验证很多次了。分布式 第二,分布式会渐渐成为主流的趋势。这是为什么?这个其实也很好理解,因为随着数据量越来越大,大家可以看到,随着现在的硬件发展,我感觉摩尔定律有渐渐失效的趋势。所以单个节点的计算资源或者计算能力,它的增长速度是远比数据的增长速度要慢的。在这种情况下,你要完成业务,存储数据,要应对这么大的并发,只有一种办法就是横向的扩展。横向的扩展,分布式基本是唯一的出路。scale-up 和 scale-out 这两个选择其实我是坚定的站在 scale-out 这边。当然传统的关系数据库都会说我现在用的 Oracle,IBM DB2,他们现在还是在走 scale-up 的路线,但是未来我觉得 scale-out 的方向会渐渐成为主流。 碎片化碎片化 第三,就是整个基础软件碎片化。现在看上去会越来越严重。但是回想在十年前、二十年前,大家在写程序的时候,我上面一层业务,下面一层数据库。但是现在你会发现,随着可以给你选择的东西越来越多,可以给你在开源社区里面能用到的组件越来越多,业务越来越复杂,你会发现,像缓存有一个单独的软件,比如 redis,队列又有很多可以选择的,比如说 zeromq, rabbitmq, celery 各种各样的队列;数据库有 NoSQL、HBase,关系型数据库有 MySQL 、PG 等各种各样的基础软件都可以选。但是就没有一个非常好东西能够完全解决自己的问题。所以这是一个碎片化的现状。微服务 第四,是微服务的模式兴起。其实这个也是最近两年在软件架构领域非常火的一个概念。这个概念的背后思想,其实也是跟当年的 SOA 是一脉相承的。就是说一个大的软件项目,其实是非常难去 handle 复杂度的,当你业务变得越来越大以后,维护成本和开发成本会随着项目的代码量呈指数级别上升的。所以现在比较流行的就是,把各个业务之间拆的非常细,然后互相之间尽量做到无状态,整个系统的复杂度可以控制,是由很多比较简单的小的组件组合在一起,来对外提供服务的。这个服务看上去非常美妙,一会儿会说有什么问题。最典型的问题就是,当你的上层业务都拆成无状态的小服务以后,你会发现原有的逻辑需要有状态的存储服务的时候你是没法拆的。我所有的业务都分成一小块,每一小块都是自己的数据库或者数据存储。比如说一个简单的 case,我每一个小部分都需要依赖同一个用户信息服务,这个信息服务会变成整个系统的一个状态集中的点,如果这个点没有办法做弹性扩展或者容量扩展的话,就会变成整个系统很致命的单点。所以现在整个基础软件的现状,特别在互联网行业是非常典型的几个大的趋势。我觉得大概传统行业跟互联网行业整合,应该在三到五年,这么一个时间。所以互联网行业遇到的今天,可能就是传统行业,或者其他的行业会遇到的明天。所以,通过现在整个互联网里面,在数据存储、数据架构方面的一些比较新的思想,我们就能知道如何去做这个程序的设计,应对明天数据的量级。现有存储系统的痛点 其实今天主要的内容是讲存储系统,存储系统现在有哪些痛点?其实我觉得在座的各位应该也都能切身的体会到。弹性扩展 首先,大数据量级下你如何实现弹性扩展?因为我们今天主要讨论的是 OLTP ,是在线的存储服务,并不是离线分析的服务。所以在线的存储服务,它其实要做到的可用性、一致性,是要比离线的分析业务强得多的。但是在这种情况下,你们怎样做到业务无感知的弹性扩展,你的数据怎么很好的满足现有的高并发、大吞吐,还有数据容量的方案。可用性 第二,在分布式的存储系统下,你的应用的可用性到底是如何去定义,如何去保证?其实这个也很好理解,因为在大规模的分布式系统里面,任何一个节点,任何一个数据中心或者支架都有可能出现硬件的故障,软件的故障,各种各样的故障,但这个时候你很多业务是并没有办法停止,或者并没有办法去容忍 Down time 的。所以在一个新的环境之下,你如何对你系统的可用性做定义和保证,这是一个新的课题。一会儿我会讲到最新的研究方向和成果。可维护性 第三,对于大规模的分布式数据库来说它的可维护性,这个怎么办?可维护性跟单机的系统是明显不同的,因为单机的数据库,或者传统的单点的数据库,它其实做到主从,甚至做到一主多从,我去维护 master ,别让它挂掉,这个维护性主要就是维护单点。在一个大规模的分布式系统上,你去做这个事情是非常麻烦的。可以简单说一个案例,就是 Google 的 Spanner。Spanner 是 Google 内部的一个大规模分布式系统,整个谷歌内部只部署了一套,在生产环节中只部署了一套。这一套系统上有上万甚至上数十万的物理节点。但是整个数据库的维护团队,其实只有很小的一组人。想像一下,上十万台的物理节点,如果你要真正换一块盘、做一次数据恢复或者人工运维的话,这是根本不可能做到的事情。但是对于一个分布式系统来说,它的可维护性或者说它的维护应该是转嫁给数据库自己。开发复杂度 还有,就是对于一个分布式数据库来说,它在开发业务的时候复杂度是怎么样的。大家其实可能接触的比较多的,像 Hbase、 Cassandra、Bigtable 等这种开源的实现,像 NoSQL 数据库它其实并没有一个很好的 cross-row transaction 的 support。另外,对于很多的 NoSQL 数据库并没有一个很好的 SQL 的 interface,这会让你写程序变得非常麻烦。比如说对于一些很普通的业务,一个表,我需要去 select from table,然后有一个fliter 比如一个条件大于 10,小于 100,这么简单的逻辑,如果在 HBase 上去做的话,你要写十行、二十行、三十行;如果你在一个关系的数据库,或者支持 SQL 的数据库,其实一行就搞定了。其实这个对于很多互联网公司来说,在过去的几年之内基本上已经完成了这种从 RDBMS 到 NoSQL 的改造,但是这个改造的成本和代价是非常非常高的。比如我原来的业务可能在很早以前是用 MySQL 已经写的稳定运行好久了,但是随着并发、容量、可扩展性的要求,我需要迁移 Bigtable、Hbase、Cassandra、MongoDB 这种 NoSQL 数据库上,这时基本上就要面临代码的完整重写。这个要放在互联网公司还可以,因为它们有这样的技术能力去保证迁移的过程。反正我花这么多钱,招这么牛的工程师,你要帮我搞定这个事情。但是对于传统的行业,或者传统的机构来说,这个基本上是不可能的事情。你不可能让他把原来用 Oracle 用SQL 的代码改成 NoSQL 的 code。因为 NoSQL 很少有跨行事务,首先你要做一个转账,你如果不是一个很强的工程师,你这个程序基本写不对,这是一个很大的问题。这也是为什么一直以来像这种 NoSQL 的东西并没有很好的在传统行业中去使用的一个最核心的原因,就是代价实在太大。存储系统的扩展模型 所以其实在去讲这些具体到底该怎么解决,或者未来数据库会是什么样的之前,我想简单讲一下扩展的模型。对于一个关系型数据库也好,对于存储的系统本身也好,它的扩展模型有哪些。Sharding 模式 第一种模式是 Sharding 模式。如果在座的各位有运维过线上的 MySQL 的话,对这个模型会非常熟悉。最简单的就是分库、分表加中间件,就是说我不同的业务可能用不同的库,不同的表。当一个单表太大的时候,我通过一些 Cobar、Mycat 等这样的数据库中间件来去把它分发到具体的数据库的实例上。这种模型是目前用的最普遍的模型,它其实也解决了很大部分的问题。为什么这十年在关系型数据库上并没有很好的扩展方案,但是大家看上去这种业务还没有出现死掉的情况,就是因为后面有各种各样 Sharding 的中间件或者分库分表这种策略在硬扛着。像这种中间件 Sharding 第一个优势就是实现非常简单。你并不需要对数据库内做任何的改造,你也并不需要去比如说从你原来的 SQL 代码转到 NoSQL 的代码。但是它也有自己的缺点。首先,对你的业务层有很强的侵入性。这是没有办法的,比如你想用一个中间件,你就需要给它指定一个 Sharding key。另外,原来比如你的业务有一些 join ,有一些跨表跨行的事务,像这种事务你必须得改掉,因为很多中间件并没有办法支持这个跨 shard 的分布式 join。 第二个比较大的缺陷是它的分片基本是固定的,自动化程度、扩展性都非常差,你必须得有一个专职的 DBA 团队给你的 MySQL 或者 PG 的 Sharding 的集群去做运维。我之前在豌豆荚做过一段时间 MySQL cluster 的分片的维护工作。当时我记得是一个 16 个节点的 MySQL 的集群,我们需要扩展到 32 个节点的规模,整整提前演练了一个月,最后上线了一个礼拜。上线那个礼拜,晚上基本上没有办法睡觉,所以非常痛苦。再说一个 Google 的事情,Google 在刚才我说的 Spanner 和 F1 这两个数据库没有上线之前,Google 的广告系统的业务是由 100 多个节点的 MySQL 的集群对外提供服务的。如 Google 这么牛的公司,在维护一百多个节点的 MySQL Sharding 的数据库的时候,都已经非常痛苦,宁可重新去写一个数据库,也不想去维护这个 database cluster。其实大家可以看到,像这种 Sharding 的方案,它比较大的问题就是它的维护代价或者维护集群的复杂度,并不是随着节点数呈线性增长,而是随着节点的增加非线性的增长上去。比如你维护 2 个节点的还好,维护 4 个节点的也还可以,但是你维护 16 个、64 个、128 个基本就是不可能的事情。第三就是一些复杂的查询优化,并没有办法在中间件这一层,去帮你产生一个足够优化的执行计划,因此,对于一些复杂查询来说,Sharding 的方案是没法做的。所以对你的业务层有很高的要求。这是一种思路,是目前来说互联网公司里边用的最多的一种 MySQL 或者 PG 这种关系型数据库的扩展方案。Region Base 模型 第二种扩展模型是 Region Base。这张图是我项目里面扒出来的图。它整个思路有点像 Bigtable,它相当于把底下的存储层分开,数据在最底层存储上已经没有表、行这样结构的划分,每一块数据都由一个固定的 size 比如 64 M、128 M 连续的 Key-value pairs 组成。其实这个模型背后最早的系统应该是谷歌在 06 年发表的 Bigtable 这篇论文里面去描述的。这个模型有什么好处呢?一是它能真正实现这种弹性的扩展。第二个,它是一个真正高度去中心化。去中心化这个事情,对于一个大的 Cluster 来说是一个非常重要的特性。**还有一个优势,在 KV 层实现真正具有一定的自动 Failover 的能力。 **Failover指的是什么呢?比如说在一个集群比较大的情况下,或者你是一个 cluster ,你任何一个节点,任何一个数据损坏,如果能做到业务端的透明,你就真正实现了 Auto-Failover 的能力。其实在一些对一致性要求不那么高的业务里面,Auto-Failover 就是指, 比如在最简单的一个 MySQL 组从的模型里,当你的组挂掉了以后,我监控的程序自动把 slave 提上来,这也是一种 Failover 的方式。但是这个一致性或者说数据的正确性并不能做到很好的保证。你怎么做到一致性的 Auto-Failover,其实背后需要做非常非常多的工作。这是 Region 模型的一些优势。但是它的劣势也同样明显,这种模型的实现非常复杂。我一会儿会说到背后的关键技术和理论,但是它比起写中间件真的复杂太多了。你要写一个能用的 MySQL 或者 PG 的中间件,可能只需要一两个工程师,花一两周的时间就能写出一个能用的数据库中间件;但是你如果按照这个模型做一个弹性扩展的数据库的话,你的工作量就会是数量级的增加。第二个劣势就是它业务层的兼容性。像 Region Base 的模型,最典型的分布式存储系统就是 HBase。HBase 它对外的编程接口和 SQL 是千差万别,因为它是一个 Key Value 的数据库。你的业务层的代码兼容性都得改,这个对于一些没有这么强开发能力的用户来说,是很难去使用的,或者它说没有 SQL 对于用户端这么友好。可用性级别 我一会儿会讲一下,刚才我们由 Region Base 这个模型往上去思考的一些东西,在此之前先说一些可用性。高可用。其实说到高可用这个词,大多数的架构师都对它非常熟悉。我的系统是高可用的,任何一个节点故障业务层都不受影响,但是真的不受影响吗?我经过很多的思考得到的一个经验就是主从的模型是不可能保证同时满足强一致性和高可用性的。可能这一点很多人觉得,我主从,我主挂了,从再提起来就好,为什么不能保护这个一致性呢?就是因为在一个集群的环境下,有一种故障叫脑裂。脑裂是什么情况?整个集群是全网络联通的,但是出现一种情况,就是我只是在集群内部分成了两个互不联通的一个子集。这两个子集又可以对外提供服务,其实这个并不是非常少见的状况,经常会发生。像这种情况,你贸然把 slave 提起来,相当于原来的 master 并没有完全的被 shutdown,这个时候两边可能都会有读写的情况,造成数据非常严重的不一致,当然这个比较极端了。所以你会发现阿里或者说淘宝,年年都在说我们有异地多活。但是去年甚至前几个月,杭州阿里的数据中心光纤被挖断,支付宝并没有直接切到重复层,而是宁可停止服务,完全不动,也不敢把 slave 数据中心提起来。所以其实任何基于主从模型的异地多活方案都是不行的。这个问题有没有办法解决呢?其实也是有的。还是说到 Google,我认为它才是全世界最大的数据库公司,因为它有全世界最大的数据量。你从来没有听说过 Google 哪一个业务因为哪一个数据中心光纤挖断,哪一个磁盘坏了而对外终止服务的,几乎完全没有。因为 Google 的存储系统大多完全抛弃了基于主从的一致性模型。它的所有数据都不是通过主从做复制的,而是通过类似 Raft 或者 Paxos 这种分布式选举的算法做数据的同步。这个算法的细节不展开了,总体来说是一个解决在数据的一致性跟自动的数据恢复方面的一个算法。同时,它的 latency 会比多节点强同步的主从平均表现要好的一个分布式选举的算法。在 Google 内部其实一直用的 Paxos,它最新的 Spanner 数据库是用 Paxos 做的 replication 。在社区里面,跟 Paxos 等价的一个算法就是 Raft。Raft 这个算法的性能以及可靠性都是跟 Paxos 等价的实现。这个算法就不展开了。我认为这才是新一代的强一致的数据库应该使用的数据库复制模型。分布式事务 说到事务。对于一个数据库来说,我要做传统的关系型数据库业务,事务在一个分布式环境下,并不像单机的数据库有这么多的方法,这么多的优化。其实在分布式事务这个领域只有一种方法,并且这么多年了从分布式事务开始到现在,在这个方法上并没有什么突破,基本只有一条出路就是两阶段提交。其实可以看一下 Google 的系统。对于我们做分布式系统的公司来说,Google 就是给大家带路的角色。Google 最新的数据库系统上它使用的分布式事务的方法仍然是两阶段提交。其实还有没有什么优化的路呢?其实也是有的。两阶段提交最大的问题是什么呢?一个是延迟。因为第一阶段先要把数据发过去,第二阶段要收到所有参与的节点的 response 之后你才能去 commit 。这个过程,相当于你走了很多次网络的 roundtrip,latency 也会变得非常高。所以其实优化的方向也是有的,但是你的 latency 没法优化,只能通过吞吐做优化,就是 throughput 。比如说我在一万个并发的情况下,每个用户的 latency 是 100 毫秒,但是一百万并发,一千万并发的时候,我每个用户的 latency 还可以是 100 毫秒,这在传统的单点关系型数据库上,是没有办法实现的。第二就是去中心化的事务管理器。另外没有什么东西是银弹,是包治百病的,你要根据你的业务的特性去选择合适的一致性算法。NewSQL 其实刚刚这些 pattern 会发展出一个新的类别,我们能不能把关系数据库上的一些 SQL、Transaction 跟 NoSQL 跟刚才我说到的 Region Base 的可扩展的模型融合起来。这个思想应该是在 2013 年左右的时候,学术界提出来比较多的东西,NewSQL。NewSQL 首先要解决 Scalability 的问题, 刚给我们说过 scalability 是一个未来的数据库必须要有的功能,第二个就是 SQL,SQL 对于业务开发者来说是很好的编程的接口。第三,ACID Transaction,我希望我的数据库实现转帐和存钱这种强一致性级别的业务。第四,就是整个 cluster 可以支持无穷大的数据规模,同时任何数据节点的宕机、损坏都需要集群自己去做监控,不需要 DBA 的介入。案例:Google Spanner / F1 有没有这样的系统?其实有的。刚才一直提到 Google 的 Spanner 系统。Spanner 系统是在 2012 年底于 OSDI 的会议上发布了论文; F1 这篇论文在 2013 年的 VLDB 发布的,去描述了整个 Google 内部的分布式关系型数据库的实现。首先,根据 Spanner 的论文 Spanner 和 F1 在生产环境只有一个部署,上万物理节点遍布在全球各种数据中心内,通过 Paxos 进行日志复制。第二,整 …"}, {"url": "https://pingcap.com/meetup/meetup-2016-09-10/", "title": "PingCAP 第 23 期 NewSQL Meetup", "content": " PingCAP 第 23 期 NewSQL Meetup 2016-09-10 金坤&黄华超 PingCAP PingCAPPingCAP ![]() 微信号pingcap2015功能介绍PingCAP 专注于新型分布式数据库的研发,是知名开源数据库 TiDB (GitHub 总计10000+ stars ) 背后的团队,总部设在北京,是国内第一家开源的新型分布式关系型数据库公司、国内领先的大数据技术和解决方案提供商。NewSQL Meetup今天是 PingCAP 第 23 期 Meetup,主题是金坤分享的《How to write a good commit message》以及黄华超分享的《QuorumKV:微信分布式 KV 存储系统》。【Topic 1】How to write a good commit messageContent:This talk about writing good commit messages aims to act as the beginning of a series of talks about writing quality technical content. To emphasise the importance of the commit messages, the talk asked the audience to set up a profile of the potential reviewer who is as cool and picky as the writer of the technical content, or the writer himself in 5 years. Then the talk introduced what is a good commit message and how to write a good commit message by encouraging the audiences to establish good habits, good format and use simple and consistent language, especially to resist the temptation of using lengthy sentences. Best practices and tools from other projects and also covered to trigger further discussions and action items to improve our project.【Topic 2】QuorumKV:微信分布式 KV 存储系统Content:本次分享首先介绍了 QuorumKV 诞生的背景以及微信的一些业务情况。并分别从单机存储引擎、分布式协议、数据迁移和冷热数据分离等方面介绍了系统的设计和实现。最后,与大家共同探讨了 QuorumKV 目前基于 Paxos 的一些改造和发展。PingCAP Meetup"}, {"url": "https://pingcap.com/weekly/2016-09-05-tidb-weekly/", "title": "Weekly update (August 29 ~ September 04, 2016)", "content": " Weekly update (August 29 ~ September 04, 2016) Last week, we landed 29 PRs in the TiDB repositories and 24 PRs in the TiKV repositories.Notable changes to TiDB Support the unhex and the ceiling/ceil functions Improve the Parser to handle rn. Solve the potential concurrency issues Support Load Data Use the Pipeline model to filter data through indexes to improve the performance Improve the code to reduce memory allocation and improve the performance Fix several bugs. Notable changes to TiKV Coprocessor supports the new decimal type. Use the Raft column family to save Raft meta and logs. See Benchmark. Tune the write column family to reduce memory usage. Notable changes to Placement Driver Check duplicated store addresses to prevent user from bootstrapping cluster in the wrong way, see issues 287, 288. Support the remove store API to remove a dead TiKV store. Use glide instead of the original godep to manage vendor. Remove join itself to prevent user from starting a removed PD server again. Benchmark Use sysbench to benchmark using the (CF_RAFT) column family to save the Raft log and previously the default (CF_DEFAULT) column family in 3-node TiKV.# Prepare data sysbench --test=./lua-tests/db/oltp.lua --mysql-host=${host} --mysql-port=${port} --mysql-user=${user} --mysql-password=${password} --oltp-tables-count=1 --oltp-table-size=${table_size} --rand-init=on prepare # Run benchmark sysbench --test=./lua-tests/db/insert.lua --mysql-host=${host} --mysql-port=${port} --mysql-user=${user} --mysql-password=${password} --oltp-tables-count=1 --oltp-table-size=${table_size} --num-threads=${threads} --report-interval=60 --max-requests=1280000 --percentile=99 run Threads Table Size CF_DEFAULT qps CF_DEFAULT avg/.99 latency CF_RAFT qps CF_RAFT avg/.99 latency 32 6400000 3885 8.24⁄13.48 3979 8.04/13.70 64 7680000 3653 17.52⁄34.10 4477 14.29⁄24.49 128 8960000 3422 37.39⁄70.10 4642 27.57⁄57.45 As we can see, the qps is increased by about 22%, and the latency is decreased by about 18%.New contributors Dagang Wei "}, {"url": "https://pingcap.com/meetup/meetup-2016-09-03/", "title": "PingCAP 第 22 期 NewSQL Meetup", "content": " PingCAP 第 22 期 NewSQL Meetup 2016-09-03 宋昭&张帅 PingCAP PingCAPPingCAP ![]() 微信号pingcap2015功能介绍PingCAP 专注于新型分布式数据库的研发,是知名开源数据库 TiDB (GitHub 总计10000+ stars ) 背后的团队,总部设在北京,是国内第一家开源的新型分布式关系型数据库公司、国内领先的大数据技术和解决方案提供商。NewSQL Meetup今天是 PingCAP 第 22 期 Meetup,主题是360 基础架构组研发工程师宋昭分享的《360 开发的大容量 redis -pika》以及 美团云工程师张帅分享的《分布式对象存储系统设计介绍》。▌ ****Topic 1:360 开发的大容量 redis -pikaLecture:宋昭,360 基础架构组研发工程师。专注于分布式存储领域,目前负责 360 开源项目 pika 相关的设计和开发工作。Content:目前 pika 在 360 内部大量使用,有 300 多实例,主要解决大容量的 redis(400G,800G)场景;在外部,被微博、美团、万达电商、garena、apus 等使用于线上核心系统中。本次分享主要介绍 pika 的系统设计和实现。▌ ****Topic 2:分布式对象存储系统设计介绍Lecture:张帅,美团云工程师。对分布式数据库及分布式存储系统有浓厚的兴趣。Content:分享关于大规模分布式对象存储的一些想法和思考。PingCAP Meetup"}, {"url": "https://pingcap.com/blog-cn/tidb-transaction-model/", "title": "TiKV 事务模型概览,Google Spanner 开源实现", "content": "随着时代的发展,应用和数据的规模越来越大。然而在这个一切都可以水平扩展的时代,你会发现,大多数应用的最下层的关系型数据库,竟然难以找到一个优雅易用的水平扩展解决方案,一直以来不得不依赖静态 Sharding ,牺牲掉事务,然后在业务层各种 Workarounds。作为后端开发者应该深有体会。层出不穷的 NoSQL 看似解决了数据水平扩展的问题,但是由于跨行事务的缺失和接口的局限,在很多业务中落地还是需要付出很多代价的。最近 Google 基础设施的神人 Jeff Dean 在一次采访中回顾自己作为工程师最大的后悔是什么的问题时提到,他最后悔的事情是没有在 BigTable 中加入跨行事务模型,以至于后来各种各样的团队尝试在 BigTable 上不停的造事务的轮子,但其实这个特性应该是由 BigTable 提供。同样的观点也在他后来的论文中反复提到过。Google 2012 年在 OSDI 上发表了 Spanner,作为 BigTable 的下一代产品,最主要的特性就是支持跨行事务和在分布式场景上实现 Serializable 的事务隔离级别。我们在2015年底从零开始按照论文做 Spanner 的开源实现 TiKV,于近期开源,和 Spanner 一样,也是一个支持分布式事务和水平扩展的 KV 数据库。一个分布式数据库涉及的技术面非常广泛, 今天我们主要探讨的是 TiKV 的 MVCC(多版本并发控制) 和 Transaction 实现。MVCC 其实并不是一个新的概念了,在传统的单机关系型数据库使用 MVCC 技术来规避大量的悲观锁的使用,提高并发事务的读写性能。值得注意的是 MVCC 只是一个思想,并不是某个特定的实现,它表示每条记录都有多个版本的,互相不影响,以一个 kv 数据库为例从逻辑上的一行的表示就并不是Record := {key, value} 而是Record := {key, value, version} 支持分布式 MVCC 在 KV 系统中比较著名的应该是在 BigTable。在 TiKV 中我们的整个事务模型是构建在一个分布式 MVCC 的基础之上:可以看到,整个 TiKV 的底层本地存储是依赖了 RocksDB,RocksDB 是一个单机的嵌入式 KV 数据库,是一个 LSM Tree的实现,是 Facebook 基于 LevelDB 的修改版本,其特点是写入性能特别好,数据存储是有序的 KV Pairs,对于有序 key 的迭代的场景访问效率较高。对于 MVCC 层,每一个 Key,在底层的 RocksDB 上都会存储同一个 Key 的多个版本,在底层存储上看来,形式如:MateKey --> key 的所有版本信息 DataKey(key+version_1)-->Value_v1 DataKey(key+version_2)-->Value_v2 暴露给上层的接口行为定义: MVCCGet(key, version), 返回某 key 小于等于 version 的最大版本的值 MVCCScan(startKey, endKey, limit, version), 返回 [startKey, endKey) 区间内的 key 小于等于 version 的最大版本的键和值,上限 limit 个 MVCCPut(key, value, version) 插入某个键值对,如果 version 已经存在,则覆盖它。上层事务系统有责任维护自增version来避免read-modify-write MVCCDelete(key, version) 删除某个特定版本的键值对, 这个需要与上层的事务删除接口区分,只有 GC 模块可以调用这个接口 给出一个 MVCCGet 的伪代码实现:MVCCGet(key, version) { versions = kv.Get(key) // read meta targetVer = nil for ver in versions { if ver <= version { targetVer = ver break } } return kv.Get(mvccEncode(key, targetVer)), targetVer } 核心思想是,先读取 meta key 然后通过 meta key 中找到相应的可见版本,然后再读取 data key,由于这些 key 都拥有相同的前缀,所以在实际的访问中,读放大的程度是可以接受的。类似的 MVCCScan 和 MVCCPut 由于篇幅的限制就不展示了,但是思想是类似的。细心的朋友可能会发现,这个方案会遇到一个 key 的 meta key 膨胀的问题,当如果一个 key 短时间内修改过于频繁,会导致 meta key 的 value 过大,这个问题可以通过 meta 拆分的方式解决,核心的思想也比较简单,本质上就是对 meta key 建立索引,将一个 meta key 变成多个 meta key:Meta0 (v127 - v0) next: 0 (0表示没有后续 Meta) 第一次分裂:Meta0 (v128 - v96) next:1 Meta1 (v95 - v0) next:0 第二次分裂:Meta0 (v224 - v192) next:2 Meta1 (v95 - v0) next: 0 Meta2 (v191 - v96) next:1 这样一来,即可规避过大的读放大问题。对 TiKV 的 MVCC 模型有了基础概念之后,就可以介绍我们的分布式事务模型,总体来讲,我们的分布式事务模型本质上是一个两阶段提交的算法,其实本质上来说,在一个分布式系统中实现跨节点事务,只有两阶段提交一种办法(3PC 本质上也是 2PC 的一个优化)。在 Spanner 中同样也是一个 2PC,但是 Google 比较创新的引入了 TrueTime API 来作为事务 ID 生成器从而实现了 Serializable 的隔离级别,具体的实现在这里就不赘述了,有兴趣的朋友可以去看 Spanner 的论文。值得一提的是,由于 TrueTime 引入了专有的硬件(GPS 时钟和原子钟)来实现跨洲际机房的时钟同步方案,大多数业务场景其实并没有这种跨洲际机房数据同步的需求,所以我们在 TiKV 中最终选择的事务模型和 Spanner 有所区别,采用了 Google 的另一套分布式事务方案 Percolator 的模型。Percolator 是 Google 的上一代分布式事务解决方案,构建在 BigTable 之上,在 Google 内部用于网页索引更新的业务。原理比较简单,总体来说就是一个经过优化的 2PC 的实现,依赖一个单点的授时服务 TSO 来实现单调递增的事务编号生成,提供 SI 的隔离级别。传统的分布式事务模型中,一般都会有一个中央节点作为事务管理器,Percolator 的模型通过对于锁的优化,去掉了单点的事务管理器的概念,将整个事务模型中的单点局限于授时服务器上,在生产环境中,单点授时是可以接受的,因为 TSO 的逻辑极其简单,只需要保证对于每一个请求返回单调递增的 id 即可,通过一些简单的优化手段(比如 pipeline)性能可以达到每秒生成百万 id 以上,同时 TSO 本身的高可用方案也非常好做,所以整个 Percolator 模型的分布式程度很高。下面我们详细介绍一下 TiKV 中事务的实现方式。总体来说,TiKV 的读写事务分为两个阶段:1、Prewrite 阶段;2、Commit 阶段。客户端会缓存本地的写操作,在客户端调用 client.Commit() 时,开始进入分布式事务 prewrite 和 commit 流程。Prewrite 对应传统 2PC 的第一阶段: 首先在所有行的写操作中选出一个作为 primary row,其他的为 secondary rows PrewritePrimary: 对 primaryRow 写入锁(修改 meta key 加入一个标记),锁中记录本次事务的开始时间戳。上锁前会检查: 该行是否已经有别的客户端已经上锁 (Locking) 是否在本次事务开始时间之后,检查versions ,是否有更新 [startTs, +Inf) 的写操作已经提交 (Conflict) 在这两种种情况下会返回事务冲突。否则,就成功上锁。将行的内容写入 row 中,版本设置为 startTs 将 primaryRow 的锁上好了以后,进行 secondaries 的 prewrite 流程: 类似 primaryRow 的上锁流程,只不过锁的内容为事务开始时间 startTs 及 primaryRow 的信息 检查的事项同 primaryRow 的一致 当锁成功写入后,写入 row,时间戳设置为 startTs 以上 Prewrite 流程任何一步发生错误,都会进行回滚:删除 meta 中的 Lock 标记 , 删除版本为 startTs 的数据。当 Prewrite 阶段完成以后,进入 Commit 阶段,当前时间戳为 commitTs,TSO 会保证 commitTs > startTsCommit 的流程是,对应 2PC 的第二阶段: commit primary: 写入 meta 添加一个新版本,时间戳为 commitTs,内容为 startTs, 表明数据的最新版本是 startTs 对应的数据 删除 Lock 标记 值得注意的是,如果 primary row 提交失败的话,全事务回滚,回滚逻辑同 prewrite 失败的回滚逻辑。如果 commit primary 成功,则可以异步的 commit secondaries,流程和 commit primary 一致, 失败了也无所谓。Primary row 提交的成功与否标志着整个事务是否提交成功。事务中的读操作: 检查该行是否有 Lock 标记,如果有,表示目前有其他事务正占用此行,如果这个锁已经超时则尝试清除,否则等待超时或者其他事务主动解锁。注意此时不能直接返回老版本的数据,否则会发生幻读的问题。 读取至 startTs 时该行最新的数据,方法是:读取 meta ,找出时间戳为 [0, startTs], 获取最大的时间戳 t,然后读取为于 t 版本的数据内容。 由于锁是分两级的,Primary 和 Seconary row,只要 Primary row 的锁去掉,就表示该事务已经成功提交,这样的好处是 Secondary 的 commit 是可以异步进行的,只是在异步提交进行的过程中,如果此时有读请求,可能会需要做一下锁的清理工作。因为即使 Secondary row 提交失败,也可以通过 Secondary row 中的锁,找到 Primary row,根据检查 Primary row 的 meta,确定这个事务到底是被客户端回滚还是已经成功提交。大致的事务提交流程介绍到这,通过 MVCC, TiKV 的事务默认隔离级别是 Repeatable Read(SI), 也对外暴露显式的加锁的 API,用于为客户端实现 SELECT … FOR UPDATE 等隔离级别为 SSI 的语句。大家可以看到, 本质上 TiKV 的事务模型是基于 Percolator 的思想,但是对比原论文,做了很多工程上的优化,我们将原来论文中的 L 列和 W 列去掉,通过和MVCC 的 Meta 来存储相关的事务信息。对于事务冲突的情况,原始的 Percolator 的论文中并没有做过多的描述,采取的策略也比较简单,读时遇到锁就等直到锁超时或者被锁的持有者清除,写时遇到锁,直接回滚然后给客户端返回失败由客户端进行重试。TiKV 采用的是乐观事务模型,只有最后 2pc 的阶段会对数据加锁,但是对于频繁冲突的场景,回滚和客户端重试的代价可能很高, TiKV 在存储节点本地添加了一个简单的 Scheduler 层,在 2PC 读写遇到锁的时候并不是粗暴的直接回滚返回,而是尝试在本地排队等一下 ,如果超时或者其他异常,再返回客户端重试,减小了网络的开销。另外的一个问题是无效版本的清理(GC),对于在线上运行的 MVCC 系统来说,如果没有 GC 策略,那么版本将会膨胀得越来越多,而且对于 MVCC 来说,数据的删除并不是真正的删除,而是标记删除,当无用版本积累太多,会对于读性能有很大的影响。同时GC 策略并不能简单的指定一个版本(safe point),然后删除之前的所有版本,很显然比如有一个 key 只有一个版本,这个版本就不能动,比如有一个 key 在 safe point 前的最后一个版本是 tombstone (已经删除),而且这个 key 之后再没有被操作过,那么这个 key 的所有版本都是可以被整体删除的。另外,在实际实现的过程中还会遇到一个问题,当 gc 一个 key 时发现 meta 中有锁(可能是由于清除 secondary lock 时客户端崩溃或者其他原因),你并不能简单删除之,因为如果这个 key 中的锁是 secondary lock,在 gc 进程去查看这个锁对应的 primary key 的对应版本是提交还是回滚时,如果 primary key 的那个版本已经被 gc 删除掉了,对于 gc 进程来说就没有办法确定该事务到底是提交还是回滚,可能出现数据误删的情况。TiKV 通过对事务的 primary key 的 meta version 进行一个特殊的标记,由于没有集中事务管理器的存在,判断一个事务的执行状态只有 primary key 的 meta 中有记录,所以在 gc 时会绕过这些 primary key 的 version 解决了这个问题,保证了数据的安全。"}, {"url": "https://pingcap.com/weekly/2016-08-29-tidb-weekly/", "title": "Weekly update (August 22 ~ August 28, 2016)", "content": " Weekly update (August 22 ~ August 28, 2016) Last week, we landed 26 PRs in the TiDB repositories and 26 PRs in the TiKV repositories.Notable changes to TiDB Support the MySQL SetOption Command and Multiple Statements. Support filter push-down for the Time/Decimal type. Support converting OuterJoin to InnerJoin by using Null Reject. Support multiple-thread Hash Join. Support Garbage Collector. Optimize the code to improve the Performance. Fix several bugs. Notable changes to TiKV Coprocessor supports the time type. Output the version information when TiKV starts. Append the write column family when committing lock-only keys to fix bug #921. Use randomized Placement Driver (PD) server and remove getting PD leader to solve issues #942 and #956. Support the Debug traits for messages in the sending channel. Coprocessor uses configuration to make the endpoint threadpool size configurable. Notable changes to Placement Driver Output the version information when PD starts. Save the next timestamp oracle(TSO) to solve issue #191. "}, {"url": "https://pingcap.com/meetup/meetup-2016-08-27/", "title": "PingCAP 第 21 期 NewSQL Meetup", "content": " PingCAP 第 21 期 NewSQL Meetup 2016-08-27 韩飞&申砾 PingCAP PingCAPPingCAP ![]() 微信号pingcap2015功能介绍PingCAP 专注于新型分布式数据库的研发,是知名开源数据库 TiDB (GitHub 总计10000+ stars ) 背后的团队,总部设在北京,是国内第一家开源的新型分布式关系型数据库公司、国内领先的大数据技术和解决方案提供商。NewSQL Meetup今天是 PingCAP 第 21 期 Meetup,主题是韩飞分享的《An Introduction to Join-Reorder in TiDB》以及申砾分享的《MPP and SMP in TiDB》。▌ ****Topic 1:An Introduction to Join-Reorder in TiDBContent:本次分享详细介绍了 TiDB 中 Join-Reorder 的流程。包括 Join-Reorder 的动机,outer-join 的 reorder 局限性和解决办法。为了解决某些 outer join re-association 的问题,我们可以引入的新算子 Generalized outerJoin。最后介绍了通过为 Join Query 建立 Query Graph 进行启发式搜索和动态规划的Join-Reorder算法。▌ ****Topic 2:MPP and SMP in TiDBContent:TiDB 是一个支持水平扩展的分布式数据库,除了提供海量数据存储能力之外,还需要提供海量数据的计算能力,这样才能帮助用户更好、更容易地使用数据。为此我们开发了一套分布式计算框架,一方面利用海量的存储节点的计算能力,加快数据处理速度;另一方面在单个计算节点内,我们利用 Go 的并发优势,通过 SMP 方式提高计算并行度。本次 Talk 首先介绍了 TiDB 分布式计算架构,并举例说明计算的具体流程;然后分享了最近 TiDB 针对索引查询和 Join 做的一系列优化,性能有大幅度提高;最后列出了一些 NewSQL database 中如何做计算值得思考的问题。PingCAP Meetup"}, {"url": "https://pingcap.com/weekly/2016-08-22-tidb-weekly/", "title": "Weekly update (August 13 ~ August 21, 2016)", "content": " Weekly update (August 13 ~ August 21, 2016) Last week, we landed 26 PRs in the TiDB repositories and 15 PRs in the TiKV repositories.Notable changes to TiDB Upgrade the query optimizer. Upgrade the lexer. Replace golang protobuf with gogo protobuf. Optimize the distributed executor. Repair the Time and Decimal types to improve the compatibility with MySQL. Support the Set names binary statement. Support Covering Index. Optimize the table scanning when the condition is false constant. Fix several bugs. Notable changes to TiKV Add the leader lease read support for better performance, see benchmark. Use delete_file_in_range from RocksDB to destroy Regions quickly to avoid blocking Raft storage threads. Support GC for obsolete data versions. Coprocessor supports covering index for Select Where and the aggregation operations. Check whether the key is already rolled back when prewrite to fix a transaction bug. Support the --log-file flag to redirect log to the log file. Notable changes to Placement Driver Refine the join flag to support multiple join scenarios. Use unix socket in test to avoid the “Address Already in Use” error. Redirect requests to the Leader if the current member is a Follower. Benchmark Use sysbench to benchmark leader lease read and previous Raft quorum read in 3-node TiKV.Insert # Prepare data sysbench --test=./lua-tests/db/oltp.lua --mysql-host=${host} --mysql-port=${port} --mysql-user=${user} --mysql-password=${password} --oltp-tables-count=$1 --oltp-table-size=5120000 --rand-init=on prepare # Run benchmark sysbench --test=./lua-tests/db/insert.lua --mysql-host=${host} --mysql-port=${port} --mysql-user=${user} --mysql-password=${password} --oltp-tables-count=1 --oltp-table-size= 5120000 --num-threads=${threads} --report-interval=60 --max-requests=1280000 --percentile=99 run |Threads|Leader lease read qps|Leader lease read avg/.99 latency|Raft quorum read qps|Raft quorum read/.99 latency| |—|—|—|—|—|—| |32|2296|13.93⁄15.28|1315|24.33⁄94| |64|2199|29.1⁄145|1325|48.29⁄473| |128|1854|69⁄931|1290|99⁄697|As we can see, the qps is increased by about 70%, and the latency is decreased by about 40%.Select # Prepare data sysbench --test=./lua-tests/db/oltp.lua --mysql-host=${host} --mysql-port=${port} --mysql-user=${user} --mysql-password=${password} --oltp-tables-count=1 --oltp-table-size=5120000 --rand-init=on prepare # Run benchmark sysbench --test=./lua-tests/db/select.lua --mysql-host=${host} --mysql-port=${port} --mysql-user=${user} --mysql-password=${password} --oltp-tables-count=1 --oltp-table-size=5120000 --num-threads=${threads} --report-interval=60 --max-requests=1280000 --percentile=99 run |Threads|Leader lease read qps|Leader lease read avg/.99 latency|Raft quorum read qps|Raft quorum read/.99 latency| |—|—|—|—|—|—| |32|21010|1.52⁄7.53|12221|2.62⁄6.69| |64|25948|2.47⁄10.20|12637|5.06/11.62| |128|27283|4.69⁄13.68|11069|11.56⁄35.88|As we can see, the qps is increased by about 130%, and the latency is decreased by about 50%.New contributors hhkbp2 "}, {"url": "https://pingcap.com/meetup/meetup-2016-08-20/", "title": "PingCAP 第 20 期 NewSQL Meetup", "content": " PingCAP 第 20 期 NewSQL Meetup 2016-08-20 雷丽媛&温文鎏 PingCAP PingCAPPingCAP ![]() 微信号pingcap2015功能介绍PingCAP 专注于新型分布式数据库的研发,是知名开源数据库 TiDB (GitHub 总计10000+ stars ) 背后的团队,总部设在北京,是国内第一家开源的新型分布式关系型数据库公司、国内领先的大数据技术和解决方案提供商。NewSQL Meetup今天是 PingCAP 第 20 期 Meetup,主题是百度网页搜索部工程师雷丽媛分享的《搜索引擎背后的万亿量级存储系统 Tera 》以及温文鎏分享的《Cloudtable:分布式强一致的 KV 存储系统》。【Topic 1】搜索引擎背后的万亿量级存储系统 Tera近景福利:今日的美女讲师 :)Lecture:雷丽媛,百度网页搜索部工程师。专注于分布式存储领域,目前负责百度结构化数据存储和分布式文件系统的相关工作。Content:介绍支撑搜索引擎核心的海量存储——Tera 的设计与实现【 ****Topic 2】Cloudtable:分布式强一致的 KV 存储系统Content:如何搭建一个适用于互联网公司业务的大容量分布式强一致性 KV 存储系统?通过结合分布式一致性协议 Raft,嵌入式存储引擎 RocksDB,HBASE 的架构和接口,YY 云存储团队在过去的两年开发了 Cloudtable 存储系统,它是一个分布式强一致性的 KV 存储系统。今天,前 YY 云存储工程师温文鎏分享了他们在构建 Cloudtbable 系统的实践和经验。PingCAP Meetup"}, {"url": "https://pingcap.com/blog-cn/building-distributed-db-with-raft/", "title": "基于 Raft 构建弹性伸缩的存储系统的一些实践", "content": "最近几年来,越来越多的文章介绍了 Raft 或者 Paxos 这样的分布式一致性算法,且主要集中在算法细节和日志同步方面的应用。但是呢,这些算法的潜力并不仅限于此,基于这样的分布式一致性算法构建一个完整的可弹性伸缩的高可用的大规模存储系统,是一个很新的课题,我结合我们这一年多以来在 TiKV 这样一个大规模分布式数据库上的实践,谈谈其中的一些设计和挑战。本次分享的主要内容是如何使用 Raft 来构建一个可以「弹性伸缩」存储。其实最近这两年也有很多的文章开始关注类似 Paxos 或者 Raft 这类的分布式一致性算法,但是主要内容还是在介绍算法本身和日志复制,但是对于如何基于这样的分布式一致性算法构建一个大规模的存储系统介绍得并不多,我们目前在以 Raft 为基础去构建一个大规模的分布式数据库 TiKV ,在这方面积累了一些第一手的经验,今天和大家聊聊类似系统的设计,本次分享的内容不会涉及很多 Raft 算法的细节,大家有个 Paxos 或者 Raft 的概念,知道它们是干什么的就好。##先聊聊 Scale 其实一个分布式存储的核心无非两点,一个是 Sharding 策略,一个是元信息存储,如何在 Sharding 的过程中保持业务的透明及一致性是一个拥有「弹性伸缩」能力的存储系统的关键。如果一个存储系统,只有静态的数据 Sharding 策略是很难进行业务透明的弹性扩展的,比如各种 MySQL 的静态路由中间件(如 Cobar)或者 Twemproxy 这样的 Redis 中间件等,这些系统都很难无缝地进行 Scale。 ##Sharding 的几种策略 在集群中的每一个物理节点都存储若干个 Sharding 单元,数据移动和均衡的单位都是 Sharding 单元。策略主要分两种,一种是 Range 另外一种是 Hash。针对不同类型的系统可以选择不同的策略,比如 HDFS 的Datanode 的数据分布就是一个很典型的例子:###首先是 Range Range 的想法比较简单粗暴,首先假设整个数据库系统的 key 都是可排序的,这点其实还是蛮普遍的,比如 HBase 中 key 是按照字节序排序,MySQL 可以按照自增 ID 排序,其实对于一些存储引擎来说,排序其实是天然的,比如 LSM-Tree 或者 BTree 都是天然有序的。Range 的策略就是一段连续的 key 作为一个 Sharding 单元:例如上图中,整个 key 的空间被划分成 (minKey, maxKey),每一个 Sharding 单元(Chunk)是一段连续的 key。按照 Range 的 Sharding 策略的好处是临近的数据大概率在一起(例如共同前缀),可以很好的支持 range scan 这样的操作,比如 HBase 的 Region 就是典型的 Range 策略。但是这种策略对于压力比较大的顺序写是不太友好的,比如日志类型的写入 load,写入热点永远在于最后一个 Region,因为一般来说日志的 key 基本都和时间戳有关,而时间显然是单调递增的。但是对于关系型数据库来说,经常性的需要表扫描(或者索引扫描),基本上都会选用 Range 的 Sharding 策略。###另外一种策略是 Hash 与 Range 相对的,Sharding 的策略是将 key 经过一个 Hash 函数,用得到的值来决定 Sharding ID,这样的好处是,每一个 key 的分布几乎是随机的,所以分布是均匀的分布,所以对于写压力比较大、同时读基本上是随机读的系统来说更加友好,因为写的压力可以均匀的分散到集群中,但是显然的,对于 range scan 这样的操作几乎没法做。比较典型的 Hash Sharding 策略的系统如:Cassandra 的一致性 Hash,Redis Cluster 和 Codis 的 Pre-sharding 策略,Twemproxy 有采用一致性 Hash 的配置。当然这两种策略并不是孤立的,可以灵活组合,比如可以建立多级的 Sharding 策略,最上层用 Hash ,每一个 Hash Sharding 中,数据有序的存储。在做动态扩展的时候,对于 Range 模型的系统会稍微好做一些,简单来说是采用分裂,比如原本我有一个 [1, 100) 的 Range Region,现在我要分裂,逻辑上我只需要简单的将这个 region 选取某个分裂点,如分裂成 [1,50), [50, 100) 即可,然后将这两个 Region 移动到不同的机器上,负载就可以均摊开。但是对于 Hash 的方案来说,做一次 re-hash 的代价是挺高的,原因也是显而易见,比如现在的系统有三个节点,现在我添加一个新的物理节点,此时我的 hash 模的 n 就会从 3 变成 4,对于已有系统的抖动是很大,尽管可以通过 ketama hash 这样的一致性 hash 算法尽量的降低对已有系统的抖动,但是很难彻底的避免。###Sharding 与高可用方案结合 选择好了 sharding 的策略,那剩下的就是和高可用方案结合,不同的复制方案达到的可用性及一致性级别是不同的。很多中间件只是简单的做了 sharding 的策略,但是并没有规定每个分片上的数据的复制方案,比如 redis 中间件 twemproxy 和 codis,MySQL 中间件 cobar 等,只是在中间层进行路由,并未假设底层各个存储节点上的复制方案。但是,在一个大规模存储系统上,这是一个很重要的事情,由于支持弹性伸缩的系统一般来说整个系统的分片数量,数据分片的具体分布都是不固定的,系统会根据负载和容量进行自动均衡和扩展,人工手动维护主从关系,数据故障恢复等操作在数据量及分片数量巨大的情况下几乎是不可能完成的任务。选择一个高度自动化的高可用方案是非常重要的。在 TiKV 中,我们选择了按 range 的 sharding 策略,每一个 range 分片我们称之为 region,因为我们需要对 scan 的支持,而且存储的数据基本是有关系表结构的,我们希望同一个表的数据尽量的在一起。另外在 TiKV 中每一个 region 采用 Raft 算法在多个物理节点上保证数据的一致性和高可用。从社区的多个 Raft 实现来看,比如 Etcd / LogCabin / Consul 基本都是单一 raft group 的实现,并不能用于存储海量的数据,所以他们主要的应用场景是配置管理,很难直接用来存储大量的数据,毕竟单个 raft group 的参与节点越多,性能越差,但是如果不能横向的添加物理节点的话,整个系统没有办法 scale。scale 的办法说来也很简单,采用多 raft group,这就很自然的和上面所说的 sharding 策略结合起来了,也就是每一个分片作为一个 raft group,这是 TiKV 能够存储海量数据的基础。但是管理动态分裂的多 raft group 的复杂程度比单 group 要复杂得多,目前 TiKV 是我已知的开源项目中实现 multiple raft group 的仅有的两个项目之一。正如之前提到过的我们采用的是按照 key range 划分的 region,当某一个 region 变得过大的时候(目前是 64M),这个 region 就会分裂成两个新的 region,这里的分裂会发生在这个 region 所处的所有物理节点上,新产生的 region 会组成新的 raft group。###总结 构建一个健壮的分布式系统是一个很复杂的工程,上面提到了在 TiKV 在实践中的一些关键的设计和思想,希望能抛砖引玉。因为 TiKV 也是一个开源的实现,作为 TiDB 的核心存储组件,最近也刚发布了 Beta 版本,代码面前没有秘密,有兴趣深入了解的同学也可以直接阅读源码和我们的文档,谢谢大家。##Q&A Q1:如何在这个 region 的各个副本上保证分裂这个操作安全的被执行? 其实这个问题比较简单,就是将 split region 这个操作作为一个 raft log,走一遍 raft 状态机,当这个 log 成功 apply 的时候,即可以认为这个操作被安全的复制了(因为 raft 算法干得就是这个事情)。确保 split log 操作被 accept 后,对新的 region 在走一次 raft 的选举流程(也可以沿用原来的 leader,新 region 的其他节点直接发心跳)。split 的过程是加上网络隔离,可能会产生很复杂的 case,比如一个复杂的例子:a, b 两个节点,a 是 leader, 发起一个分裂 region 1 [a, d) -> region 1 [a, b) + region 2 [b, d), region 2的 heartbeart 先发到 b,但这时候 region 2 分裂成了 region 2 [b, c) + region 3 [c, d),给 b 发送的 snapshot 是最新的 region 2 的 snapshot [b, c),region 1的 split log 到了 b,b 的老 region 1 也分裂成了 region 1 [a, b) + region 2 [b,d), 这之后 a 给 b 发送的最新的 region 2 的 snapshot [b, c) 到了,region 2 被 apply 之后,b 节点的 region 2 必须没有 [c, d) 区间的数据。Q2:如何做到透明? 在这方面,raft 做得比 paxos 好,raft 很清晰的提供了 configuration change 的流程,configuration change 流程用于应对 raft gourp 安全的动态添加节点和移除节点,有了这个算法,在数据库中 rebalance 的流程其实能很好的总结为:对一个 region: add replica / transfer leadership / remove local replica这三个流程都是标准的 raft 的 configuration change 的流程,TiKV 的实现和 raft 的 paper 的实现有点不一样的是:config change 的 log 被 apply 后,才会发起 config change 操作,一次一个 group 只能处理一个 config change 操作,避免 disjoint majority,不过这点在 diego 的论文里提到过。主要是出于正确性没问题的情况下,工程实现比较简单的考虑。 另外这几个过程要做到业务层透明,也需要客户端及元信息管理模块的配合。毕竟当一个 region 的 leader 被转移走后,客户端对这个 region 的读写请求要发到新的 leader 节点上。客户端这里指的是 TiKV 的 client sdk,下面简称 client , client 对数据的读写流程是这样的:首先 client 会本地缓存一份数据的路由表,这个路由表形如:{startKey1, endKey1} -> {Region1, NodeA} {startKey2, endKey2} -> {Region2, NodeB} {startKey3, endKey3} -> {Region3, NodeC} … client 根据用户访问的 key,查到这个 key 属于哪个区间,这个区间是哪个 region,leader 现在在哪个物理节点上,然后客户端查到后直接将这个请求发到这个具体的 node 上,刚才说过了,此时 leader 可能已经被 transfer 到了其他节点,此时客户端会收到一个 region stale 的错误,客户端会向元信息管理服务请求然后更新自己的路由表缓存。这里可以看到,路由表是一个很重要的模块,它需要存储所有的 region 分布的信息,同时还必须准确,另外这个模块需要高可用。另一方面,刚才提到的数据 rebalance 工作,需要有一个拥有全局视角的调度器,这个调度器需要知道哪个 node 容量不够了,哪个 node 的压力比较大,哪个 node region leader 比较多?以动态的调整 regions 在各个 node 中的分布,因为每个 node 是几乎无状态的,它们无法自主的完成数据迁移工作,需要依靠这个调度器发起数据迁移的操作(raft config change)。大家应该也注意到了,这个调度器的角色很自然的能和路由表融合成一个模块,在 Google Spanner 的论文中,这个模块的名字叫 Placement Driver, 我们在 TiKV 中沿用了这个名称,简称 pd,pd 主要的工作就是上面提到的两项:1. 路由表 2. 调度器。 Spanner 的论文中并没有过多的介绍 pd 的设计,但是设计一个大规模的分布式存储系统的一个核心思想是一定要假设任何模块都是会 crash 的,模块之间互相持有状态是一件很危险的事情,因为一旦 crash,standby 要立刻启动起来,但是这个新实例状态不一定和之前 crash 的实例一致,这时候就要小心会不会引发问题. 比如一个简单的 case :因为 pd 的路由表是存储在 etcd 上的,但是 region 的分裂是由 node 自行决定的 ( node 才能第一时间知道自己的某个 region 大小是不是超过阈值),这个 split 事件如果主动的从 node push 到 pd ,如果 pd 接收到这个事件,但是在持久化到 etcd 前宕机,新启动的 pd 并不知道这个 event 的存在,路由表的信息就可能错误。我们的做法是将 pd 设计成彻底无状态的,只有彻底无状态才能避免各种因为无法持久化状态引发的问题。每个 node 会定期的将自己机器上的 region 信息通过心跳发送给 pd, pd 通过各个 node 通过心跳传上来的 region 信息建立一个全局的路由表。这样即使 pd 挂掉,新的 pd 启动起来后,只需要等待几个心跳时间,就又可以拥有全局的路由信息,另外 etcd 可以作为缓存加速这一过程,也就是新的 pd 启动后,先从 etcd 上拉取一遍路由信息,然后等待几个心跳,就可以对外提供服务。但是这里有一个问题,细心的朋友也可能注意到了,如果集群出现局部分区,可能某些 node 的信息是错误的,比如一些 region 在分区之后重新发起了选举和分裂,但是被隔离的另外一批 node 还将老的信息通过心跳传递给 pd,可能对于某个 region 两个 node 都说自己是 leader 到底该信谁的?在这里,TiKV 使用了一个 epoch 的机制,用两个逻辑时钟来标记,一个是 raft 的 config change version,另一个是 region version,每次 config change 都会自增 config version,每次 region change(比如split、merge)都会更新 region version. pd 比较的 epoch 的策略是取这两个的最大值,先比较 region version, 如果 region version 相等则比较 config version 拥有更大 version 的节点,一定拥有更新的信息。"}, {"url": "https://pingcap.com/weekly/2016-08-12-tidb-weekly/", "title": "Weekly update (August 05 ~ August 12, 2016)", "content": " Weekly update (August 05 ~ August 12, 2016) Last week, we landed 20 PRs in the TiDB repositories and 11 PRs in the TiKV repositories.Notable changes to TiDB Rewrite Lexer and improve the speed of parsing SQL texts by 40%. Add a command line flag for log output file and rotate log files regularly. Optimize the 2 phase commit process and adopt faster methods to clear locks. Optimize the execution speed of the Insert On Duplicate Update statement. Update the Documents repository. Fix several bugs. Notable changes to TiKV Support the Scan and Resolve transaction lock. Support garbage collection(GC) stale peer. Use a Write column family to store transaction commit logs. Remove the unnecessary Seek operation. Fix random quorum test. Notable changes to Placement Driver Support the get PD leader API. "}, {"url": "https://pingcap.com/meetup/meetup-2016-08-11/", "title": "TiDB 优化器实现的基础 -- 统计信息的收集", "content": " TiDB 优化器实现的基础 – 统计信息的收集 原创2016-08-11 周昱行 PingCAP PingCAPPingCAP ![]() 微信号pingcap2015功能介绍PingCAP 专注于新型"}, {"url": "https://pingcap.com/meetup/meetup-2016-08-06/", "title": "PingCAP 第 19 期 NewSQL Meetup", "content": " PingCAP 第 19 期 NewSQL Meetup 2016-08-06 方君&韩飞 PingCAP PingCAPPingCAP ![]() 微信号pingcap2015功能介绍PingCAP 专注于新型分布式数据库的研发,是知名开源数据库 TiDB (GitHub 总计10000+ stars ) 背后的团队,总部设在北京,是国内第一家开源的新型分布式关系型数据库公司、国内领先的大数据技术和解决方案提供商。NewSQL Meetup今天是 PingCAP 第 19 期 Meetup,主题是百度基础架构部工程师方君分享的《What’s New in Spark 2.0》以及韩飞分享 的《An Overview of Cost Based Optimization and Join Reorder》。▌ ****Topic 1:What’s New in Spark 2.0Lecture:方君,百度基础架构部工程师,专注于分布式计算与流式计算领域,目前在百度负责 Spark 计算平台和计算表示层的相关工作。Content: DataSet API Performance Optimization Structure Streaming ▌ ****Topic 2:An Overview ofCost Based Optimization and Join ReorderContent:自从 System R 优化框架面世,基于 interesting order 的动态规划算法一直是大部分优化器采用的基础算法。本次分享介绍了优化器在没有 histogram 信息下的代价估计算法,以及举例说明 TiDB 中的动态规划算法实现。最近有好多小伙伴在微信后台留言,想加入到我们的 Meetup 中来。在这里统一答复大家:我们的 Meetup 是每周六上午十点,在 PingCAP 公司内开讲哦。有兴趣的小伙伴届时带着你们对技术满满的热情来参加就好啦 :)PingCAP Meetup"}, {"url": "https://pingcap.com/weekly/2016-08-05-tidb-weekly/", "title": "Weekly update (July 30 ~ August 05, 2016)", "content": " Weekly update (July 30 ~ August 05, 2016) Last week, we landed 28 PRs in the TiDB repositories and 32 PRs in the TiKV repositories.Notable changes to TiDB Add support for constant folding in the SQL optimizer. Optimize the query speed of the secondary index. In certain scenarios, only the data in the index needs to be read. Use dynamic programing to decide the join path for multiple tables. Adjust the command line to support setting the listening address. Prometheus metrics and golang pprof share the same port. Update the Documents repository. Fix several bugs.Notable changes to TiKV Split the operations on RocksDB from scheduler thread to a worker pool. Support leader lease mechanism when the quorum check is enabled. Use pending snapshot regions check to avoid receiving multiple overlapping snapshots at the same time. Check down peers and report to Placement Driver(PD). Support time monitor to check whether time jumps back or not. Notable changes to Placement Driver Reduce the “1234” and “9090” ports in PD. Now PD has only “2379” and “2380” ports for external use. Support the join flag to let PD join an existing cluster dynamically. Support the remove PD member API to remove a PD from a cluster dynamically. Support the list PD members API. "}, {"url": "https://pingcap.com/blog-cn/cloud-native-db/", "title": "云时代数据库的核心特点", "content": " 引言 最近几年,随着云计算相关技术的发展,各种不同类型的云层出不穷,服务越来越多不同类型的企业业务,传统企业也渐渐开始探索上云的道路。在云上,作为业务最核心的数据库,相比之前的传统方案会有哪些变化呢?在正式聊云时代的数据库特点之前,我们需要了解一下目前云时代架构发生的变化。畅想一下,未来的服务都跑在云端,任何的服务资源都可以像水电煤一样按需选购。从 IaaS 层的容器/虚拟机,到 PaaS 层的数据库,缓存和计算单元,再到 SaaS 层的不同类型的应用,我们只需要根据自身业务特点进行资源选配,再也不用担心应用服务支撑不住高速的业务增长,因为在云上一切都是弹性伸缩的。有了可靠的基础软件架构,我们就可以把更多精力放到新业务的探索,新模式的创新,就有可能产生更多不一样的新场景,从而催生更强大能力的云端服务,这是一件多么 cool 的事情。当然,理想要一步一步实现,未来的基础软件栈到底会怎样呢?社区在这方面正在进行积极地探索,其中最有代表性的就是基于容器(以 Docker 为代表)的虚拟化技术和微服务(Microservice)。在云时代,一切都应该是可伸缩的,使用 k8s(Kubernetes)在保证资源平衡的前提下,通过 Docker 部署我们依托于容器的微服务模块,我们不用关心服务到底跑在哪里,只需要关心我们需要多少服务资源。Docker 提供了极大的便利性,一次构建,到处运行,我们可以很好地解决开发、测试和上线的环境一致性问题。(如果不能很好地保证测试和实际上线环境的一致性,则很有可能需要花费远超过开发的时间去发现和修复问题。)k8s 更是在 Docker 构建的基础上增加了更多的云特性,包括 Docker 的升级,高可用和弹性伸缩等等。 关于 Docker/k8s 相关的讨论已经很多了,因为时间关系,关于具体的细节就不再展开。我们只需要了解,有了它,可以很轻松地解决服务的安装和部署。下面再聊聊微服务,微服务将一个服务拆分成相对独立的更小的子服务单元,不同的子服务单元之间通过统一的接口(HTTP/RPC 等)进行数据交互。相比于传统的解决方案,这种架构有很多的优点。 更好的开发效率和可维护性。微服务将一个单独的服务进行更细力度的拆分,每一个子服务单元专注于更小的功能模块,可以更好地根据业务建立对应的数据模型,降低复杂度,使得开发变得更轻松,维护和部署变得更加友好. 更好的可扩展性。每个不同的子服务单元相互独立,彼此之间没有任何依赖,所以可以根据业务的具体需要,灵活地部署多个子服务单元进行水平扩展。 更强的容错性。当其中一个子服务出现故障的时候,可以通过辅助的负载均衡工具,自动路由到其他的子服务,不会影响整体服务的可用性. 当然,微服务也不是一个银弹,相对来说,这种方案会使整体系统的设计更加复杂,同时也加大了网络的延迟,对整个系统测试的复杂度也会更高。Docker 提供的隔离型和可移植性,与微服务是一种天然的契合,微服务将整个软件进行拆分和解耦,而通过 Docker/k8s 可以很自然地做到独立的部署,高可用和容错性,似乎一切都可以完美地运转起来。但是真的是这样么?我们是不是忽略了什么?是的,我们在讨论前面的问题的时候忽略了一个很重要的东西:状态。从整个技术发展的角度来看,微服务是一个非常有意义的探索。每个人都期望着每个微服务的子服务都是无状态的,这样我可以自由地启停和伸缩,没有任何的心智负担,但是现实的业务情况是什么样的呢?比如一个电商网站,用户正在下单购买一件商品,此时平台是通过订单子服务的 A 应用来提供服务的,突然,因为机器故障,订单子服务的 A 应用不可用了,改由订单子服务的 B 应用提供服务,那么它是必须要知道刚才用户的订单信息的,否则正在访问自己订单页面的用户会发现自己的订单信息突然不见了。虽然我们尽量想把子服务设计成无状态的,但是很多时候状态都是不可避免的,我们不得不通过存储层保存状态,业界最主要的还是各种数据库,包括 RDBMS 和 NoSQL,比如使用 MySQL、MongoDB、HBase、Cassandra 等,特别是有些场景还要考虑数据一致性问题的时候,更加重了对存储层的依赖。由此可见,云计算时代系统的架构发生了巨大的变化,这一方面为用户提供了更优秀的特性,另一方面也对云计算的组件提出了更高的要求。数据库作为云计算最基础的组件之一,也需要适应这种架构的变化。(这里我们主要关注 SQL 数据库,云时代的数据库以下简称云数据库。)那么云数据库主要有一些什么样的特点呢?我认为主要有以下几点。 弹性伸缩 传统的数据库方案,常见的会选用 Oracle,MySQL,PostgreSQL。在云时代,数据量的规模有爆发性的增长,传统的数据库很容易遇到单机的存储瓶颈,不得不选用一些集群方案,常见的比如 Oracle RAC、 MySQL Sharding 等,而这些集群方案或多或少都有一些不令人满意的地方。比如说,Oracle RAC 通过共享存储的硬件方案解决集群问题,这种方式基本上只能通过停机换用更大的共享内存硬件来解决扩容问题,RAC 节点过多会带来更多的并发问题,同样也会带来更高的成本。以 MySQL Sharding 为代表的数据分片方案,很多时候不得不提前对数据量进行规划,把扩容作为很重要的一个计划来做,从 DBA 到运维到测试到开发人员,很早之前就要做相关的准备工作,真正扩容的时候,为了保证数据安全,经常会选择停服务来保证没有新的数据写入,新的分片数据同步后还要做数据的一致性校验。当然业界大公司有足够雄厚的技术实力,可以采用更复杂的方案,将扩容停机时间尽量缩短(但是很难缩减到 0),但是对于大部分中小互联网公司和传统企业,依然无法避免较长时间的停服务。在云时代,理想中所有的资源都是根据用户业务需求按需分配的,服务器资源,应用容器资源,当然也包括数据库资源。添加或者减少新的数据库资源,完全就像日常吃饭那样稀疏平常,甚至用户基本感知不到。比如作为一个电商用户,在双 11 促销活动之前,可以通过增加数据库节点的方式,扩大更多的资源池,用来部署相应的容器服务,当活动结束之后,再将多余的资源移除去支持其他的服务,这样可以极大地提高资源的利用率,同样可以弹性地支撑各种峰值业务。高可用 传统的 MySQL 方案,数据复制的时候默认采用异步的方式,对于一个写入的请求,主库写入成功后就会返回成功信息给客户端,但是这个时候数据可能还没有同步给从库,一旦主库这个时候挂掉了,启动从库的时候就会有丢失数据的风险。当然,也有人会选择半同步的复制方式,这种方式在正常情况下是同步的,但是在遇到数据压力比较大的时候,依然会退化为异步的方式,所以本质上来说,同样有丢失数据的风险。其他也有一些多主的同步方案,比如在应用层做数据同步,但是这种方式一是需要应用层的配合,二是在对网络超时的处理非常复杂,增加心智负担。在云时代,因为所有的数据库资源都是分布式存储的,每个数据库节点出现问题都是很正常的事情,所以就必须有一种可以实现数据一致性的数据复制方式来保证服务的高可用,业界给出的答案就是:Paxos/Raft(关于 Paxos 和 Raft 的实现细节我们不在这里展开)。PingCAP 在做的 TiDB 就是选择了 Raft 协议,Raft 协议看起来更像是一个多副本的自适应的主从复制协议,对于每次写请求,Raft 都会保证大多数写成功才会返回客户端,即使 Raft Group的Leader 挂掉了,在一个有限的时间范围内,会很快地选出一个新的 Leader 出来,继续提供服务。同样,对于一个 3 副本的 Raft Group,只要 2 个写入成功,就可以保证成功,而大多数情况下,最先写入成功的往往是与 Leader 网络情况最好的那个副本,所以这种 Majority 写的方式,可以很自然地选择速度最快的副本进行数据同步复制。另外,Raft 协议本身支持 Config Change,增加一个新的节点,可以很容易地做副本数据分布的变更,而不需要停止任何服务。同样,在云时代,数据库的 DDL 操作也会是一个非常有趣的事情。以一个常见的 Add Column 操作为例,在表规模已经很大的情况下,在传统的实现方案中,比较有参考意义的是,通过一些工具,创建类似表级别的触发器,将原表的数据同步到一个新的临时表中,当数据追平的时候,再进行一个锁表操作,将临时表命名为原表,这样一个 Add Column 操作就完成了。但是在云时代,分布式的数据存储方式决定了这种方案很难实现,因为每个数据库节点很难保证 Schema 状态变更的一致性,而且当数据规模增长到几十亿,几百亿甚至更多的时候,很短的阻塞时间都有可能会导致很大的负载压力变化,所以 DDL 操作必须是保证无阻塞的在线操作。值得欣慰的是,Google 的 F1 给我们提供了很好的实现参考,TiDB 即是根据 F1 的启发进行的研发,感兴趣的同学可以看下相关的内容。易用透明 我们可以将云数据库想象成一个提供无限大容量的数据库,传统数据库遇到单机数据存储瓶颈的问题将不复存在。已有的程序基本上不怎么需要修改已有的代码,就可以很自然地接入到云数据库中来获得无限 Scale 的能力。增减数据库节点,或者节点的故障恢复,对于应用层来说完全透明。另外,云数据库的监控、运维、部署、备份等等操作都可以在云端通过高效的自动化工具来自动完成,极大地降低了运维成本。多租户 云数据库本身应该是可以弹性伸缩的,所以很自然的,从资源利用率的角度来考虑,多个不同用户的数据库服务底层会跑在一个共享的云数据库中。因此多租户技术会成为云数据库的标配。但是这里面就有一个不得不面对的问题,如何做到不同用户的隔离性?用户数据隔离是相对比较容易的,比如还是以电商用户(这里说的是电商企业,不是顾客客户)为例,每个用户都有一个唯一的 ID,这样在云数据库的底层存储中,可以保证每个用户数据都带有自己 ID 前缀,用户登陆进来的时候可以根据这个前缀规则,获取他对应的数据,同时他看不到其他用户的数据。在一个真实的多租户环境下面,纯粹的数据隔离往往是不够的,你还需要做到资源公平性的隔离。比如有的用户写一个 SQL,这个 SQL 没有做优化,主要做的事情是一个全表描扫,这个表的数据量特别特别大,这样他会吃掉很多的 CPU、Memory、IO 等资源,导致其他用户很轻量级的 SQL 操作都可能会变得很慢,影响到其他用户实际的体验。那么针对这种情况怎么做隔离?与此类似的还有,网络带宽怎么做隔离?大家都是跑在一个云数据库上面的,如果一个用户存放的数据特别大,他把带宽都吃掉了,别人就显得非常慢了。还有一种情况,如果我本身作为一个租户,内部又怎么做隔离,大家知道 MySQL 可以建很多 Database,不同的 Database 给不同的团队来用,那么他们之间内部隔离又怎么做,这个问题就进一步更加复杂了。目前来讲没有特别好的方法,在一个分布式的环境下面去做很好的隔离,有两个方向可以考虑:第一种是最简单也是有效的方法,制定一些规则,把某些用户特别大的数据库表迁移到独享的服务器节点上面,这样就不会影响其他用户的服务,但是这里面就涉及到定制化的事情了,本身理念其实与云数据库并不相符。第二种就是依靠统计信息,做资源隔离和调度,但是这里面对技术的要求就比较高了。因为云数据库是分布式的,所以一般的统计都要横跨很多的机器,因为网络原因,不可能做到完全准确的统计,所有统计都是有延迟的。比如说对于某个用户,现在统计到的流量是 1 个 G,他可能突然就有一次峰值的网络访问,可能下一次统计消耗的流量是 5 个 G(这里面只是举例说明问题),如果你给他流量限制是 1 个 G,中间统计的间隔是多少比较合适,如果间隔比较小,那么这个对整个系统的压力就比较大,可能影响正常的用户 SQL 访问,另外本身这个流量限制的系统也是很复杂的系统。调度算法一直是整个分布式系统领域很困难的一个问题,如何做到隔离性和公平调度也是未来云数据库非常有挑战的一个事情。低成本 低成本应该是云时代基础设施最明显的特点。首先,云数据库的高可用和容错能力,使得我们不再需要昂贵的硬件设备,只需要普通的 X86 服务器就可以提供服务。然后,受益于 Docker 的虚拟化技术,使得不同类型的应用容器可以跑在同一个物理机上,这样可以极大地提高资源的利用率。其次,多租户的支持,使得不同的用户可以共用一套底层的数据库存储系统,在数据库层面再一次提高了资源的利用效率。再次,云数据库的自动化运维工具,降低了整个核心数据库的运维成本。最后,云数据库资源是按需分配的,用户完全可以根据自身的业务特点,选购合适的服务资源。高吞吐 云数据库虽然可以做到弹性扩容,但是本身是分布式存储的,虽然可以通过 Batch Write、Pipeline 和 Router Cache 等方式加快访问 SQL 请求的数据,但是相对传统单机的数据库来说,在数据访问链路上至少也要多走一次网络,所以大部分并发量不大的小数据量请求,都会比单机延迟要高一些。也就是说,当没有足够高的并发 SQL 访问的话,其实不能完全体现云数据库的性能优势,所以这也是我们在选用云数据库的时候需要认识到的问题,云数据库更多的是追求高吞吐,而不是低延迟。当并发大到一定规模,云数据库高吞吐特性就显现出来了,即使在很高的并发下,依然可以维持相当稳定的延迟,而不会像单机数据库那样,延迟线性增长。当然,延迟的问题,在合理的架构设计方案下,可以通过缓存的方式得到极大的缓解。数据安全 云数据库的物理服务器分布在多个机房,这就为跨数据库中心的数据安全提供了最基础的硬件支持。谈到金融业务,大家耳熟能详的可能就是两地三中心,比如北京有两个机房,上海有一个。未来一切服务都跑在云上,金融类的业务当然也不例外。相比其他业务,金融类业务对数据安全要求就要高得多。当然,每个公司内部都有核心的业务,所以如果上云的话,也会有同样的强烈需要。这样,对云数据库来说,数据的一致性、分布式事务、跨数据中心的数据安全等更高端的需求有可能会日益强烈。常见的数据备份也有可能会被其他新的模式所取代或者弱化,比如基于 Paxos/Raft 的多副本方案,本身就保证了会有多份备份。自动负载平衡 对于云数据库来说,负载平衡是一个很重要的问题,它直接决定了整个云数据库系统性能的好坏,如果一个数据库节点的数据访问过热的话,就需要考虑把数据迁移到其他的数据库节点来分担负载,不然就很容易出现性能瓶颈。整个负载平衡是一个动态的过程,调度算法需要保证资源配比的最大平衡,还有保证数据迁移的过程对系统整体的负载影响最小。这在未来也是云数据库需要解决的一个核心问题。小结 从目前已有的 SQL 数据库实现方案来看,NewSQL 应该是最贴近于云数据库理念的实现。NewSQL 本身具有 SQL、ACID 和 Scale 的能力,天然就具备了云数据库的一些特点。但是,从 NewSQL 到云数据库,依然有很多需要挑战的难题,比如多租户、性能等。上面提到的一些云数据库的特点,也是 PingCAP 目前在着力实现的部分,TiDB 作为国内第一个 NewSQL 的开源项目,在与社区的共同努力下,我们在上月底刚刚发布了 Beta 版本,欢迎各位上 GitHub 了解我们。随着整个社区技术水平的发展和云时代新的业务需求的驱动,除了 PingCAP 的 TiDB,相信会有更多的团队在这方面进行探索, 期待早日看到云数据库成熟的那一天。Q&A 问:由于客户数据环境复杂多样,在迁移到云端的时候怎么怎么做规划,以便后期统一运维管理?或者说,怎么把用户 SQL Server 或者 MongoDB 逐渐迁移到 TiDB 之类的分布式数据库? 崔秋:因为每个业务场景都不太相同,所以在选用云端服务的时候,首先要了解自身业务和云服务具体的优缺点。 如果你的业务本身比较简单,比如你之前用的 MongoDB,现在很多云服务厂商都会提供云端的 MongoDB 服务。这个时候你就要根据业务特点来做判断,如果 MongoDB 本身容量不大,远期的业务数据不会增长过快的话,这个时候其实你可以直接使用 MongoDB 的服务的。但是如果你本身的数据量比较大,或者数据增长比较快的话,就可能要考虑数据的扩容问题,MongoDB 在这方面做的不是太好。 你可以考虑 SQL 数据库的集群方案。比如 TiDB,它本身是支持弹性扩容,高并发高吞吐和跨数据库中心数据安全的,另外有一点明显的好处是 TiDB 兼容 MySQL 协议,所以如果你的应用程序是使用 MySQL,就基本上可以无缝地迁移到 TiDB,这方面是非常方便的。后续我们会提供常用的数据库迁移工具,帮用户把数据从 MongoDB/SQL Server 等平滑迁移到 TiDB 上面。 还是那个原则,不要为了上云而上云,一定要了解清楚自己的业务特点,云数据库会帮助你提供很多特性,如果真的很适用你的业务的话,就可以考虑。问:但从产品的角度来看,云厂商提供的 RDS 产品是 Copy 客户数据库的思路,或者说是为了支持不同的数据库而支持。请问这种局面以后会有什么改变吗? 崔秋:现在确实蛮多云数据库服务其实就是在传统的 RDS 上面包了一层自动化的监控,运维和部署工具,就卖给用户提供服务了,但是实际上本身解决的仅仅是自动化管控的问题,云服务提供的数据库特性还是单机的 RDS,或者 RDS Sharing 的特性。如果本身底层的数据库满足不了你的需求的话,云服务也是满足不了的。 如果你需要不停服务的弹性扩容,单机的 RDS 服务肯定是搞不定的,RDS Sharing 也很难帮助你做到,这就对底层的数据库有了更高的要求,当然这方面是 TiDB 的强项了。 现在很多云上的 RDS 产品还远远没有达到理想中的云数据库的要求,不过随着社区的发展和业务需求的推动,我个人觉得,这方面最近几年会有更多的变化。如果对于这方面感兴趣的话,可以关注下 TiDB。问:从 Oracle 分流数据到 TiDB、Oracle 增量修改、Update 的记录,如何同步到 TiDB?有没有工具推荐,比如类似 Ogg? 崔秋:目前 TiDB 还没有相应的工具。如果真的需要在线从 Oracle 这边分流的话,可以考虑使用 Oracle 的触发器,将数据的变化记录下来,然后转化为 SQL,同步到 TiDB,当然这需要一定开发的工作量。"}, {"url": "https://pingcap.com/blog-cn/tidb-optimization-for-subquery/", "title": "TiDB 中的子查询优化技术", "content": " 子查询简介 子查询是嵌套在另一个查询中的 SQL 表达式,比较常见的是嵌套在 FROM 子句中,如 SELECT ID FROM (SELECT * FROM SRC) AS T。对于出现在 FROM 中的子表达式,一般的 SQL 优化器都会处理的很好。但是当子查询出现在 WHERE 子句或 SELECT 列表中时,优化的难度就会大大增加,因为这时子查询可以出现在表达式中的任何位置,如 CASE...WHEN... 子句等。对于不在 FROM 子句出现的子查询,分为“关联子查询”(Correlated Subquery) 和“非关联子查询”。关联子查询是指子查询中存在外部引用的列,例如:SELECT * FROM SRC WHERE EXISTS(SELECT * FROM TMP WHERE TMP.id = SRC.id) 对于非关联子查询,我们可以在 plan 阶段进行预处理,将其改写成一个常量。因此,本文只考虑关联子查询的优化。一般来说,子查询语句分为三种: 标量子查询(Scalar Subquery),如(SELECT…) + (SELECT…) 集合比较(Quantified Comparision),如T.a = ANY(SELECT…) 存在性测试(Existential Test),如NOT EXISTS(SELECT…),T.a IN (SELECT…) 对于简单的存在性测试类的子查询,一般的做法是将其改写成 SEMI-JOIN。但是很少有文献给出通用性的算法,指出什么样的查询可以“去关联化”。对于不能去关联化的子查询,数据库的做法通常是使用类似 Nested Loop 的方式去执行,称为 correlated execution。TiDB 沿袭了 SQL Server 对子查询的处理思想,引入 Apply 算子将子查询用代数形式表示,称为归一化,再根据 Cost 信息,进行去关联化。Apply 算子 子查询难以优化的原因是,人们通常不能把一个子查询执行表示成一个类似 Projection、Join 这样的逻辑算子。这使得找到一个通用子查询转换的算法是很难的。所以我们第一件要做的事就是,引入一个可以表示子查询的逻辑算子:Apply。Apply 算子的语义是:公式中的 E 代表一个“参数化”的子查询。在每一次执行中,Apply 算子会向关系 R 取一条记录 r,作为参数传入 E 中,然后让 r 和 E® 做 ⊗ 操作。⊗ 会根据子查询类型的不同而不同,通常是半连接 ⋉。对于 SQL 语句:SELECT * FROM SRC WHERE EXISTS(SELECT * FROM TMP WHERE TMP.id = SRC.id) 它的 Apply 算子表示是:对于出现在 SELECT 列表中、GROUP BY 列表中的子查询,道理也是类似的。所以 Apply 是可以表示出现在任意位置的子查询的。去关联化 引入了 Apply,我们就可以将子查询去关联化了。去关联化的规则如下:根据上述规则,你可以将所有的确定性 SQL 子查询去关联化。例如 SQL 语句:SELECT C_CUSTKEY FROM CUSTOMER WHERE 1000000 < (SELECT SUM(O_TOTALPRICE) FROM ORDER WHERE O_CUSTKEY = C_CUSTKEY) 其中两个 CUSTKEY 均为主键。转换成 Apply 之后的表达式为:因为主键的存在,利用规则(9),可以转化为:此时根据规则(2),我们可以彻底消除 Apply,转化为只有连接的 SQL 表达式:再根据外连接化简的原则,可以进一步化简为:利用上述九条规则,理论上已经解决去关联化的问题了。是不是对于所有的情况,去关联化都是最好的呢?答案是否定的。如果 SQL 的结果很小,同时子查询可以利用索引,有时候使用 correlated execution 是最好的。是否去关联化还需要统计信息的帮助。而到了这一步,普通的优化器已经无能为力了。只有 Volcano 或 Cascade Style 的优化器,可以同时考虑逻辑等价规则和代价选择。因此,想要完美解决子查询的问题,要需要优秀的优化器框架的支撑。半连接 TiDB 在去关联化方面,目前只支持将关联子查询改写成半连接和左外半连接。例如,对于查询:SELECT * FROM SRC WHERE EXISTS(SELECT * FROM TMP WHERE TMP.id = SRC.id) TiDB 做出的 Plan 为:当子查询出现在 SELECT 子句当中时:SELECT CASE WHEN EXISTS(SELECT * FROM TMP WHERE TMP.id = SRC.id) THEN 1 ELSE 2 END FROM SRC Projection 算子需要知道 Exists 结果是 True 或者 False。这时需要左外半连接,当然外表匹配时,有一个辅助列 aux 输出 True,当不匹配时,输出 False。对于半连接的算法实现,其实和 Join 差别不大,可以选择 MergeSortJoin,HashJoin,IndexLoopUpJoin,NestedLoop 等等。确定使用 SemiJoin 之后,优化器会根据统计信息选择最合适的算法,这里不再赘述。"}, {"url": "https://pingcap.com/meetup/meetup-2016-08-01/", "title": "TiDB 中的子查询优化技术", "content": " TiDB 中的子查询优化技术 原创2016-08-01 韩飞 PingCAP PingCAPPingCAP ![]() 微信号pingcap2015功能介绍PingCAP 专注于新型"}, {"url": "https://pingcap.com/meetup/meetup-2016-07-30/", "title": "PingCAP 第 18 期 NewSQL Meetup", "content": " PingCAP 第 18 期 NewSQL Meetup 2016-07-30 常冰琳&张阳 PingCAP PingCAPPingCAP ![]() 微信号pingcap2015功能介绍PingCAP 专注于新型分布式数据库的研发,是知名开源数据库 TiDB (GitHub 总计10000+ stars ) 背后的团队,总部设在北京,是国内第一家开源的新型分布式关系型数据库公司、国内领先的大数据技术和解决方案提供商。NewSQL Meetup今天是 PingCAP 第 18 期 Meetup,主题是小米云平台工程师常冰琳分享的《Kudu 的设计思想和具体实现》以及张阳分享的《Kubernetes in PingCAP》。▌ ****Topic 1:Kudu 的设计思想和具体实现lecture:常冰琳 小米云平台工程师,长期专注于 Hadoop 生态的分布式计算框架,Kudu PMC&Commiter, Hadoop Nativetask 项目发起者(已合入 Hadoop)。目前在小米负责 SQL 类数据分析平台,利用 Impala 和 Kudu 搭建实时数据分析云服务。Content:本次分享将简单介绍 Kudu 的设计思想和具体实现,以及小米作为 Kudu 最早用户的一些实践经验。 设计目标 数据模型,分区和副本设计 Tablet 存储设计 其他底层细节 小米实践 ▌ ****Topic 2:Kubernetes in PingCAPContent:本次分享,主要与大家沟通了 Kubernetes 在 TiKV 及 TiDB 中的一些应用场景,包括部署、运维以及与 Jenkins CI 的集成等。同时,对大家集中提问的 stateful 的 TiKV 在 rolling update、recovery 等情况下的“状态”维护上的一些问题,进行了探讨,基于此问题,大家在分享结束后也积极交流了各自对于 Kubernetes 本身的一些见解。两个小时的分享时间很快就过去了,还没尽兴的小伙伴们便又开始了跟讲师和 PingCAP 团队单聊的节奏。于是,这些“自动配对,小组交流”的画面便出现在了 PingCAP 公司内的各个角落。接下来,我们也会从以往 Meetup 议题中筛选出现场关注度较高的技术点,邀请讲师以深度文章的形式分享出来。如果大家有任何相关技术问题,也欢迎通过微信留言与我们交流探讨。PingCAP Meetup"}, {"url": "https://pingcap.com/weekly/2016-07-29-tidb-weekly/", "title": "Weekly update (July 23 ~ July 29, 2016)", "content": " Weekly update (July 23 ~ July 29, 2016) Last week, we landed 27 PRs in the TiDB repositories and 34 PRs in the TiKV repositories.Notable changes to TiDB Support cost based query optimization. Set the new query optimizer as default to improve the speed of complex queries. Meanwhile, a start-up parameter is provided to switch to the old query optimizer. Use Varint to encode the Column Value with integer type and Column ID, which saves storage space significantly. Add a Documents repository. Supprt the Hex Function. Simplify the compling and deployment for better usability. Fix several bugs. New Contributor Huaiyu XuNotable changes to TiKV Support building TiKV by linking static RocksDB automatically. You can build TiKV in one machine and copy the binary to other machines to use directly as long as the machines have the same architecture and operation system. Supprt getting snapshot asynchronously for higher throughput and better performance, see benchmark. Use PipeBuf to receive data to reduce system call and memory allocation. Use Varint to encode un-comparable integers to save disk space. Use one SendCh to clean up duplicated code. Add user documents on how to build and use TiKV. Notable changes to Placement Driver Embed etcd to for easier deployment. Add a health check for Store. Add user documents on how to build and use PD. Clean up the command flags. Benchmark Use sysbench to benchmark getting snapshot asynchronously and synchronously in 3-node TiKV.# Prepare data sysbench --test=./lua-tests/db/oltp.lua --mysql-host=${host} --mysql-port=${port} --mysql-user=${user} --mysql-password=${password} --oltp-tables-count=1 --oltp-table-size=5120000 --rand-init=on prepare # Run benchmark sysbench --test=./lua-tests/db/select.lua --mysql-host=${host} --mysql-port=${port} --mysql-user=${user} --mysql-password=${password} --oltp-tables-count=1 --oltp-table-size=5120000 --num-threads=${threads} --report-interval=60 --max-requests=5120000 --percentile=99 run |Threads|Async qps|Async avg/.99 latency|Sync qps|Sync avg/.99 latency| |—|—|—|—|—|—| |32|13347|2.4⁄4.61|12345|2.59⁄4.78| |64|14210|4.50⁄7.78|11868|5.39⁄8.50| 128|14075|9.09/15.22|12324|10.38⁄16.68|As we can see, the qps is increased by about 15%, and the latency is decreased by about 10%."}, {"url": "https://pingcap.com/meetup/meetup-2016-07-23/", "title": "PingCAP 第 17 期 NewSQL Meetup", "content": " PingCAP 第 17 期 NewSQL Meetup 2016-07-23 崔秋 PingCAP PingCAPPingCAP ![]() 微信号pingcap2015功能介绍PingCAP 专注于新型分布式数据库的研发,是知名开源数据库 TiDB (GitHub 总计10000+ stars ) 背后的团队,总部设在北京,是国内第一家开源的新型分布式关系型数据库公司、国内领先的大数据技术和解决方案提供商。NewSQL Meetup今天是 PingCAP 第 17 期 Meetup,主题是崔秋分享的《How does TiKV auto-balance work?》。▌ ****Topic:How does TiKV auto-balance work?TiDB最近发布了Beta版本,相比传统的关系型数据库,TiDB具有在线弹性伸缩,高可用和强一致性,一致性的分布式事务和MySQL协议兼容性等特性,特别适用于大规模高并发的海量数据场景。本次交流主要介绍了 TiKV 的 Balance Scheduler 框架和算法实现演进,对于大家主要关注的 TiKV 集群的在线弹性扩容实现细节和 TiKV Balance 中在线服务高可用的问题,进行了深度的探讨。在 TiKV 里面,数据是按照 Range 进行存放的,称为一个 Region。PD(Placement Driver) 负责整个 TiKV 集群的管理和调度。在 TiKV 里面,数据移动的基本单元是 Region,所以 PD 的 auto balance 也是针对 Region 进行处理。对于一个 Region 来说,它会不会被 Balance,有两种方式:1)HeartbeartRegion 会定期地上报当前的状态信息给 PD,如果 PD 发现该 Region 副本数不足或者超过阀值,则会通知该 Region 进行 Membership Change 处理。2)Balance LoopPD 会每隔一段时间检测整个系统是否需要调度。如果 PD 发现某个 Store 能用的空间不多,或者某个 Store Leader Region 数量太多,load 比较高,就会在该 Store 里面选择一个 Region,将其在该 Store 的副本迁移到另一个 Store 上面。PingCAP Meetup"}, {"url": "https://pingcap.com/weekly/2016-07-23-tidb-weekly/", "title": "Weekly update (July 17 ~ July 22, 2016)", "content": " Weekly update (July 17 ~ July 22, 2016) Last week, we landed 22 PRs in the TiDB repositories and 15 PRs in the TiKV repositories.Notable changes to TiDB Refactor the query optimizer to imporve the query efficiency for Join and SubQuery Add distributed SQL support for aggregate functions Improve the stability of the TiDB service Refactor the Decimal codes to improve the compatibility with MySQL Optimize the TiDB compatibility and performance for Zabbix Enhance the performance and the Sysbench result is improved significantly Notable changes to TiKV Add asynchronous scheduler support for higher throughput and better performance, see Benchmark. Use PipeBuf to speed up socket read/write. Add pushing down max/min support for the coprocessor. Re-use RocksDB write ahead log (WAL) to guarantee consistency when writing data in different column families. Support using make install on the CentOS platform to install TiKV. Notable changes to Placement Driver Refactor the balance framework to make a cluster more balanced and stable. Support web UI in Docker. Benchmark Use sysbench to benchmark asynchronous scheduler and previous 8 threadpools in 3-node TiKV.# Prepare data sysbench --test=./lua-tests/db/oltp.lua --mysql-host=${host} --mysql-port=${port} --mysql-user=${user} --mysql-password=${password} --oltp-tables-count=$1 --oltp-table-size=1000 --rand-init=on prepare # Run benchmark sysbench --test=./lua-tests/db/insert.lua --mysql-host=${host} --mysql-port=${port} --mysql-user=${user} --mysql-password=${password} --oltp-tables-count=1 --oltp-table-size=1000 --num-threads=${threads} --report-interval=60 --max-requests=1280000 --percentile=99 run |Threads|Async scheduler qps|Async scheduler avg/.99 latency|8 threadpools qps|Thread pool avg/.99 latency| |—|—|—|—|—|—| |32|2049|15.6⁄29.1|1652|19.4⁄36.3| |64|2042|31.3⁄85.5|1693|37.8⁄83| |128|2125|60.2⁄147|1649|77⁄175|As we can see, the qps is increased by about 25%, and the latency is decreased by about 15%."}, {"url": "https://pingcap.com/meetup/meetup-2016-07-16/", "title": "PingCAP 第 16 期 NewSQL Meetup", "content": " PingCAP 第 16 期 NewSQL Meetup 2016-07-16 田琪&孟圣智 PingCAP PingCAPPingCAP ![]() 微信号pingcap2015功能介绍PingCAP 专注于新型分布式数据库的研发,是知名开源数据库 TiDB (GitHub 总计10000+ stars ) 背后的团队,总部设在北京,是国内第一家开源的新型分布式关系型数据库公司、国内领先的大数据技术和解决方案提供商。NewSQL Meetup今天是 PingCAP 第 16 期 Meetup,主题是来自京东的田琪分享的《Cool Extensions of Raft for NewSQL》,以及来自百度的孟圣智分享的《基于 Ceph 构建文件共享服务的实践》 。▌ ****Topic1:Cool Extensions of Raft for NewSQLlecturer:田琪,京东数据库系统部负责人,开源 docker 镜像存储系统 speedy 作者,TiDB committer, etcd contributorTopic summary:主要分享了 Raft 协议在 etcd 中的实现,与 etcd 在 Raft 协议方面近期更新地比较重要的特性,以及引进这些特性的缘由。 the functionality of leader transfer the future improvement of leader transfer the functionality of quorum checking implement leader lease based on quorum checking some issues about leader lease how to implement efficient read-only query some other Raft internal details ▌Topic 2:基于 Ceph 构建文件共享服务的实践lecturer:孟圣智,百度资深研发工程师,在存储领域有多年经验,Ceph contributor,Ceph-Dokan 项目作者,曾在国内最早落地 OpenStack Manila 项目,现在在百度负责 Memcache、Redis 类存储的研发和维护。Topic summary: Ceph 的基本架构 CephFS 的实现方式 CephFS 的多客户端方案 OpenStack 中使用 Ceph 的经验 基于 CephFS 实现文件共享服务的实践 PingCAP Meetup"}, {"url": "https://pingcap.com/meetup/meetup-2016-07-09/", "title": "PingCAP 第15期 NewSQL Meetup", "content": " PingCAP 第15期 NewSQL Meetup 2016-07-09 申砾&周昱行 PingCAP PingCAPPingCAP ![]() 微信号pingcap2015功能介绍PingCAP 专注于新型分布式数据库的研发,是知名开源数据库 TiDB (GitHub 总计10000+ stars ) 背后的团队,总部设在北京,是国内第一家开源的新型分布式关系型数据库公司、国内领先的大数据技术和解决方案提供商。NewSQL Meetup今天是 PingCAP 第15期 Meetup ,主题是申砾分享的《TiDB 存储模型变更》以及周昱行分享的《TiDB 优化器统计信息的采集》。▌Part 1:《TiDB 存储模型变更》TiDB 在 Key-Value 存储模型之上,将一行数据拆分成多个 Key-Value pair。这样做有利于列较多并且 update 较为频繁的业务场景,同时对 Online Schema 变更较为友好。但是这种存储模型对于需要读取/写入大量 row 的业务场景并不适用。为此我们修改了 TiDB 的存储模型,将一行内需要频繁修改和很少修改的数据存储在不同的 column family 中,以更好地适应不同热度的数据,以及生存期差别比较大的数据。同时,非常有效地适配了读写放大以及空间放大的问题。▌Part 2:《TiDB 优化器统计信息的采集》统计信息是实现基于代价的优化(CBO)的必要条件,本期为大家介绍 TiDB 收集统计信息使用的采样算法和直方图生成算法。PingCAP Meetup"}, {"url": "https://pingcap.com/meetup/meetup-2016-07-02/", "title": "PingCAP 第14期 NewSQL Meetup", "content": " PingCAP 第14期 NewSQL Meetup 2016-07-02 马涛&刘奇 PingCAP PingCAPPingCAP ![]() 微信号pingcap2015功能介绍PingCAP 专注于新型分布式数据库的研发,是知名开源数据库 TiDB (GitHub 总计10000+ stars ) 背后的团队,总部设在北京,是国内第一家开源的新型分布式关系型数据库公司、国内领先的大数据技术和解决方案提供商。NewSQL Meetup今天是 PingCAP 第14期 Meetup ,主题是酷克数据联合创始人马涛分享的《HashData 数据仓库的动态缩容扩容实现》以及 PingCAP 联合创始人兼 CEO 刘奇针对近日发布的 TiDB Beta 版进行的现场 Demo 演示。▌Part 1:《 HashData 数据仓库的动态缩容扩容实现》讲师:马涛,酷克数据联合创始人,数据库领域从业近10年,最初 Pivotal HAWQ 项目成员,06年至11年就职人大金仓做内核开发。目前主要负责 OLAP 系统内核和外围云化工作。通过对比 Greenplum,Dynamo 和 HashData 的当前实现,为大家简单介绍数据处理系统动态缩容扩容的实现。阐述数据系统缩容和扩容的需求集合和设计方案,深入介绍 HashData 选择的设计、目前实现和后续改进。▌Part 2:《 TiDB Beta 版现场 Demo 演示》讲师:刘奇,PingCAP 联合创始人兼 CEO。针对6月30日发布的 TiDB Beta 版,刘奇在现场进行演示,与大家共同见证了 TiDB 界面的首次亮相。直接通过标准的 MySQL 客户端连接,后端三台普通 x86 服务器集群,演示了常用的 SQL 插入和查询,并演示了在大压力数据写入的场景下,TiDB 自动扩容的全过程,期间无需人为干预,TiDB 自动完成数据迁移和扩容及流量的负载均衡,业务层完全透明。小伙伴们都惊呆了。TiDB Beta 版已如约亮相,说好的 “三五好友,吃吃喝喝”,说来就来 :)PingCAP Meetup"}, {"url": "https://pingcap.com/meetup/meetup-2016-06-25/", "title": "PingCAP 第13期 NewSQL Meetup", "content": " PingCAP 第13期 NewSQL Meetup 2016-06-25 闫宇&崔秋 PingCAP PingCAPPingCAP ![]() 微信号pingcap2015功能介绍PingCAP 专注于新型分布式数据库的研发,是知名开源数据库 TiDB (GitHub 总计10000+ stars ) 背后的团队,总部设在北京,是国内第一家开源的新型分布式关系型数据库公司、国内领先的大数据技术和解决方案提供商。NewSQL Meetup今天是 PingCAP 第13期 Meetup ,主题是百度资深研发工程师、百度 BAC 存储负责人闫宇分享的《 百度 redis3 生产环境实践》以及 PingCAP 联合创始人崔秋分享的《TiKV Auto Balance 》。▌Topic 1:《百度 redis3 生产环境实践》讲师:闫宇,百度资深研发工程师,百度 BAC 存储负责人**(百度 BAC 的 redis3 服务目前机器规模达到1400台左右,总数据量接近100T,日 pv 超过1500亿,用户涵盖了百度贴吧、百度糯米、手机百度等百度内部几百个业务线。)内容方向:1)介绍百度BAC的 redis3 服务的整体架构;2)交流在 redis3 实践中的一些经验。以下为本次分享的干货PPT:▌Topic 2:《TiKV Auto Balance》讲师:崔秋,PingCAP 联合创始人内容方向:1)PD - God View of TiKV; 2)TiKV 如何成为真正意义上的分布式存储引擎。以下为本次分享的干货PPT:最后,附赠一张今日爆满全场听讲图PingCAP Meetup"}, {"url": "https://pingcap.com/meetup/meetup-2016-06-18/", "title": "PingCAP 第12期 NewSQL Meetup", "content": " PingCAP 第12期 NewSQL Meetup 2016-06-18 张金鹏 PingCAP PingCAPPingCAP ![]() 微信号pingcap2015功能介绍PingCAP 专注于新型分布式数据库的研发,是知名开源数据库 TiDB (GitHub 总计10000+ stars ) 背后的团队,总部设在北京,是国内第一家开源的新型分布式关系型数据库公司、国内领先的大数据技术和解决方案提供商。NewSQL Meetup今天是 PingCAP 第12期 Meetup ,主题是张金鹏分享的《 rocksdb 日志分析和性能调优经验 》。▌张金鹏《 rocksdb 日志分析和性能调优经验 》首先和大家一起分享如何分析 rocksdb 的 LOG,包括观察 compaction 相关的统计信息。例如每个 level 导致的 compaction 个数,每个 compaction job 的平均持续时长,compaction 导致的 read 总量和 write 量,以及写放大等;也可以观察整个系统是否有 stall 情况,持续多长时间,时间占比是多少等;另外,还有跟踪某个具体的 compaction job 的 input files 组成,output files,以及 compacting 过程中 drop 掉的 key 个数等信息。然后根据 rocksdb 的 LOG 以及观察到的系统负载情况,来对不同参数组进行测试。最后对比不同参数组的一些效果,包括同样的数据量导致的 compaction 放大比例;整个系统的 stall 情况;以及是否存在长时间的 compaction 导致的长时间高 CPU 及高 IO,从而对 TiKV 服务本身造成负面影响等情况。PingCAP Meetup"}, {"url": "https://pingcap.com/blog-cn/tidb-api-union-scan/", "title": "TiDB 下推 API 实现细节 - Union Scan", "content": " TiDB 集群的架构分为上层的 SQL 层和底层的 KV 层,SQL 层通过调用 KV 层的 API 读写数据,由于 SQL 层的节点和 KV 层节点通常不在一台机器上,所以,每次调用 KV 的 API 都是一次 RPC, 而往往一个普通的 Select 语句的执行,需要调用几十到几十万次 KV 的接口,这样的结果就是性能非常差,绝大部分时间都消耗在 RPC 上。为了解决这个问题,TiDB 实现了下推 API,把一部分简单的 SQL 层的执行逻辑下推到 KV 层执行,让 KV 层可以理解 Table 和 Column,可以批量读取多行结果,可以用 Where 里的 Expression 对结果进行过滤, 可以计算聚合函数,大幅减少了 RPC 次数和数据的传输量。TiDB 的下推 API 通过把 SQL 层的计算下推到 KV 层,大幅减少 RPC 次数和数据传输量,使性能得到数量级的提升。但是当我们一开始启用下推 API 的时候,发现了一个问题,就是当事务写入了数据,但是还未提交的时候,又执行了 Select 操作。这个时候,刚刚写入的未提交的脏数据读不到,得到的结果是错误的,比如我们在一个空表 t 执行:begin; insert t values (1); select * from t; 这时我们期待的结果是一条记录 “1”,但是启用下推 API 后得到的结果是空。导致这个问题的原因是我们的事务在提交之前,写入的数据是 buffer 在 SQL 层,并没有写入 KV, 而下推 API 直接从 KV 读取数据,得到的结果直接返回,所以得到了空的结果。但是既然 KV 层读取不到未提交的脏数据,那在启用下推 API 之前,是如何得到正确结果的呢?这就涉及到 SQL 层的 Buffer 实现。当初为了解决未提交事务的 Buffer 可见性问题,SQL 层实现了一个 UnionStore 的结构,UnionStore 对 Buffer 和 KV 层接口做了一个封装,事务对 KV 的读写都经过 UnionStore,当 UnionStore 遇到读请求时,会先在 Buffer 里找,Buffer 找不到时,才会调用 KV 层的接口,读取 KV 层的数据。所以相当于把 Buffer 和 KV 的数据做了一个 Merge,返回 Merge 后的正确结果。Buffer 的数据是用 goleveldb 的 MemDB 存储的,所以是有序的,当需要遍历数据的时候,UnionStore 会同时创建 Buffer 的 Iterator 和 KV 的 Iterator,遍历的算法类似 LevelDB,把两个 Iterator merge 成一个。UnionStore 的实现是基于 Key Value 的,但是下推 API 返回的结果是基于 Row 的,也就是说,我们虽然有脏数据 Buffer 和下推 API 返回的结果集, 但是我们没有办法把这两部分数据合并在一起, 所以我们为了绕过这个问题,加了一个判断条件,当事务写入了 Buffer,包含了脏数据以后,就不走下推 API,而是使用基础的 KV API。在我们刚刚开始启用下推 API 的时候,因为性能基准比较低,而且带脏数据的下推请求只占很小的一部分,所以我选择暂时绕过这个问题。但是当全面启用下推 API 以后,整体性能已经大幅提升,这时带脏数据的请求无法走下推 API 这个 worst case 问题就渐渐凸显出来。比如说,我们如果需要在一个事务里 UPDATE 多个行,就一定会遇到下推 API 无法使用,降级到基础 KV API 的问题。假设我们创建一个表,插入了两行数据:create table t (c int); insert t values (1), (4); 这时我们执行这样一个事务:begin; update t set c = 2 where c = 1; update t set c = 3 where c = 4; UPDATE 语句执行的过程分两步,第一步是先读取到需要更新的数据,第二步把更新的数据写入 Buffer。也就是 UPDATE 包含了一次 SELECT 请求。当第一个 UPDATE 语句执行的时候,因为没有脏数据,所以读请求会走下推 API,但是第一个 UPDATE 语句执行完后,事务就有了脏数据,再执行第二个 UPDATE 的时候,无法使用下推 API, 会导致性能大幅下降。解决这个问题的方案,最容易想到的是在 KV 层实现 UnionStore 相同的算法,当发送下推 API 请求时,把 Buffer 一并传下去。但是这个方案的缺点也很明显,就是计算和存储不在同一节点,不符合就近计算原则。脏数据是在 SQL 层生成并存储的,本来应该在 SQL 进行 Merge,但是却要传输到 KV 层去 Merge,如果 Buffer 的数据很多,传输 Buffer 带来的开销就会很大。最终我们设计实现了一个更好的方案 Union Scan,在不需要把 Buffer 传输到 KV 层,不修改 KV 层的情况下,解决了脏数据的可见性问题。下面是这个算法的简介 脏数据缓存在 SQL 层,要让它可见,一定是需要 Merge 的,当我们使用下推 API, 只拿到了一堆 Row,这时怎么 Merge 呢?如果我们不做 Merge,直接返回给用户结果集,错误表现的就是少了某些 row,多了某些 row,或某些 row 的数据是旧的。如果我们把 INSERT, UPDATE, DELETE 的修改操作,以 row 为单位记录下来,这样和下推 API 返回的结果就是同样的形式了,就可以很方便的做 Merge 的计算了。所以 Union Scan 的算法就是以 Row 为单位,把事务的修改操作保存起来,最终和下推 API 返回的结果集进行 Merge,返回给客户端。我们为每个事务在对某个 table 执行写操作时,创建一个 dirtyTable 保存这个事务的修改,dirtyTable 包含两个 map,一个是 addedRows,用来保存新写入的 row,另一个是 removedRows,用来保存删除的 row,对于不同的操作,我们需要对这两个 map 做不同的操作。对于 INSERT,我们需要把 row 添加到 addedRows 里。对于 DELETE,我们需要把 row 从 addedRows 里删掉,然后把 row 添加到 removedRows 里。对于 UPDATE,相当于先执行 DELETE, 再执行 INSERT。当我们从下推 API 得到了结果集之后,我们下面把它叫做快照结果集,Merge 的算法如下:对于每一条快照结果集里的 Row,在 removedRows 里查找,如果有,那么代表这一条结果已经被删掉,那么把它从结果集里删掉,得到过滤后的结果集。把 addedRows 里的所有 Row,放到一个 slice 里,并对这个 slice 用快照结果集相同的顺序排序,生成脏数据结果集。返回结果的时候,将过滤后的快照结果集与脏数据结果集进行 Merge。实现了 Union Scan 以后,所有的读请求都可以使用下推 API 加速,大幅提升了 worst case 的性能。"}, {"url": "https://pingcap.com/meetup/meetup-2016-06-04/", "title": "PingCAP 第11期 NewSQL Meetup", "content": " PingCAP 第11期 NewSQL Meetup 2016-06-04 黄梦龙&张金鹏 PingCAP PingCAPPingCAP ![]() 微信号pingcap2015功能介绍PingCAP 专注于新型分布式数据库的研发,是知名开源数据库 TiDB (GitHub 总计10000+ stars ) 背后的团队,总部设在北京,是国内第一家开源的新型分布式关系型数据库公司、国内领先的大数据技术和解决方案提供商。NewSQL Meetup今天是 PingCAP 第11期 Meetup ,主题是黄梦龙分享的《 TiKV 的结构化存储模型优化》和张金鹏分享的《深入解析 LevelDB 》。▌黄梦龙《 TiKV 的结构化存储模型优化》目前 TiKV 的存储模型是简单的纯 Key-Value,在存储 SQL 结构化数据的过程中会产生比较严重的读写放大问题。我们计划为 TiKV 添加类似于 Hbase 的 ColumnFamily 机制,以使得 TiKV 与 TiDB 成为更加完美的搭档。大家对其中的实现细节,以及各种方案的优缺点进行了探讨。▌张金鹏《深入解析 LevelDB 》首先介绍了 LevelDB 的整体架构,以及 LSM Tree 这一数据库中非常经典的结构。之后对 LevelDB 的写和读的流程进行分析,同时介绍 LevelDB 的 snapshot 功能的实现原理,以及 iterator 内部实现,和 iterator 存在的潜在问题。最后介绍 LevelDB 的 compaction 过程,以及存在的问题。PingCAP Meetup"}, {"url": "https://pingcap.com/meetup/meetup-2016-05-28/", "title": "PingCAP 第10期 NewSQL Meetup", "content": " PingCAP 第10期 NewSQL Meetup 2016-05-28 刘奇&周昱行 PingCAP PingCAPPingCAP ![]() 微信号pingcap2015功能介绍PingCAP 专注于新型分布式数据库的研发,是知名开源数据库 TiDB (GitHub 总计10000+ stars ) 背后的团队,总部设在北京,是国内第一家开源的新型分布式关系型数据库公司、国内领先的大数据技术和解决方案提供商。NewSQL Meetup今天是 PingCAP 第10期 Meetup ,跟京东小伙伴就Raft group 中出现网络隔离时的 stale read 的问题做了充分讨论交流。之后进行的分享主题是《 TiKV 的网络模拟测试》和《 TiDB 的条件下推优化》。▌随机讨论Raft group 中出现网络隔离时,会有stale read 的问题。目前我们考虑采用 region leader 的方案,保证在出现网络隔离的情况下,也能保证读的正确性。大家对其中的实现细节,以及各种方案的优缺点进行了讨论。▌刘奇《 TiKV 的网络模拟测试》TiKV 如何做分布式系统测试。目前已经构建了一套测试框架,提供设置网络延迟、网络隔离、节点掉线等功能,用于构建测试用例。▌周昱行《 TiDB 的条件下推优化》使用基于 Row 的 Merge 算法,解决存在脏数据时,使用 TiDB 下推 API 优化的问题。TiDB 的下推 API 相比基础的 API 对读性能有着几个数量级的提升,任何无法使用下推 API 的操作的请求,性能都慢到完全无法接受的程度。但是之前的实现并不能保证所有读请求都可以走下推 API, 当事务有写操作以后,无法使用下推 API。无法使用的原因是,事务提交之前,事务内写入的数据是对事务自身是可见的,下推 API 只能读到已提交的数据,返回的结果是错误的。一个很常见的场景是在一个事务内 UPDATE 多个 Row,会退化到使用基础 KV API。本周 TiDB 的一个更新,通过设计实现了一种基于 Row 的 Merge 算法,解决了这个问题。小花絮: 赠送 PingCAP 家褶皱版美背 T 恤买家秀一只。大家周末愉快:PPingCAP Meetup"}, {"url": "https://pingcap.com/meetup/meetup-2016-05-21/", "title": "PingCAP 第9期 NewSQL Meetup", "content": " PingCAP 第9期 NewSQL Meetup 2016-05-21 韩飞&刘奇 PingCAP PingCAPPingCAP ![]() 微信号pingcap2015功能介绍PingCAP 专注于新型分布式数据库的研发,是知名开源数据库 TiDB (GitHub 总计10000+ stars ) 背后的团队,总部设在北京,是国内第一家开源的新型分布式关系型数据库公司、国内领先的大数据技术和解决方案提供商。NewSQL Meetup今天是 PingCAP 第9期 NewSQL Meetup ,分享主题是韩飞的《 SQL 子查询优化》和刘奇的《 TiKV MVCC 和 GC 实现》。▌韩飞 《 SQL 子查询优化》分享 SQL subqueries 的变换和优化问题。关联子查询的优化是 SQL 优化中很重要的一部分,一般的执行方式方式是 correlated execution,但是可以通过引入 Apply 算子形式化证明所有的子查询都可以改写成 Join 的不同形式。在分布式场景下,Join 可以比 correlated execution 有更多的优化空间。▌刘奇《 TiKV MVCC 和 GC 实现》详细分析了 TiKV 的 MVCC 机制, 事务模型,并进一步介绍了 percolator 事务模型的特点,以及对 GC 的影响。另外讲解了 TiKV 对 percolator 事务模型的改进, 以及 TiKV 的 GC 算法,和如何支持长时间的数据库备份和分析操作。PingCAP Meetup"}, {"url": "https://pingcap.com/about/", "title": "About", "content": ""}, {"url": "https://pingcap.com/docs/v1.0/", "title": "About TiDB", "content": " About TiDB TiDB introduction TiDB (The pronunciation is: /‘taɪdiːbi:/ tai-D-B, etymology: titanium) is a Hybrid Transactional/Analytical Processing (HTAP) database. Inspired by the design of Google F1 and Google Spanner, TiDB features infinite horizontal scalability, strong consistency, and high availability. The goal of TiDB is to serve as a one-stop solution for online transactions and analyses. Horizontal and linear scalability Compatible with MySQL protocol Automatic failover and high availability Consistent distributed transactions Online DDL Multiple storage engine support Highly concurrent and real-time writing and query of large volume of data (HTAP) TiDB is designed to support both OLTP (Online Transactional Processing) and OLAP (Online Analytical Processing) scenarios. For complex OLAP scenarios, use TiSpark.Read the following three articles to understand TiDB techniques: Data Storage Computing Scheduling Roadmap Read the Roadmap.Connect with us Twitter: @PingCAP Reddit: https://www.reddit.com/r/TiDB/ Stack Overflow: https://stackoverflow.com/questions/tagged/tidb Mailing list: Google Group TiDB architecture To better understand TiDB’s features, you need to understand the TiDB architecture.The TiDB cluster has three components: the TiDB server, the PD server, and the TiKV server.TiDB server The TiDB server is in charge of the following operations: Receiving the SQL requests Processing the SQL related logics Locating the TiKV address for storing and computing data through Placement Driver (PD) Exchanging data with TiKV Returning the result The TiDB server is stateless. It does not store data and it is for computing only. TiDB is horizontally scalable and provides the unified interface to the outside through the load balancing components such as Linux Virtual Server (LVS), HAProxy, or F5.Placement Driver server The Placement Driver (PD) server is the managing component of the entire cluster and is in charge of the following three operations: Storing the metadata of the cluster such as the region location of a specific key. Scheduling and load balancing regions in the TiKV cluster, including but not limited to data migration and Raft group leader transfer. Allocating the transaction ID that is globally unique and monotonic increasing. As a cluster, PD needs to be deployed to an odd number of nodes. Usually it is recommended to deploy to 3 online nodes at least.TiKV server The TiKV server is responsible for storing data. From an external view, TiKV is a distributed transactional Key-Value storage engine. Region is the basic unit to store data. Each Region stores the data for a particular Key Range which is a left-closed and right-open interval from StartKey to EndKey. There are multiple Regions in each TiKV node. TiKV uses the Raft protocol for replication to ensure the data consistency and disaster recovery. The replicas of the same Region on different nodes compose a Raft Group. The load balancing of the data among different TiKV nodes are scheduled by PD. Region is also the basic unit for scheduling the load balance.Features Horizontal scalability Horizontal scalability is the most important feature of TiDB. The scalability includes two aspects: the computing capability and the storage capacity. The TiDB server processes the SQL requests. As the business grows, the overall processing capability and higher throughput can be achieved by simply adding more TiDB server nodes. Data is stored in TiKV. As the size of the data grows, the scalability of data can be resolved by adding more TiKV server nodes. PD schedules data in Regions among the TiKV nodes and migrates part of the data to the newly added node. So in the early stage, you can deploy only a few service instances. For example, it is recommended to deploy at least 3 TiKV nodes, 3 PD nodes and 2 TiDB nodes. As business grows, more TiDB and TiKV instances can be added on-demand.High availability High availability is another important feature of TiDB. All of the three components, TiDB, TiKV and PD, can tolerate the failure of some instances without impacting the availability of the entire cluster. For each component, See the following for more details about the availability, the consequence of a single instance failure and how to recover.TiDB TiDB is stateless and it is recommended to deploy at least two instances. The front-end provides services to the outside through the load balancing components. If one of the instances is down, the Session on the instance will be impacted. From the application’s point of view, it is a single request failure but the service can be regained by reconnecting to the TiDB server. If a single instance is down, the service can be recovered by restarting the instance or by deploying a new one.PD PD is a cluster and the data consistency is ensured using the Raft protocol. If an instance is down but the instance is not a Raft Leader, there is no impact on the service at all. If the instance is a Raft Leader, a new Leader will be elected to recover the service. During the election which is approximately 3 seconds, PD cannot provide service. It is recommended to deploy three instances. If one of the instances is down, the service can be recovered by restarting the instance or by deploying a new one.TiKV TiKV is a cluster and the data consistency is ensured using the Raft protocol. The number of the replicas can be configurable and the default is 3 replicas. The load of TiKV servers are balanced through PD. If one of the node is down, all the Regions in the node will be impacted. If the failed node is the Leader of the Region, the service will be interrupted and a new election will be initiated. If the failed node is a Follower of the Region, the service will not be impacted. If a TiKV node is down for a period of time (the default value is 10 minutes), PD will move the data to another TiKV node."}, {"url": "https://pingcap.com/docs/v2.0/", "title": "About TiDB", "content": " About TiDB TiDB introduction TiDB (The pronunciation is: /‘taɪdiːbi:/ tai-D-B, etymology: titanium) is an open-source distributed scalable Hybrid Transactional and Analytical Processing (HTAP) database. It features infinite horizontal scalability, strong consistency, and high availability. TiDB is MySQL compatible and serves as a one-stop data warehouse for both OLTP (Online Transactional Processing) and OLAP (Online Analytical Processing) workloads. Horizontal scalabilityTiDB provides horizontal scalability simply by adding new nodes. Never worry about infrastructure capacity ever again. MySQL compatibilityEasily replace MySQL with TiDB to power your applications without changing a single line of code in most cases and still benefit from the MySQL ecosystem. Distributed transactionTiDB is your source of truth, guaranteeing ACID compliance, so your data is accurate and reliable anytime, anywhere. Cloud NativeTiDB is designed to work in the cloud – public, private, or hybrid – making deployment, provisioning, and maintenance drop-dead simple. No more ETLETL (Extract, Transform and Load) is no longer necessary with TiDB’s hybrid OLTP/OLAP architecture, enabling you to create new values for your users, easier and faster. High availabilityWith TiDB, your data and applications are always on and continuously available, so your users are never disappointed. TiDB is designed to support both OLTP and OLAP scenarios. For complex OLAP scenarios, use TiSpark.Read the following three articles to understand TiDB techniques: Data Storage Computing Scheduling Roadmap Read the Roadmap.Connect with us Twitter: @PingCAP Reddit: https://www.reddit.com/r/TiDB/ Stack Overflow: https://stackoverflow.com/questions/tagged/tidb Mailing list: Google Group TiDB architecture To better understand TiDB’s features, you need to understand the TiDB architecture. The TiDB cluster includes three key components: the TiDB server, the PD server, and the TiKV server. In addition, TiDB also provides the TiSpark component for the complex OLAP requirements.TiDB server The TiDB server is in charge of the following operations: Receiving the SQL requests Processing the SQL related logics Locating the TiKV address for storing and computing data through Placement Driver (PD) Exchanging data with TiKV Returning the result The TiDB server is stateless. It does not store data and it is for computing only. TiDB is horizontally scalable and provides the unified interface to the outside through the load balancing components such as Linux Virtual Server (LVS), HAProxy, or F5.Placement Driver server The Placement Driver (PD) server is the managing component of the entire cluster and is in charge of the following three operations: Storing the metadata of the cluster such as the region location of a specific key. Scheduling and load balancing regions in the TiKV cluster, including but not limited to data migration and Raft group leader transfer. Allocating the transaction ID that is globally unique and monotonic increasing. As a cluster, PD needs to be deployed to an odd number of nodes. Usually it is recommended to deploy to 3 online nodes at least.TiKV server The TiKV server is responsible for storing data. From an external view, TiKV is a distributed transactional Key-Value storage engine. Region is the basic unit to store data. Each Region stores the data for a particular Key Range which is a left-closed and right-open interval from StartKey to EndKey. There are multiple Regions in each TiKV node. TiKV uses the Raft protocol for replication to ensure the data consistency and disaster recovery. The replicas of the same Region on different nodes compose a Raft Group. The load balancing of the data among different TiKV nodes are scheduled by PD. Region is also the basic unit for scheduling the load balance.TiSpark TiSpark deals with the complex OLAP requirements. TiSpark makes Spark SQL directly run on the storage layer of the TiDB cluster, combines the advantages of the distributed TiKV cluster, and integrates into the big data ecosystem. With TiSpark, TiDB can support both OLTP and OLAP scenarios in one cluster, so the users never need to worry about data synchronization.Features Horizontal scalability Horizontal scalability is the most important feature of TiDB. The scalability includes two aspects: the computing capability and the storage capacity. The TiDB server processes the SQL requests. As the business grows, the overall processing capability and higher throughput can be achieved by simply adding more TiDB server nodes. Data is stored in TiKV. As the size of the data grows, the scalability of data can be resolved by adding more TiKV server nodes. PD schedules data in Regions among the TiKV nodes and migrates part of the data to the newly added node. So in the early stage, you can deploy only a few service instances. For example, it is recommended to deploy at least 3 TiKV nodes, 3 PD nodes and 2 TiDB nodes. As business grows, more TiDB and TiKV instances can be added on-demand.High availability High availability is another important feature of TiDB. All of the three components, TiDB, TiKV and PD, can tolerate the failure of some instances without impacting the availability of the entire cluster. For each component, See the following for more details about the availability, the consequence of a single instance failure and how to recover.TiDB TiDB is stateless and it is recommended to deploy at least two instances. The front-end provides services to the outside through the load balancing components. If one of the instances is down, the Session on the instance will be impacted. From the application’s point of view, it is a single request failure but the service can be regained by reconnecting to the TiDB server. If a single instance is down, the service can be recovered by restarting the instance or by deploying a new one.PD PD is a cluster and the data consistency is ensured using the Raft protocol. If an instance is down but the instance is not a Raft Leader, there is no impact on the service at all. If the instance is a Raft Leader, a new Leader will be elected to recover the service. During the election which is approximately 3 seconds, PD cannot provide service. It is recommended to deploy three instances. If one of the instances is down, the service can be recovered by restarting the instance or by deploying a new one.TiKV TiKV is a cluster and the data consistency is ensured using the Raft protocol. The number of the replicas can be configurable and the default is 3 replicas. The load of TiKV servers are balanced through PD. If one of the node is down, all the Regions in the node will be impacted. If the failed node is the Leader of the Region, the service will be interrupted and a new election will be initiated. If the failed node is a Follower of the Region, the service will not be impacted. If a TiKV node is down for a period of time (default 30 minutes), PD will move the data to another TiKV node."}, {"url": "https://pingcap.com/docs/sql/aggregate-group-by-functions/", "title": "Aggregate (GROUP BY) Functions", "content": " Aggregate (GROUP BY) Functions This document describes details about the supported aggregate functions in TiDB.Supported aggregate functions This section describes the supported MySQL group (aggregate) functions in TiDB. Name Description COUNT() Return a count of the number of rows returned COUNT(DISTINCT) Return the count of a number of different values SUM() Return the sum AVG() Return the average value of the argument MAX() Return the maximum value MIN() Return the minimum value GROUP_CONCAT() Return a concatenated string Unless otherwise stated, group functions ignore NULL values. If you use a group function in a statement containing no GROUP BY clause, it is equivalent to grouping on all rows. GROUP BY modifiers TiDB does not currently support GROUP BY modifiers such as WITH ROLLUP. We plan to add support in the future. See TiDB #4250.SQL mode support TiDB supports the SQL Mode ONLY_FULL_GROUP_BY, and when enabled TiDB will refuse queries with ambiguous non-aggregated columns. For example, this query is illegal with ONLY_FULL_GROUP_BY enabled because the non-aggregated column “b” in the SELECT list does not appear in the GROUP BY statement:drop table if exists t; create table t(a bigint, b bigint, c bigint); insert into t values(1, 2, 3), (2, 2, 3), (3, 2, 3); mysql> select a, b, sum(c) from t group by a; +------+------+--------+ | a | b | sum(c) | +------+------+--------+ | 1 | 2 | 3 | | 2 | 2 | 3 | | 3 | 2 | 3 | +------+------+--------+ 3 rows in set (0.01 sec) mysql> set sql_mode = 'ONLY_FULL_GROUP_BY'; Query OK, 0 rows affected (0.00 sec) mysql> select a, b, sum(c) from t group by a; ERROR 1055 (42000): Expression #2 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'b' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by TiDB does not currently enable the ONLY_FULL_GROUP_BY mode by default.Differences from MySQL The current implementation of ONLY_FULL_GROUP_BY is less strict than that in MySQL 5.7. For example, suppose that we execute the following query, expecting the results to be ordered by “c”:drop table if exists t; create table t(a bigint, b bigint, c bigint); insert into t values(1, 2, 1), (1, 2, 2), (1, 3, 1), (1, 3, 2); select distinct a, b from t order by c; To order the result, duplicates must be eliminated first. But to do so, which row should we keep? This choice influences the retained value of “c”, which in turn influences ordering and makes it arbitrary as well.In MySQL, a query that has DISTINCT and ORDER BY is rejected as invalid if any ORDER BY expression does not satisfy at least one of these conditions: The expression is equal to one in the SELECT list All columns referenced by the expression and belonging to the query’s selected tables are elements of the SELECT list But in TiDB, the above query is legal, for more information see #4254.Another TiDB extension to standard SQL permits references in the HAVING clause to aliased expressions in the SELECT list. For example, the following query returns “name” values that occur only once in table “orders”:select name, count(name) from orders group by name having count(name) = 1; The TiDB extension permits the use of an alias in the HAVING clause for the aggregated column:select name, count(name) as c from orders group by name having c = 1; Standard SQL permits only column expressions in GROUP BY clauses, so a statement such as this is invalid because “FLOOR(value/100)” is a noncolumn expression:select id, floor(value/100) from tbl_name group by id, floor(value/100); TiDB extends standard SQL to permit noncolumn expressions in GROUP BY clauses and considers the preceding statement valid.Standard SQL also does not permit aliases in GROUP BY clauses. TiDB extends standard SQL to permit aliases, so another way to write the query is as follows:select id, floor(value/100) as val from tbl_name group by id, val; Unsupported aggregate functions The following aggregate functions are currently unsupported in TiDB. You can track our progress in TiDB #7623: STD, STDDEV, STDDEV_POP STDDEV_SAMP VARIANCE, VAR_POP VAR_SAMP JSON_ARRAYAGG JSON_OBJECTAGG "}, {"url": "https://pingcap.com/docs/v1.0/sql/aggregate-group-by-functions/", "title": "Aggregate (GROUP BY) Functions", "content": " Aggregate (GROUP BY) Functions Aggregate (GROUP BY) function descriptions This section describes the supported MySQL group (aggregate) functions in TiDB. Name Description COUNT() Return a count of the number of rows returned COUNT(DISTINCT) Return the count of a number of different values SUM() Return the sum AVG() Return the average value of the argument MAX() Return the maximum value MIN() Return the minimum value GROUP_CONCAT() Return a concatenated string Unless otherwise stated, group functions ignore NULL values. If you use a group function in a statement containing no GROUP BY clause, it is equivalent to grouping on all rows. For more information see TiDB handling of GROUP BY. GROUP BY modifiers TiDB dose not support any GROUP BY modifiers currently. We’ll do it in the future. For more information, see #4250.TiDB handling of GROUP BY TiDB performs equivalent to MySQL with sql mode ONLY_FULL_GROUP_BY being disabled: permits the SELECT list, HAVING condition, or ORDER BY list to refer to non-aggregated columns even if the columns are not functionally dependent on GROUP BY columns.For example, this query is illegal in MySQL 5.7.5 with ONLY_FULL_GROUP_BY enabled because the non-aggregated column “b” in the SELECT list does not appear in the GROUP BY:drop table if exists t; create table t(a bigint, b bigint, c bigint); insert into t values(1, 2, 3), (2, 2, 3), (3, 2, 3); select a, b, sum(c) from t group by a; The preceding query is legal in TiDB. TiDB does not support SQL mode ONLY_FULL_GROUP_BY currently. We’ll do it in the future. For more inmormation, see #4248.Suppose that we execute the following query, expecting the results to be ordered by “c”:drop table if exists t; create table t(a bigint, b bigint, c bigint); insert into t values(1, 2, 1), (1, 2, 2), (1, 3, 1), (1, 3, 2); select distinct a, b from t order by c; To order the result, duplicates must be eliminated first. But to do so, which row should we keep? This choice influences the retained value of “c”, which in turn influences ordering and makes it arbitrary as well.In MySQL, a query that has DISTINCT and ORDER BY is rejected as invalid if any ORDER BY expression does not satisfy at least one of these conditions: - The expression is equal to one in the SELECT list - All columns referenced by the expression and belonging to the query’s selected tables are elements of the SELECT listBut in TiDB, the above query is legal, for more information see #4254.Another TiDB extension to standard SQL permits references in the HAVING clause to aliased expressions in the SELECT list. For example, the following query returns “name” values that occur only once in table “orders”:select name, count(name) from orders group by name having count(name) = 1; The TiDB extension permits the use of an alias in the HAVING clause for the aggregated column:select name, count(name) as c from orders group by name having c = 1; Standard SQL permits only column expressions in GROUP BY clauses, so a statement such as this is invalid because “FLOOR(value/100)” is a noncolumn expression:select id, floor(value/100) from tbl_name group by id, floor(value/100); TiDB extends standard SQL to permit noncolumn expressions in GROUP BY clauses and considers the preceding statement valid.Standard SQL also does not permit aliases in GROUP BY clauses. TiDB extends standard SQL to permit aliases, so another way to write the query is as follows:select id, floor(value/100) as val from tbl_name group by id, val; Detection of functional dependence TiDB does not support SQL mode ONLY_FULL_GROUP_BY and detection of functional dependence. We’ll do it in the future. For more information, see #4248."}, {"url": "https://pingcap.com/docs/v2.0/sql/aggregate-group-by-functions/", "title": "Aggregate (GROUP BY) Functions", "content": " Aggregate (GROUP BY) Functions This document describes details about the supported aggregate functions in TiDB.Aggregate (GROUP BY) function descriptions This section describes the supported MySQL group (aggregate) functions in TiDB. Name Description COUNT() Return a count of the number of rows returned COUNT(DISTINCT) Return the count of a number of different values SUM() Return the sum AVG() Return the average value of the argument MAX() Return the maximum value MIN() Return the minimum value GROUP_CONCAT() Return a concatenated string Unless otherwise stated, group functions ignore NULL values. If you use a group function in a statement containing no GROUP BY clause, it is equivalent to grouping on all rows. For more information see TiDB handling of GROUP BY. GROUP BY modifiers TiDB dose not support any GROUP BY modifiers currently. We’ll do it in the future. For more information, see #4250.TiDB handling of GROUP BY TiDB performs equivalent to MySQL with sql mode ONLY_FULL_GROUP_BY being disabled: permits the SELECT list, HAVING condition, or ORDER BY list to refer to non-aggregated columns even if the columns are not functionally dependent on GROUP BY columns.For example, this query is illegal in MySQL 5.7.5 with ONLY_FULL_GROUP_BY enabled because the non-aggregated column “b” in the SELECT list does not appear in the GROUP BY:drop table if exists t; create table t(a bigint, b bigint, c bigint); insert into t values(1, 2, 3), (2, 2, 3), (3, 2, 3); select a, b, sum(c) from t group by a; The preceding query is legal in TiDB. TiDB does not support SQL mode ONLY_FULL_GROUP_BY currently. We’ll do it in the future. For more inmormation, see #4248.Suppose that we execute the following query, expecting the results to be ordered by “c”:drop table if exists t; create table t(a bigint, b bigint, c bigint); insert into t values(1, 2, 1), (1, 2, 2), (1, 3, 1), (1, 3, 2); select distinct a, b from t order by c; To order the result, duplicates must be eliminated first. But to do so, which row should we keep? This choice influences the retained value of “c”, which in turn influences ordering and makes it arbitrary as well.In MySQL, a query that has DISTINCT and ORDER BY is rejected as invalid if any ORDER BY expression does not satisfy at least one of these conditions: - The expression is equal to one in the SELECT list - All columns referenced by the expression and belonging to the query’s selected tables are elements of the SELECT listBut in TiDB, the above query is legal, for more information see #4254.Another TiDB extension to standard SQL permits references in the HAVING clause to aliased expressions in the SELECT list. For example, the following query returns “name” values that occur only once in table “orders”:select name, count(name) from orders group by name having count(name) = 1; The TiDB extension permits the use of an alias in the HAVING clause for the aggregated column:select name, count(name) as c from orders group by name having c = 1; Standard SQL permits only column expressions in GROUP BY clauses, so a statement such as this is invalid because “FLOOR(value/100)” is a noncolumn expression:select id, floor(value/100) from tbl_name group by id, floor(value/100); TiDB extends standard SQL to permit noncolumn expressions in GROUP BY clauses and considers the preceding statement valid.Standard SQL also does not permit aliases in GROUP BY clauses. TiDB extends standard SQL to permit aliases, so another way to write the query is as follows:select id, floor(value/100) as val from tbl_name group by id, val; Detection of functional dependence TiDB does not support SQL mode ONLY_FULL_GROUP_BY and detection of functional dependence. We’ll do it in the future. For more information, see #4248."}, {"url": "https://pingcap.com/agreements/", "title": "Agreements", "content": ""}, {"url": "https://pingcap.com/docs/v1.0/op-guide/ansible-deployment/", "title": "Ansible Deployment", "content": " Ansible Deployment Overview Ansible is an IT automation tool. It can configure systems, deploy software, and orchestrate more advanced IT tasks such as continuous deployments or zero downtime rolling updates.TiDB-Ansible is a TiDB cluster deployment tool developed by PingCAP, based on Ansible playbook. TiDB-Ansible enables you to quickly deploy a new TiDB cluster which includes PD, TiDB, TiKV, and the cluster monitoring modules.You can use the TiDB-Ansible configuration file to set up the cluster topology, completing all operation tasks with one click, including: Initializing operating system parameters Deploying the components Rolling upgrade, including module survival detection Cleaning data Cleaning environment Configuring monitoring modules Prepare Before you start, make sure that you have: Several target machines with the following requirements: 4 or more machines. At least 3 instances for TiKV. Do not deploy TiKV together with TiDB or PD on the same machine. See Software and Hardware Requirements. Recommended Operating system: CentOS 7.3 or later Linux x86_64 architecture (AMD64) ext4 filesystem Use ext4 filesystem for your data disks. Mount ext4 filesystem with the nodelalloc mount option. See Mount the data disk ext4 filesystem with options. The network between machines. Turn off the firewalls and iptables when deploying and turn them on after the deployment. The same time and time zone for all machines with the NTP service on to synchronize the correct time. See How to check whether the NTP service is normal. Create a normal tidb user account as the user who runs the service. The tidb user can sudo to the root user without a password. See How to configure SSH mutual trust and sudo without password.  > Note: When you deploy TiDB using Ansible, use SSD disks for the data directory of TiKV and PD nodes. A Control Machine with the following requirements: The Control Machine can be one of the managed nodes. It is recommended to install CentOS 7.3 or later version of Linux operating system (Python 2.7 involved by default). The Control Machine must have access to the Internet in order to download TiDB and related packages. Configure mutual trust of ssh authorized_key. In the Control Machine, you can login to the deployment target machine using tidb user account without a password. See How to configure SSH mutual trust and sudo without password. Install Ansible and dependencies in the Control Machine Use the following method to install Ansible on the Control Machine of CentOS 7 system. Installation from the EPEL source includes Ansible dependencies automatically (such as Jinja2==2.7.2 MarkupSafe==0.11). After installation, you can view the version using ansible --version. Note: Make sure that the Ansible version is Ansible 2.4 or later, otherwise a compatibility issue occurs. # yum install epel-release # yum install ansible curl # ansible --version ansible 2.4.2.0 For other systems, see Install Ansible.Download TiDB-Ansible to the Control Machine Login to the Control Machine using the tidb user account and enter the /home/tidb directory. Use the following command to download the corresponding version of TiDB-Ansible from GitHub TiDB-Ansible project. The default folder name is tidb-ansible.Download the 1.0 version:cd /home/tidb git clone -b release-1.0 https://github.com/pingcap/tidb-ansible.git orDownload the master version:cd /home/tidb git clone https://github.com/pingcap/tidb-ansible.git Note: For the production environment, download the 1.0 version to deploy TiDB. Orchestrate the TiDB cluster The file path of inventory.ini: tidb-ansible/inventory.iniThe standard cluster has 6 machines: 2 TiDB nodes, the first TiDB machine is used as a monitor 3 PD nodes 3 TiKV nodes The cluster topology of single TiKV instance on a single machine Name Host IP Services node1 172.16.10.1 PD1, TiDB1 node2 172.16.10.2 PD2, TiDB2 node3 172.16.10.3 PD3 node4 172.16.10.4 TiKV1 node5 172.16.10.5 TiKV2 node6 172.16.10.6 TiKV3 [tidb_servers] 172.16.10.1 172.16.10.2 [pd_servers] 172.16.10.1 172.16.10.2 172.16.10.3 [tikv_servers] 172.16.10.4 172.16.10.5 172.16.10.6 [monitoring_servers] 172.16.10.1 [grafana_servers] 172.16.10.1 [monitored_servers] 172.16.10.1 172.16.10.2 172.16.10.3 172.16.10.4 172.16.10.5 172.16.10.6 The cluster topology of multiple TiKV instances on a single machine Take two TiKV instances as an example: Name Host IP Services node1 172.16.10.1 PD1, TiDB1 node2 172.16.10.2 PD2, TiDB2 node3 172.16.10.3 PD3 node4 172.16.10.4 TiKV1-1, TiKV1-2 node5 172.16.10.5 TiKV2-1, TiKV2-2 node6 172.16.10.6 TiKV3-1, TiKV3-2 [tidb_servers] 172.16.10.1 172.16.10.2 [pd_servers] 172.16.10.1 172.16.10.2 172.16.10.3 [tikv_servers] TiKV1-1 ansible_host=172.16.10.4 deploy_dir=/data1/deploy tikv_port=20171 labels="host=tikv1" TiKV1-2 ansible_host=172.16.10.4 deploy_dir=/data2/deploy tikv_port=20172 labels="host=tikv1" TiKV1-3 ansible_host=172.16.10.4 deploy_dir=/data3/deploy tikv_port=20173 labels="host=tikv1" TiKV2-1 ansible_host=172.16.10.5 deploy_dir=/data1/deploy tikv_port=20171 labels="host=tikv2" TiKV2-2 ansible_host=172.16.10.5 deploy_dir=/data2/deploy tikv_port=20172 labels="host=tikv2" TiKV2-3 ansible_host=172.16.10.5 deploy_dir=/data3/deploy tikv_port=20173 labels="host=tikv2" TiKV3-1 ansible_host=172.16.10.6 deploy_dir=/data1/deploy tikv_port=20171 labels="host=tikv3" TiKV3-2 ansible_host=172.16.10.6 deploy_dir=/data2/deploy tikv_port=20172 labels="host=tikv3" TiKV3-3 ansible_host=172.16.10.6 deploy_dir=/data3/deploy tikv_port=20173 labels="host=tikv3" [monitoring_servers] 172.16.10.1 [grafana_servers] 172.16.10.1 [monitored_servers] 172.16.10.1 172.16.10.2 172.16.10.3 172.16.10.4 172.16.10.5 172.16.10.6 ...... [pd_servers:vars] location_labels = ["host"] Edit the parameters in the service configuration file: For multiple TiKV instances, edit the end-point-concurrency and block-cache-size parameters in tidb-ansible/conf/tikv.yml: end-point-concurrency: keep the number lower than CPU Vcores rocksdb defaultcf block-cache-size(GB): MEM * 80% / TiKV instance number * 30% rocksdb writecf block-cache-size(GB): MEM * 80% / TiKV instance number * 45% rocksdb lockcf block-cache-size(GB): MEM * 80% / TiKV instance number * 2.5% (128 MB at a minimum) raftdb defaultcf block-cache-size(GB): MEM * 80% / TiKV instance number * 2.5% (128 MB at a minimum) If multiple TiKV instances are deployed on a same physical disk, edit the capacity parameter in conf/tikv.yml: capacity: (DISK - log space) / TiKV instance number (the unit is GB) Description of inventory.ini variables Description of the deployment directory You can configure the deployment directory using the deploy_dir variable. The global variable is set to /home/tidb/deploy by default, and it applies to all services. If the data disk is mounted on the /data1 directory, you can set it to /data1/deploy. For example:## Global variables [all:vars] deploy_dir = /data1/deploy To set a deployment directory separately for a service, you can configure host variables when configuring the service host list. Take the TiKV node as an example and it is similar for other services. You must add the first column alias to avoid confusion when the services are mixedly deployed.TiKV1-1 ansible_host=172.16.10.4 deploy_dir=/data1/deploy Description of other variables Variable Description cluster_name the name of a cluster, adjustable tidb_version the version of TiDB, configured by default in TiDB-Ansible branches deployment_method the method of deployment, binary by default, Docker optional process_supervision the supervision way of processes, systemd by default, supervise optional timezone the timezone of the managed node, adjustable, Asia/Shanghai by default, used with the set_timezone variable set_timezone to edit the timezone of the managed node, True by default; False means closing enable_elk …"}, {"url": "https://pingcap.com/docs/v1.0/op-guide/root-ansible-deployment/", "title": "Ansible Deployment Using the Root User Account", "content": " Ansible Deployment Using the Root User Account Note: The remote Ansible user (the ansible_user in the incentory.ini file) can use the root user account to deploy TiDB, but it is not recommended. The following example uses the tidb user account as the user running the service.To deploy TiDB using a root user account, take the following steps: Edit inventory.ini as follows.Remove the code comments for ansible_user = root, ansible_become = true and ansible_become_user. Add comments for ansible_user = tidb.## Connection # ssh via root: ansible_user = root ansible_become = true ansible_become_user = tidb # ssh via normal user # ansible_user = tidb Connect to the network and download TiDB binary to the Control Machine.ansible-playbook local_prepare.yml Initialize the system environment and edit the kernel parameters.ansible-playbook bootstrap.yml Note: If the service user does not exist, the initialization operation will automatically create the user. If the remote connection using the root user requires a password, use the -k (lower case) parameter. This applies to other playbooks as well:ansible-playbook bootstrap.yml -k Deploy the TiDB cluster.ansible-playbook deploy.yml -k Start the TiDB cluster.ansible-playbook start.yml -k "}, {"url": "https://pingcap.com/tidb-academy/mysql_dbas/rocksdb/architecture/", "title": "Architecture", "content": " Architecture Resources Write Ahead Log SST MemTable Bloom Filter Transcript In this video, we are going to provide a brief introduction to how RocksDB works. Or even more specifically, how an LSM tree works, which is the basic data structure of RocksDB, which differs from InnoDB that uses a B+tree. We will also look at the filesystem to explain what you are seeing in TiKV’s data directory.Let’s start with the basic operation of inserting new rows into RocksDB:First, it’s important to state that the “core data structure” of the LSM is around key-value pairs. So I will not be using the term rows, but key-value pairs. If your table just has a primary key, then that will be the key, and the row data will be the value. If you have additional indexes, then those will also have additional key-values, where the value will be the primary key. It is also important to state that despite being key-value, it is also transactional, so we can guarantee that multiple key-value pairs are updated atomically without any inconsistencies.OK. So let’s go through the example of inserting a new key-value pair in RocksDB:Similar to InnoDB, the first stage of any modification is to log it. RocksDB has a write-ahead-log which records history of the change for recovery purposes only. In InnoDB, these are sometimes called transaction logs or redo logs, but the process is very similar. Step #1 is to make sure that if there was a crash, the log can be replayed and durability is ensured.Once our key-value pair is in the write-ahead-log, it is inserted into an in-memory structure called a memtable. You can think of the memtable as like a buffer that is being filled up with changes. The goal is to be able to collect a batch of key-value pairs and then write them out in sorted order into an SST file.SST stands for static-stored-table. This is the core file structure of an LSM tree like RocksDB. As the name suggests, SST files contain a set of key-value pairs that are sorted in order. They are also only ever written once, and never updated in place.So if you look inside db/ of the RocksDB data directory, you will see a set of .sst files and a set of LOG files. The log files being the WAL that we mentioned are just prior.So as we keep batch inserting new rows, the memtable will fill and keep writing out new SST files. If we change that operation, and say that is now an update operation: well, because we said that SST files are never modified in place, the operation is very similar. We will write out a new SST file with the new key-value pair that takes precedence over the old value.So over time what might happen is that older SST files contain a lot of keys which have since been modified. It is now time to talk about one of the essential components of an LSM which is compaction. Compaction is the process of merging SST files and creating new SST files to replace them.So in this example, we can do a very efficient merge-sort to combine these two SST files into a new SST. Because the SST files are read-only, this operation can be done in the background. When the operation is complete, we now have a new larger SST file to replace the earlier files, which can now be deleted.So now that we’ve introduced merging of files, let’s introduce levels. The initial SST files written out from the memtable can be considered Level zero. We then merge these files to create level 1, and those files will over time be merged to create level two, and so on. Compaction can be seen as a tradeoff, and the more frequently (and aggressively) it runs, the more efficient the LSM tree will be for read operations. Compaction can also help free disk space, and you might see the free space of your TiKV servers fluctuates slightly as it is happening.RocksDB also allows different compression algorithms to be used per level, and in the default configuration, you will find that L0-L1 use no compression, L2-L4 use lz4 and L5-L6 use zstd, which while still fast, is much better for compression.So we’ve now provided a simplified description of how RocksDB works, there is only one key detail which is pertinent and that is the bloom filter. You can think of a bloom filter as like a special type of index. For a given key, it can accurately determine if a given key may exist or definitely does not exist in an SST file. While the may exist might sound strange since it is not a hard guarantee, the bloom filter is small to keep in memory and helps ensure good performance of point-lookup queries, since all SST files do not need to be opened."}, {"url": "https://pingcap.com/docs/op-guide/backup-restore/", "title": "Backup and Restore", "content": " Backup and Restore About This document describes how to back up and restore the data of TiDB. Currently, this document only covers full backup and restoration.Here we assume that the TiDB service information is as follows: Name Address Port User Password TiDB 127.0.0.1 4000 root * Use the following tools for data backup and restoration: mydumper: to export data from TiDB loader: to import data into TiDB Download TiDB toolset (Linux) # Download the tool package. wget http://download.pingcap.org/tidb-enterprise-tools-latest-linux-amd64.tar.gz wget http://download.pingcap.org/tidb-enterprise-tools-latest-linux-amd64.sha256 # Check the file integrity. If the result is OK, the file is correct. sha256sum -c tidb-enterprise-tools-latest-linux-amd64.sha256 # Extract the package. tar -xzf tidb-enterprise-tools-latest-linux-amd64.tar.gz cd tidb-enterprise-tools-latest-linux-amd64 Full backup and restoration using mydumper/loader You can use mydumper to export data from MySQL and loader to import the data into TiDB. Important: You must use the mydumper from the Enterprise Tools package, and not the mydumper provided by your operating system’s package manager. The upstream version of mydumper does not yet handle TiDB correctly (#155). Using mysqldump is also not recommended, as it is much slower for both backup and restoration. Best practices of full backup and restoration using mydumper/loader To quickly backup and restore data (especially large amounts of data), refer to the following recommendations: Keep the exported data file as small as possible and it is recommended keep it within 64M. You can use the -F parameter to set the value. You can adjust the -t parameter of loader based on the number and the load of TiKV instances. For example, if there are three TiKV instances, -t can be set to 3 * (1 ~ n). If the load of TiKV is too high and the log backoffer.maxSleep 15000ms is exceeded is displayed many times, decrease the value of -t; otherwise, increase it. An example of restoring data and related configuration The total size of the exported files is 214G. A single table has 8 columns and 2 billion rows. The cluster topology: 12 TiKV instances: 4 nodes, 3 TiKV instances per node 4 TiDB instances 3 PD instances The configuration of each node: CPU: Intel Xeon E5-2670 v3 @ 2.30GHz 48 vCPU [2 x 12 physical cores] Memory: 128G Disk: sda [raid 10, 300G] sdb[RAID 5, 2T] Operating System: CentOS 7.3 The -F parameter of mydumper is set to 16 and the -t parameter of loader is set to 64. Results: It takes 11 hours to import all the data, which is 19.4G/hour.Backup data from TiDB Use mydumper to backup data from TiDB../bin/mydumper -h 127.0.0.1 -P 4000 -u root -t 16 -F 64 -B test -T t1,t2 --skip-tz-utc -o ./var/test In this command, -B test: means the data is exported from the test database. -T t1,t2: means only the t1 and t2 tables are exported. -t 16: means 16 threads are used to export the data. -F 64: means a table is partitioned into chunks and one chunk is 64MB. --skip-tz-utc: the purpose of adding this parameter is to ignore the inconsistency of time zone setting between MySQL and the data exporting machine and to disable automatic conversion. Restore data into TiDB To restore data into TiDB, use loader to import the previously exported data. See Loader instructions for more information../bin/loader -h 127.0.0.1 -u root -P 4000 -t 32 -d ./var/test After the data is imported, you can view the data in TiDB using the MySQL client:mysql -h127.0.0.1 -P4000 -uroot mysql> show tables; +----------------+ | Tables_in_test | +----------------+ | t1 | | t2 | +----------------+ mysql> select * from t1; +----+------+ | id | age | +----+------+ | 1 | 1 | | 2 | 2 | | 3 | 3 | +----+------+ mysql> select * from t2; +----+------+ | id | name | +----+------+ | 1 | a | | 2 | b | | 3 | c | +----+------+"}, {"url": "https://pingcap.com/docs/v1.0/op-guide/backup-restore/", "title": "Backup and Restore", "content": " Backup and Restore About This document describes how to backup and restore the data of TiDB. Currently, this document only covers full backup and restoration.Here we assume that the TiDB service information is as follows: Name Address Port User Password TiDB 127.0.0.1 4000 root * Use the following tools for data backup and restoration: mydumper: to export data from TiDB loader: to import data into TiDB Download TiDB toolset (Linux) # Download the tool package. wget http://download.pingcap.org/tidb-enterprise-tools-latest-linux-amd64.tar.gz wget http://download.pingcap.org/tidb-enterprise-tools-latest-linux-amd64.sha256 # Check the file integrity. If the result is OK, the file is correct. sha256sum -c tidb-enterprise-tools-latest-linux-amd64.sha256 # Extract the package. tar -xzf tidb-enterprise-tools-latest-linux-amd64.tar.gz cd tidb-enterprise-tools-latest-linux-amd64 Full backup and restoration using mydumper/loader You can use mydumper to export data from MySQL and loader to import the data into TiDB. Note: Although TiDB also supports the official mysqldump tool from MySQL for data migration, it is not recommended to use it. Its performance is much lower than mydumper/loader and it takes much time to migrate large amounts of data. mydumper/loader is more powerful. For more information, see https://github.com/maxbube/mydumper. Best practices of full backup and restoration using mydumper/loader To quickly backup and restore data (especially large amounts of data), refer to the following recommendations: Keep the exported data file as small as possible and it is recommended keep it within 64M. You can use the -F parameter to set the value. You can adjust the -t parameter of loader based on the number and the load of TiKV instances. For example, if there are three TiKV instances, -t can be set to 3 * (1 ~ n). If the load of TiKV is too high and the log backoffer.maxSleep 15000ms is exceeded is displayed many times, decrease the value of -t; otherwise, increase it. An example of restoring data and related configuration The total size of the exported files is 214G. A single table has 8 columns and 2 billion rows. The cluster topology: 12 TiKV instances: 4 nodes, 3 TiKV instances per node 4 TiDB instances 3 PD instances The configuration of each node: CPU: Intel Xeon E5-2670 v3 @ 2.30GHz 48 vCPU [2 x 12 physical cores] Memory: 128G Disk: sda [raid 10, 300G] sdb[RAID 5, 2T] Operating System: CentOS 7.3 The -F parameter of mydumper is set to 16 and the -t parameter of loader is set to 64. Results: It takes 11 hours to import all the data, which is 19.4G/hour.Backup data from TiDB Use mydumper to backup data from TiDB../bin/mydumper -h 127.0.0.1 -P 4000 -u root -t 16 -F 64 -B test -T t1,t2 --skip-tz-utc -o ./var/test In this command, -B test: means the data is exported from the test database. -T t1,t2: means only the t1 and t2 tables are exported. -t 16: means 16 threads are used to export the data. -F 64: means a table is partitioned into chunks and one chunk is 64MB. --skip-tz-utc: the purpose of adding this parameter is to ignore the inconsistency of time zone setting between MySQL and the data exporting machine and to disable automatic conversion. Restore data into TiDB To restore data into TiDB, use loader to import the previously exported data. See Loader instructions for more information../bin/loader -h 127.0.0.1 -u root -P 4000 -t 32 -d ./var/test After the data is imported, you can view the data in TiDB using the MySQL client:mysql -h127.0.0.1 -P4000 -uroot mysql> show tables; +----------------+ | Tables_in_test | +----------------+ | t1 | | t2 | +----------------+ mysql> select * from t1; +----+------+ | id | age | +----+------+ | 1 | 1 | | 2 | 2 | | 3 | 3 | +----+------+ mysql> select * from t2; +----+------+ | id | name | +----+------+ | 1 | a | | 2 | b | | 3 | c | +----+------+"}, {"url": "https://pingcap.com/docs/v2.0/op-guide/backup-restore/", "title": "Backup and Restore", "content": " Backup and Restore About This document describes how to back up and restore the data of TiDB. Currently, this document only covers full backup and restoration.Here we assume that the TiDB service information is as follows: Name Address Port User Password TiDB 127.0.0.1 4000 root * Use the following tools for data backup and restoration: mydumper: to export data from TiDB loader: to import data into TiDB Download TiDB toolset (Linux) # Download the tool package. wget http://download.pingcap.org/tidb-enterprise-tools-latest-linux-amd64.tar.gz wget http://download.pingcap.org/tidb-enterprise-tools-latest-linux-amd64.sha256 # Check the file integrity. If the result is OK, the file is correct. sha256sum -c tidb-enterprise-tools-latest-linux-amd64.sha256 # Extract the package. tar -xzf tidb-enterprise-tools-latest-linux-amd64.tar.gz cd tidb-enterprise-tools-latest-linux-amd64 Full backup and restoration using mydumper/loader You can use mydumper to export data from MySQL and loader to import the data into TiDB. Note: Although TiDB also supports the official mysqldump tool from MySQL for data migration, it is not recommended to use it. Its performance is much lower than mydumper/loader and it takes much time to migrate large amounts of data. mydumper/loader is more powerful. For more information, see https://github.com/maxbube/mydumper. Best practices of full backup and restoration using mydumper/loader To quickly backup and restore data (especially large amounts of data), refer to the following recommendations: Keep the exported data file as small as possible and it is recommended keep it within 64M. You can use the -F parameter to set the value. You can adjust the -t parameter of loader based on the number and the load of TiKV instances. For example, if there are three TiKV instances, -t can be set to 3 * (1 ~ n). If the load of TiKV is too high and the log backoffer.maxSleep 15000ms is exceeded is displayed many times, decrease the value of -t; otherwise, increase it. An example of restoring data and related configuration The total size of the exported files is 214G. A single table has 8 columns and 2 billion rows. The cluster topology: 12 TiKV instances: 4 nodes, 3 TiKV instances per node 4 TiDB instances 3 PD instances The configuration of each node: CPU: Intel Xeon E5-2670 v3 @ 2.30GHz 48 vCPU [2 x 12 physical cores] Memory: 128G Disk: sda [raid 10, 300G] sdb[RAID 5, 2T] Operating System: CentOS 7.3 The -F parameter of mydumper is set to 16 and the -t parameter of loader is set to 64. Results: It takes 11 hours to import all the data, which is 19.4G/hour.Backup data from TiDB Use mydumper to backup data from TiDB../bin/mydumper -h 127.0.0.1 -P 4000 -u root -t 16 -F 64 -B test -T t1,t2 --skip-tz-utc -o ./var/test In this command, -B test: means the data is exported from the test database. -T t1,t2: means only the t1 and t2 tables are exported. -t 16: means 16 threads are used to export the data. -F 64: means a table is partitioned into chunks and one chunk is 64MB. --skip-tz-utc: the purpose of adding this parameter is to ignore the inconsistency of time zone setting between MySQL and the data exporting machine and to disable automatic conversion. Restore data into TiDB To restore data into TiDB, use loader to import the previously exported data. See Loader instructions for more information../bin/loader -h 127.0.0.1 -u root -P 4000 -t 32 -d ./var/test After the data is imported, you can view the data in TiDB using the MySQL client:mysql -h127.0.0.1 -P4000 -uroot mysql> show tables; +----------------+ | Tables_in_test | +----------------+ | t1 | | t2 | +----------------+ mysql> select * from t1; +----+------+ | id | age | +----+------+ | 1 | 1 | | 2 | 2 | | 3 | 3 | +----+------+ mysql> select * from t2; +----+------+ | id | name | +----+------+ | 1 | a | | 2 | b | | 3 | c | +----+------+"}, {"url": "https://pingcap.com/tidb-academy/mysql_dbas/backup/overview/", "title": "Backup and Restore", "content": " Backup and Restore Transcript You can’t be a DBA without knowing how to backup and restore. It is one of the fundamental skills of database administration, and in this lesson we are going to be taking a closer look.But before we dive too deep, I want to take a step back and describe some of the fundamentals behind a High Availability and Disaster Recovery plan.TiKV provides High Availability (HA) natively out of the box, ensuring three copies of each Region are retained. It can also provide Disaster Recovery, or to differentiate between the terms HA and DR, it is common to have one of the copies located remotely. TiDB itself will only read from the primary Region, so there is some PD configuration that we will look into later to assist in this setup. Additionally, range partitioning can be used so that the primaries are pushed to where the data is needed. For example, a database shared across many branches and partitioned by branch.Now that we’ve made that digression, let’s clarify that you still need a backup. Your HA plan may not have accounted for a particular catastrophe. But even perfect HA cannot protect against human errors or malicious actions.The most common case of restoring data is accidental deletes. For example, someone in your organization updated the wrong row, and information has been lost. Or a bug in a recently released update has started corrupting records, and you want to intelligently restore earlier versions of data. In MySQL, you have to start fixing this problem by restoring a backup to a new MySQL instance and then rolling forward through binary logs to find the lost data. Then you usually dump the lost data out of the old version and insert/update it into your active customer facing MySQL instance. Sometimes you will need to do the same in TiDB. However, you may not even need to go to bakup to find your lost data: it supports the ability to flashback and read the data as it appeared at an earlier point in time up to your retention window.The success of any backup plan is usually measured on two key criteria: the Recovery Time Objective, meaning how quickly service can be restored after a failure has occurred, and the Recovery point objective, meaning how much data was lost between the last backup and when the disaster occurred. Backups in TiDB are hot, in that they can be taken on the running system without blocking either reads or writes from occurring.Let’s jump forward and practice flashback in our first lab."}, {"url": "https://pingcap.com/docs/bikeshare-example-database/", "title": "Bikeshare Example Database", "content": " Bikeshare Example Database Examples used in the TiDB manual use System Data from Capital Bikeshare, released under the Capital Bikeshare Data License Agreement.Download all data files The system data is available for download in .zip files organized per year. Downloading and extracting all files requires approximately 3GB of disk space. To download all files for years 2010-2017 using a bash script:mkdir -p bikeshare-data && cd bikeshare-data for YEAR in 2010 2011 2012 2013 2014 2015 2016 2017; do wget https://s3.amazonaws.com/capitalbikeshare-data/${YEAR}-capitalbikeshare-tripdata.zip unzip ${YEAR}-capitalbikeshare-tripdata.zip done; Load data into TiDB The system data can be imported into TiDB using the following schema:CREATE DATABASE bikeshare; USE bikeshare; CREATE TABLE trips ( trip_id bigint NOT NULL PRIMARY KEY auto_increment, duration integer not null, start_date datetime, end_date datetime, start_station_number integer, start_station varchar(255), end_station_number integer, end_station varchar(255), bike_number varchar(255), member_type varchar(255) ); You can import files individually using the example LOAD DATA command here, or import all files using the bash loop below:LOAD DATA LOCAL INFILE '2017Q1-capitalbikeshare-tripdata.csv' INTO TABLE trips FIELDS TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY 'rn' IGNORE 1 LINES (duration, start_date, end_date, start_station_number, start_station, end_station_number, end_station, bike_number, member_type); Import all files To import all *.csv files into TiDB in a bash loop:for FILE in `ls *.csv`; do echo "== $FILE==" mysql bikeshare -e "LOAD DATA LOCAL INFILE '${FILE}' INTO TABLE trips FIELDS TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY 'rn' IGNORE 1 LINES (duration, start_date, end_date, start_station_number, start_station, end_station_number, end_station, bike_number, member_type);" done;"}, {"url": "https://pingcap.com/docs/tools/binlog-slave-client/", "title": "Binlog Slave Client User Guide", "content": " Binlog Slave Client User Guide Binlog Slave Client is used to parse the binlog data and output the data in a specific format to Kafka. Currently, Drainer supports outputting data in multiple formats including MySQL, TiDB, TheFlash, and pb. But sometimes users have customized requirements for outputting data to other formats, for example, Elasticsearch and Hive, so this feature is introduced. After data is output to Kafka, the user writes code to read data from Kafka and then processes the data.Configure Drainer Modify the configuration file of Drainer and set it to output the data to Kafka:[syncer] db-type = "kafka" [syncer.to] # the Kafka address kafka-addrs = "127.0.0.1:9092" # the Kafka version kafka-version = "0.8.2.0" Customized development Data format Firstly, you need to obtain the format information of the data which is output to Kafka by Drainer:// `Column` stores the column data in the corresponding variable based on the data type. message Column { // Indicates whether the data is null optional bool is_null = 1 [ default = false ]; // Stores `int` data optional int64 int64_value = 2; // Stores `uint`, `enum`, and `set` data optional uint64 uint64_value = 3; // Stores `float` and `double` data optional double double_value = 4; // Stores `bit`, `blob`, `binary` and `json` data optional bytes bytes_value = 5; // Stores `date`, `time`, `decimal`, `text`, `char` data optional string string_value = 6; } // `ColumnInfo` stores the column information, including the column name, type, and whether it is the primary key. message ColumnInfo { optional string name = 1 [ (gogoproto.nullable) = false ]; // the lower case column field type in MySQL // https://dev.mysql.com/doc/refman/8.0/en/data-types.html // for the `numeric` type: int bigint smallint tinyint float double decimal bit // for the `string` type: text longtext mediumtext char tinytext varchar // blob longblog mediumblog binary tinyblob varbinary // enum set // for the `json` type: json optional string mysql_type = 2 [ (gogoproto.nullable) = false ]; optional bool is_primary_key = 3 [ (gogoproto.nullable) = false ]; } // `Row` stores the actual data of a row. message Row { repeated Column columns = 1; } // `MutationType` indicates the DML type. enum MutationType { Insert = 0; Update = 1; Delete = 2; } // `Table` contains mutations in a table. message Table { optional string schema_name = 1; optional string table_name = 2; repeated ColumnInfo column_info = 3; repeated TableMutation mutations = 4; } // `TableMutation` stores mutations of a row. message TableMutation { required MutationType type = 1; // data after modification required Row row = 2; // data before modification. It only takes effect for `Update MutationType`. optional Row change_row = 3; } // `DMLData` stores all the mutations caused by DML in a table. message DMLData { // `tables` contains all the table changes. repeated Table tables = 1; } // `DDLData` stores the DDL information. message DDLData { // the database used currently optional string schema_name = 1; // the relates table optional string table_name = 2; // `ddl_query` is the original DDL statement query. optional bytes ddl_query = 3; } // `BinlogType` indicates the binlog type, including DML and DDL. enum BinlogType { DML = 0; // Has `dml_data` DDL = 1; // Has `ddl_query` } // `Binlog` stores all the changes in a transaction. Kafka stores the serialized result of the structure data. message Binlog { optional BinlogType type = 1 [ (gogoproto.nullable) = false ]; optional int64 commit_ts = 2 [ (gogoproto.nullable) = false ]; // `dml_data` is marshalled from the DML type. optional DMLData dml_data = 3; optional DDLData ddl_data = 4; } For the definition of the data format, see binlog.proto.Driver The TiDB-Tools project provides Driver, which is used to read the binlog data in Kafka. It has the following features: Read the Kafka data. Locate the binlog stored in Kafka based on commit ts. You need to configure the following information when using Driver: KafkaAddr: the address of the Kafka cluster CommitTS: from which commit ts to start reading the binlog Offset: from which Kafka offset to start reading data. If CommitTS is set, you needn’t configure this parameter ClusterID: the cluster ID of the TiDB cluster You can use Driver by quoting the Driver code in package and refer to the example code provided by Driver to learn how to use Driver and parse the binlog data.Currently, two examples are provided: Using Driver to synchronize data to MySQL. This example shows how to convert a binlog to SQL Using Driver to print data Notes: The example code only shows how to use Driver. If you want to use Driver in the production environment, you need to optimize the code. Currently, only the Golang version of Driver and example code are available. If you want to use other languages, you need to generate the code file in the corresponding language based on the binlog proto file and develop an application to read the binlog data in Kafka, parse the data, and output the data to the downstream. You are also welcome to optimize the example code and submit the example code of other languages to TiDB-Tools. "}, {"url": "https://pingcap.com/docs-cn/tools/binlog-slave-client/", "title": "Binlog Slave Client 用户文档", "content": " Binlog Slave Client 用户文档 目前 Drainer 提供了多种输出方式,包括 MySQL、TiDB、TheFlash、pb 格式文件等。但是用户往往有一些自定义的需求,比如输出到 Elasticsearch、Hive 等,这些需求 Drainer 现在还没有实现,因此 Drainer 增加了输出到 Kafka 的功能,将 binlog 数据解析后按一定的格式再输出到 Kafka 中,用户编写代码从 Kafka 中读出数据再进行处理。配置 Drainer 修改 Drainer 的配置文件,设置输出为 Kafka,相关配置如下:[syncer] db-type = "kafka" [syncer.to] # Kafka 地址 kafka-addrs = "127.0.0.1:9092" # Kafka 版本号 kafka-version = "0.8.2.0" 自定义开发 数据格式 首先需要了解 Drainer 写入到 Kafka 中的数据格式:// Column 保存列的数据,针对数据的类型,保存在对应的变量中 message Column { // 数据是否为 null optional bool is_null = 1 [ default = false ]; // 保存 int 类型的数据 optional int64 int64_value = 2; // 保存 uint、enum, set 类型的数据 optional uint64 uint64_value = 3; // 保存 float、double 类型的数据 optional double double_value = 4; // 保存 bit、blob、binary、json 类型的数据 optional bytes bytes_value = 5; // 保存 date、time、decimal、text、char 类型的数据 optional string string_value = 6; } // ColumnInfo 保存列的信息,包括列名、类型、是否为主键 message ColumnInfo { optional string name = 1 [ (gogoproto.nullable) = false ]; // MySQL 中小写的列字段类型 // https://dev.mysql.com/doc/refman/8.0/en/data-types.html // numeric 类型:int bigint smallint tinyint float double decimal bit // string 类型:text longtext mediumtext char tinytext varchar // blob longblog mediumblog binary tinyblob varbinary // enum set // json 类型:json optional string mysql_type = 2 [ (gogoproto.nullable) = false ]; optional bool is_primary_key = 3 [ (gogoproto.nullable) = false ]; } // Row 保存一行的具体数据 message Row { repeated Column columns = 1; } // MutationType 表示 DML 的类型 enum MutationType { Insert = 0; Update = 1; Delete = 2; } // Table 包含一个表的数据变更 message Table { optional string schema_name = 1; optional string table_name = 2; repeated ColumnInfo column_info = 3; repeated TableMutation mutations = 4; } // TableMutation 保存一行数据的变更 message TableMutation { required MutationType type = 1; // 修改后的数据 required Row row = 2; // 修改前的数据,只对 Update MutationType 有效 optional Row change_row = 3; } // DMLData 保存一个表所有的 DML 造成的数据变更 message DMLData { // `tables` 包含一个表的所有数据变更 repeated Table tables = 1; } // DDLData 保存 DDL 的信息 message DDLData { // 当前使用的数据库 optional string schema_name = 1; // 相关表 optional string table_name = 2; // `ddl_query` 是原始的 DDL 语句 query optional bytes ddl_query = 3; } // BinlogType 为 Binlog 的类型,分为 DML 和 DDL enum BinlogType { DML = 0; // Has `dml_data` DDL = 1; // Has `ddl_query` } // Binlog 保存一个事务所有的变更,Kafka 中保存的数据为该结构数据序列化后的结果 message Binlog { optional BinlogType type = 1 [ (gogoproto.nullable) = false ]; optional int64 commit_ts = 2 [ (gogoproto.nullable) = false ]; // dml_data 是由 DML 类型的数据序列化后生成的数据 optional DMLData dml_data = 3; optional DDLData ddl_data = 4; } 查看数据格式的具体定义,参见 binlog.proto。Driver TiDB-Tools 项目提供了用于读取 Kafka 中 binlog 数据的 Driver,具有如下功能: 读取 Kafka 的数据 根据 commit ts 查找到 Kafka 中存储的 binlog 的位置 使用该 Driver 时,用户需要配置如下信息: KafkaAddr:Kafka 集群的地址 CommitTS:从哪个 commit ts 开始读取 binlog Offset:从 Kafka 哪个 offset 开始读取,如果设置了 CommitTS 就不用配置该参数 ClusterID:TiDB 集群的 cluster ID 用户以包的形式引用 Driver 的代码即可使用,可以参考 Driver 中提供的的示例代码来学习如何使用 Driver 以及 binlog 数据的解析,目前提供了两个例子: 使用该 Driver 将数据同步到 MySQL,该示例包含将 binlog 转化为 SQL 的具体方法 使用该 Driver 将数据打印出来 Driver 项目地址:Binlog Slave Driver。 注意: 示例代码仅仅用于示范如何使用 Driver,如果需要用于生产环境需要优化代码。 目前仅提供了 golang 版本的 Driver 以及示例代码。如果需要使用其他语言,用户需要根据 binlog 的 proto 文件生成相应语言的代码文件,并自行开发程序读取 Kafka 中的 binlog 数据、解析数据、输出到下游。也欢迎用户优化 example 代码,以及提交其他语言的示例代码到 TiDB-Tools。 "}, {"url": "https://pingcap.com/docs/sql/bit-functions-and-operators/", "title": "Bit Functions and Operators", "content": " Bit Functions and Operators In TiDB, the usage of bit functions and operators is similar to MySQL. See Bit Functions and Operators.Bit functions and operators Name Description BIT_COUNT() Return the number of bits that are set as 1 & Bitwise AND ~ Bitwise inversion | Bitwise OR 0 Bitwise XOR << Left shift >> Right shift "}, {"url": "https://pingcap.com/docs/v1.0/sql/bit-functions-and-operators/", "title": "Bit Functions and Operators", "content": " Bit Functions and Operators In TiDB, the usage of bit functions and operators is similar to MySQL. See Bit Functions and Operators.Bit functions and operators Name Description BIT_COUNT() Return the number of bits that are set as 1 & Bitwise AND ~ Bitwise inversion | Bitwise OR 0 Bitwise XOR << Left shift >> Right shift "}, {"url": "https://pingcap.com/docs/v2.0/sql/bit-functions-and-operators/", "title": "Bit Functions and Operators", "content": " Bit Functions and Operators In TiDB, the usage of bit functions and operators is similar to MySQL. See Bit Functions and Operators.Bit functions and operators Name Description BIT_COUNT() Return the number of bits that are set as 1 & Bitwise AND ~ Bitwise inversion | Bitwise OR 0 Bitwise XOR << Left shift >> Right shift "}, {"url": "https://pingcap.com/docs-cn/sql/literal-value-bit-value/", "title": "Bit-value Literals", "content": " Bit-value Literals 位值字面值用 b 或者 0b 做前缀,后接以 0 跟 1 组成的二进制数字。其中 0b 是区分大小写的,0B 是会报错的。合法的 Bit-value: b’01’ B’01’ 0b01 非法的 Bit-value: b’2’ (2 不是二进制数值, 必须为 0 或 1) 0B01 (0B 必须是小写 0b) 默认情况,位值字面值是一个二进制字符串。Bit-value 是作为二进制返回的,所以输出到 MySQL Client 可能会显示不出来,如果要转换为可打印的字符,可以使用内建函数 BIN() 或者 HEX():CREATE TABLE t (b BIT(8)); INSERT INTO t SET b = b'00010011'; INSERT INTO t SET b = b'1110'; INSERT INTO t SET b = b'100101'; mysql> SELECT b+0, BIN(b), HEX(b) FROM t; +------+--------+--------+ | b+0 | BIN(b) | HEX(b) | +------+--------+--------+ | 19 | 10011 | 13 | | 14 | 1110 | E | | 37 | 100101 | 25 | +------+--------+--------+ 3 rows in set (0.00 sec)"}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/literal-value-bit-value/", "title": "Bit-value Literals", "content": " Bit-value Literals 位值字面值用 b 或者 0b 做前缀,后接以 0 跟 1 组成的二进制数字。其中 0b 是区分大小写的,0B 是会报错的。合法的 Bit-value: b’01’ B’01’ 0b01 非法的 Bit-value: b’2’ (2 不是二进制数值, 必须为 0 或 1) 0B01 (0B 必须是小写 0b) 默认情况,位值字面值是一个二进制字符串。Bit-value 是作为二进制返回的,所以输出到 MySQL Client 可能会显示不出来,如果要转换为可打印的字符,可以使用内建函数 BIN() 或者 HEX():CREATE TABLE t (b BIT(8)); INSERT INTO t SET b = b'00010011'; INSERT INTO t SET b = b'1110'; INSERT INTO t SET b = b'100101'; mysql> SELECT b+0, BIN(b), HEX(b) FROM t; +------+--------+--------+ | b+0 | BIN(b) | HEX(b) | +------+--------+--------+ | 19 | 10011 | 13 | | 14 | 1110 | E | | 37 | 100101 | 25 | +------+--------+--------+ 3 rows in set (0.00 sec)"}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/literal-value-bit-value/", "title": "Bit-value Literals", "content": " Bit-value Literals 位值字面值用 b 或者 0b 做前缀,后接以 0 跟 1 组成的二进制数字。其中 0b 是区分大小写的,0B 是会报错的。合法的 Bit-value: b’01’ B’01’ 0b01 非法的 Bit-value: b’2’ (2 不是二进制数值, 必须为 0 或 1) 0B01 (0B 必须是小写 0b) 默认情况,位值字面值是一个二进制字符串。Bit-value 是作为二进制返回的,所以输出到 MySQL Client 可能会显示不出来,如果要转换为可打印的字符,可以使用内建函数 BIN() 或者 HEX():CREATE TABLE t (b BIT(8)); INSERT INTO t SET b = b'00010011'; INSERT INTO t SET b = b'1110'; INSERT INTO t SET b = b'100101'; mysql> SELECT b+0, BIN(b), HEX(b) FROM t; +------+--------+--------+ | b+0 | BIN(b) | HEX(b) | +------+--------+--------+ | 19 | 10011 | 13 | | 14 | 1110 | E | | 37 | 100101 | 25 | +------+--------+--------+ 3 rows in set (0.00 sec)"}, {"url": "https://pingcap.com/blog-cn/", "title": "Blog-cns", "content": ""}, {"url": "https://pingcap.com/blog/", "title": "Blogs", "content": ""}, {"url": "https://pingcap.com/docs-cn/sql/literal-value-boolean/", "title": "Boolean Literals", "content": " Boolean Literals 常量 TRUE 和 FALSE 等于 1 和 0,它是大小写不敏感的。mysql> SELECT TRUE, true, tRuE, FALSE, FaLsE, false; +------+------+------+-------+-------+-------+ | TRUE | true | tRuE | FALSE | FaLsE | false | +------+------+------+-------+-------+-------+ | 1 | 1 | 1 | 0 | 0 | 0 | +------+------+------+-------+-------+-------+ 1 row in set (0.00 sec)"}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/literal-value-boolean/", "title": "Boolean Literals", "content": " Boolean Literals 常量 TRUE 和 FALSE 等于 1 和 0,它是大小写不敏感的。mysql> SELECT TRUE, true, tRuE, FALSE, FaLsE, false; +------+------+------+-------+-------+-------+ | TRUE | true | tRuE | FALSE | FaLsE | false | +------+------+------+-------+-------+-------+ | 1 | 1 | 1 | 0 | 0 | 0 | +------+------+------+-------+-------+-------+ 1 row in set (0.00 sec)"}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/literal-value-boolean/", "title": "Boolean Literals", "content": " Boolean Literals 常量 TRUE 和 FALSE 等于 1 和 0,它是大小写不敏感的。mysql> SELECT TRUE, true, tRuE, FALSE, FaLsE, false; +------+------+------+-------+-------+-------+ | TRUE | true | tRuE | FALSE | FaLsE | false | +------+------+------+-------+-------+-------+ | 1 | 1 | 1 | 0 | 0 | 0 | +------+------+------+-------+-------+-------+ 1 row in set (0.00 sec)"}, {"url": "https://pingcap.com/docs/sql/cast-functions-and-operators/", "title": "Cast Functions and Operators", "content": " Cast Functions and Operators Name Description BINARY Cast a string to a binary string CAST() Cast a value as a certain type CONVERT() Cast a value as a certain type Cast functions and operators enable conversion of values from one data type to another.For details, see here."}, {"url": "https://pingcap.com/docs/v1.0/sql/cast-functions-and-operators/", "title": "Cast Functions and Operators", "content": " Cast Functions and Operators Name Description BINARY Cast a string to a binary string CAST() Cast a value as a certain type CONVERT() Cast a value as a certain type Cast functions and operators enable conversion of values from one data type to another.For details, see here."}, {"url": "https://pingcap.com/docs/v2.0/sql/cast-functions-and-operators/", "title": "Cast Functions and Operators", "content": " Cast Functions and Operators Name Description BINARY Cast a string to a binary string CAST() Cast a value as a certain type CONVERT() Cast a value as a certain type Cast functions and operators enable conversion of values from one data type to another.For details, see here."}, {"url": "https://pingcap.com/docs-cn/sql/cast-functions-and-operators/", "title": "Cast 函数和操作符", "content": " Cast 函数和操作符 Cast 函数和操作符用于将某种数据类型的值转换为另一种数据类型。TiDB 中该函数和操作符的使用方法与 MySQL基本一致,详情参见: Cast Functions and Operators.Cast 函数和操作符表 函数和操作符名 功能描述 BINARY 将一个字符串转换成一个二进制字符串 CAST() 将一个值转换成一个确定类型 CONVERT() 将一个值转换成一个确定类型 "}, {"url": "https://pingcap.com/docs/sql/character-set-configuration/", "title": "Character Set Configuration", "content": " Character Set Configuration Currently, TiDB only supports the utf8 character set, which is the equivalent to utf8mb4 in MySQL. Since MySQL 5.7 defaults to latin1, this difference is documented under default differences between TiDB and MySQL.For more information, see Character Set Configuration in MySQL."}, {"url": "https://pingcap.com/docs/v1.0/sql/character-set-configuration/", "title": "Character Set Configuration", "content": " Character Set Configuration Currently, TiDB does not support configuring the character set. The default character set is utf8.For more information, see Character Set Configuration in MySQL."}, {"url": "https://pingcap.com/docs/v2.0/sql/character-set-configuration/", "title": "Character Set Configuration", "content": " Character Set Configuration Currently, TiDB does not support configuring the character set. The default character set is utf8mb4.For more information, see Character Set Configuration in MySQL."}, {"url": "https://pingcap.com/docs/sql/character-set-support/", "title": "Character Set Support", "content": " Character Set Support A character set is a set of symbols and encodings. A collation is a set of rules for comparing characters in a character set.Currently, TiDB supports the following character sets:mysql> SHOW CHARACTER SET; +---------|---------------|-------------------|--------+ | Charset | Description | Default collation | Maxlen | +---------|---------------|-------------------|--------+ | utf8 | UTF-8 Unicode | utf8_bin | 3 | | utf8mb4 | UTF-8 Unicode | utf8mb4_bin | 4 | | ascii | US ASCII | ascii_bin | 1 | | latin1 | Latin1 | latin1_bin | 1 | | binary | binary | binary | 1 | +---------|---------------|-------------------|--------+ 5 rows in set (0.00 sec) Note: In TiDB, utf8 is treated as utf8mb4. Each character set has at least one collation. Most of the character sets have several collations. You can use the following statement to display the available character sets:mysql> SHOW COLLATION WHERE Charset = 'latin1'; +-------------------|---------|------|---------|----------|---------+ | Collation | Charset | Id | Default | Compiled | Sortlen | +-------------------|---------|------|---------|----------|---------+ | latin1_german1_ci | latin1 | 5 | | Yes | 1 | | latin1_swedish_ci | latin1 | 8 | Yes | Yes | 1 | | latin1_danish_ci | latin1 | 15 | | Yes | 1 | | latin1_german2_ci | latin1 | 31 | | Yes | 1 | | latin1_bin | latin1 | 47 | | Yes | 1 | | latin1_general_ci | latin1 | 48 | | Yes | 1 | | latin1_general_cs | latin1 | 49 | | Yes | 1 | | latin1_spanish_ci | latin1 | 94 | | Yes | 1 | +-------------------|---------|------|---------|----------|---------+ 8 rows in set (0.00 sec) The latin1 collations have the following meanings: Collation Meaning latin1_bin Binary according to latin1 encoding latin1_danish_ci Danish/Norwegian latin1_general_ci Multilingual (Western European) latin1_general_cs Multilingual (ISO Western European), case sensitive latin1_german1_ci German DIN-1 (dictionary order) latin1_german2_ci German DIN-2 (phone book order) latin1_spanish_ci Modern Spanish latin1_swedish_ci Swedish/Finnish Each character set has a default collation. For example, the default collation for utf8 is utf8_bin. Note: The collations in TiDB are case sensitive. Collation naming conventions The collation names in TiDB follow these conventions: The prefix of a collation is its corresponding character set, generally followed by one or more suffixes indicating other collation characteristic. For example, utf8_general_ci and latin1_swedish_ci are collations for the utf8 and latin1 character sets, respectively. The binary character set has a single collation, also named binary, with no suffixes. A language-specific collation includes a language name. For example, utf8_turkish_ci and utf8_hungarian_ci sort characters for the utf8 character set using the rules of Turkish and Hungarian, respectively. Collation suffixes indicate whether a collation is case and accent sensitive, or binary. The following table shows the suffixes used to indicate these characteristics. Suffix Meaning _ai Accent insensitive _as Accent sensitive _ci Case insensitive _cs Case sensitive _bin Binary Note: Currently, TiDB only supports some of the collations in the above table. Database character set and collation Each database has a character set and a collation. You can use the CREATE DATABASE statement to specify the database character set and collation:CREATE DATABASE db_name [[DEFAULT] CHARACTER SET charset_name] [[DEFAULT] COLLATE collation_name] Where DATABASE can be replaced with SCHEMA.Different databases can use different character sets and collations. Use the character_set_database and collation_database to see the character set and collation of the current database:mysql> create schema test1 character set utf8 COLLATE uft8_general_ci; Query OK, 0 rows affected (0.09 sec) mysql> use test1; Database changed mysql> SELECT @@character_set_database, @@collation_database; +--------------------------|----------------------+ | @@character_set_database | @@collation_database | +--------------------------|----------------------+ | utf8 | uft8_general_ci | +--------------------------|----------------------+ 1 row in set (0.00 sec) mysql> create schema test2 character set latin1 COLLATE latin1_general_ci; Query OK, 0 rows affected (0.09 sec) mysql> use test2; Database changed mysql> SELECT @@character_set_database, @@collation_database; +--------------------------|----------------------+ | @@character_set_database | @@collation_database | +--------------------------|----------------------+ | latin1 | latin1_general_ci | +--------------------------|----------------------+ 1 row in set (0.00 sec) You can also see the two values in INFORMATION_SCHEMA:SELECT DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = 'db_name'; Table character set and collation You can use the following statement to specify the character set and collation for tables:CREATE TABLE tbl_name (column_list) [[DEFAULT] CHARACTER SET charset_name] [COLLATE collation_name]] ALTER TABLE tbl_name [[DEFAULT] CHARACTER SET charset_name] [COLLATE collation_name] For example:mysql> CREATE TABLE t1(a int) CHARACTER SET utf8 COLLATE utf8_general_ci; Query OK, 0 rows affected (0.08 sec) The table character set and collation are used as the default values for column definitions if the column character set and collation are not specified in individual column definitions.Column character set and collation See the following table for the character set and collation syntax for columns:col_name {CHAR | VARCHAR | TEXT} (col_length) [CHARACTER SET charset_name] [COLLATE collation_name] col_name {ENUM | SET} (val_list) [CHARACTER SET charset_name] [COLLATE collation_name] Connection character sets and collations The server character set and collation are the values of the character_set_server and collation_server system variables. The character set and collation of the default database are the values of the character_set_database and collation_database system variables. You can use character_set_connection and collation_connection to specify the character set and collation for each connection. The character_set_client variable is to set the client character set. Before returning the result, the character_set_results system variable indicates the character set in which the server returns query results to the client, including the metadata of the result. You can use the following statement to specify a particular collation that is related to the client: SET NAMES 'charset_name' [COLLATE 'collation_name']SET NAMES indicates what character set the client will use to send SQL statements to the server. SET NAMES utf8 indicates that all the requests from the client use utf8, as well as the results from the server.The SET NAMES 'charset_name' statement is equivalent to the following statement combination:SET character_set_client = charset_name; SET character_set_results = charset_name; SET character_set_connection = charset_name; COLLATE is optional, if absent, the default collation of the charset_name is used. SET CHARACTER SET 'charset_name'Similar to SET NAMES, the SET NAMES 'charset_name' statement is equivalent to the following statement combination:SET character_set_client = charset_name; SET character_set_results = charset_name; SET collation_connection = @@collation_database; For more information, see Connection Character Sets and Collations in MySQL."}, {"url": "https://pingcap.com/docs/v1.0/sql/character-set-support/", "title": "Character Set Support", "content": " Character Set Support A character set is a set of symbols and encodings. A collation is a set of rules for comparing characters in a character set.Currently, TiDB supports the following character sets:mysql> SHOW CHARACTER SET; +---------|---------------|-------------------|--------+ | Charset | Description | Default collation | Maxlen | +---------|---------------|-------------------|--------+ | utf8 | UTF-8 Unicode | utf8_bin | 3 | | utf8mb4 | UTF-8 Unicode | utf8mb4_bin | 4 | | ascii | US ASCII | ascii_bin | 1 | | latin1 | Latin1 | latin1_bin | 1 | | binary | binary | binary | 1 | +---------|---------------|-------------------|--------+ 5 rows in set (0.00 sec) Note: In TiDB, utf8 is treated as utf8mb4. Each character set has at least one collation. Most of the character sets have several collations. You can use the following statement to display the available character sets:mysql> SHOW COLLATION WHERE Charset = 'latin1'; +-------------------|---------|------|---------|----------|---------+ | Collation | Charset | Id | Default | Compiled | Sortlen | +-------------------|---------|------|---------|----------|---------+ | latin1_german1_ci | latin1 | 5 | | Yes | 1 | | latin1_swedish_ci | latin1 | 8 | Yes | Yes | 1 | | latin1_danish_ci | latin1 | 15 | | Yes | 1 | | latin1_german2_ci | latin1 | 31 | | Yes | 1 | | latin1_bin | latin1 | 47 | | Yes | 1 | | latin1_general_ci | latin1 | 48 | | Yes | 1 | | latin1_general_cs | latin1 | 49 | | Yes | 1 | | latin1_spanish_ci | latin1 | 94 | | Yes | 1 | +-------------------|---------|------|---------|----------|---------+ 8 rows in set (0.00 sec) The latin1 collations have the following meanings: Collation Meaning latin1_bin Binary according to latin1 encoding latin1_danish_ci Danish/Norwegian latin1_general_ci Multilingual (Western European) latin1_general_cs Multilingual (ISO Western European), case sensitive latin1_german1_ci German DIN-1 (dictionary order) latin1_german2_ci German DIN-2 (phone book order) latin1_spanish_ci Modern Spanish latin1_swedish_ci Swedish/Finnish Each character set has a default collation. For example, the default collation for utf8 is utf8_bin. Note: The collations in TiDB are case sensitive. Collation naming conventions The collation names in TiDB follow these conventions: The prefix of a collation is its corresponding character set, generally followed by one or more suffixes indicating other collation characteristic. For example, utf8_general_ci and latin1_swedish_ci are collations for the utf8 and latin1 character sets, respectively. The binary character set has a single collation, also named binary, with no suffixes. A language-specific collation includes a language name. For example, utf8_turkish_ci and utf8_hungarian_ci sort characters for the utf8 character set using the rules of Turkish and Hungarian, respectively. Collation suffixes indicate whether a collation is case and accent sensitive, or binary. The following table shows the suffixes used to indicate these characteristics. Suffix Meaning _ai Accent insensitive _as Accent insensitive _ci Case insensitive _cs Case sensitive _bin Binary Note: For now, TiDB supports on some of the collations in the above table. Database character set and collation Each database has a character set and a collation. You can use the CREATE DATABASE statement to specify the database character set and collation:CREATE DATABASE db_name [[DEFAULT] CHARACTER SET charset_name] [[DEFAULT] COLLATE collation_name] Where DATABASE can be replaced with SCHEMA.Different databases can use different character sets and collations. Use the character_set_database and collation_database to see the character set and collation of the current database:mysql> create schema test1 character set utf8 COLLATE uft8_general_ci; Query OK, 0 rows affected (0.09 sec) mysql> use test1; Database changed mysql> SELECT @@character_set_database, @@collation_database; +--------------------------|----------------------+ | @@character_set_database | @@collation_database | +--------------------------|----------------------+ | utf8 | uft8_general_ci | +--------------------------|----------------------+ 1 row in set (0.00 sec) mysql> create schema test2 character set latin1 COLLATE latin1_general_ci; Query OK, 0 rows affected (0.09 sec) mysql> use test2; Database changed mysql> SELECT @@character_set_database, @@collation_database; +--------------------------|----------------------+ | @@character_set_database | @@collation_database | +--------------------------|----------------------+ | latin1 | latin1_general_ci | +--------------------------|----------------------+ 1 row in set (0.00 sec) You can also see the two values in INFORMATION_SCHEMA:SELECT DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = 'db_name'; Table character set and collation You can use the following statement to specify the character set and collation for tables:CREATE TABLE tbl_name (column_list) [[DEFAULT] CHARACTER SET charset_name] [COLLATE collation_name]] ALTER TABLE tbl_name [[DEFAULT] CHARACTER SET charset_name] [COLLATE collation_name] For example:mysql> CREATE TABLE t1(a int) CHARACTER SET utf8 COLLATE utf8_general_ci; Query OK, 0 rows affected (0.08 sec) The table character set and collation are used as the default values for column definitions if the column character set and collation are not specified in individual column definitions.Column character set and collation See the following table for the character set and collation syntax for columns:col_name {CHAR | VARCHAR | TEXT} (col_length) [CHARACTER SET charset_name] [COLLATE collation_name] col_name {ENUM | SET} (val_list) [CHARACTER SET charset_name] [COLLATE collation_name] Connection character sets and collations The server character set and collation are the values of the character_set_server and collation_server system variables. The character set and collation of the default database are the values of the character_set_database and collation_database system variables. You can use character_set_connection and collation_connection to specify the character set and collation for each connection. The character_set_client variable is to set the client character set. Before returning the result, the character_set_results system variable indicates the character set in which the server returns query results to the client, including the metadata of the result. You can use the following statement to specify a particular collation that is related to the client: SET NAMES 'charset_name' [COLLATE 'collation_name']SET NAMES indicates what character set the client will use to send SQL statements to the server. SET NAMES utf8 indicates that all the requests from the client use utf8, as well as the results from the server.The SET NAMES 'charset_name' statement is equivalent to the following statement combination:SET character_set_client = charset_name; SET character_set_results = charset_name; SET character_set_connection = charset_name; COLLATE is optional, if absent, the default collation of the charset_name is used. SET CHARACTER SET 'charset_name'Similar to SET NAMES, the SET NAMES 'charset_name' statement is equivalent to the following statement combination:SET character_set_client = charset_name; SET character_set_results = charset_name; SET collation_connection = @@collation_database; For more information, see Connection Character Sets and Collations in MySQL."}, {"url": "https://pingcap.com/docs/v2.0/sql/character-set-support/", "title": "Character Set Support", "content": " Character Set Support A character set is a set of symbols and encodings. A collation is a set of rules for comparing characters in a character set.Currently, TiDB supports the following character sets:mysql> SHOW CHARACTER SET; +---------|---------------|-------------------|--------+ | Charset | Description | Default collation | Maxlen | +---------|---------------|-------------------|--------+ | utf8 | UTF-8 Unicode | utf8_bin | 3 | | utf8mb4 | UTF-8 Unicode | utf8mb4_bin | 4 | | ascii | US ASCII | ascii_bin | 1 | | latin1 | Latin1 | latin1_bin | 1 | | binary | binary | binary | 1 | +---------|---------------|-------------------|--------+ 5 rows in set (0.00 sec) Note: In TiDB, utf8 is treated as utf8mb4. Each character set has at least one collation. Most of the character sets have several collations. You can use the following statement to display the available character sets:mysql> SHOW COLLATION WHERE Charset = 'latin1'; +-------------------|---------|------|---------|----------|---------+ | Collation | Charset | Id | Default | Compiled | Sortlen | +-------------------|---------|------|---------|----------|---------+ | latin1_german1_ci | latin1 | 5 | | Yes | 1 | | latin1_swedish_ci | latin1 | 8 | Yes | Yes | 1 | | latin1_danish_ci | latin1 | 15 | | Yes | 1 | | latin1_german2_ci | latin1 | 31 | | Yes | 1 | | latin1_bin | latin1 | 47 | | Yes | 1 | | latin1_general_ci | latin1 | 48 | | Yes | 1 | | latin1_general_cs | latin1 | 49 | | Yes | 1 | | latin1_spanish_ci | latin1 | 94 | | Yes | 1 | +-------------------|---------|------|---------|----------|---------+ 8 rows in set (0.00 sec) The latin1 collations have the following meanings: Collation Meaning latin1_bin Binary according to latin1 encoding latin1_danish_ci Danish/Norwegian latin1_general_ci Multilingual (Western European) latin1_general_cs Multilingual (ISO Western European), case sensitive latin1_german1_ci German DIN-1 (dictionary order) latin1_german2_ci German DIN-2 (phone book order) latin1_spanish_ci Modern Spanish latin1_swedish_ci Swedish/Finnish Each character set has a default collation. For example, the default collation for utf8 is utf8_bin. Note: The collations in TiDB are case sensitive. Collation naming conventions The collation names in TiDB follow these conventions: The prefix of a collation is its corresponding character set, generally followed by one or more suffixes indicating other collation characteristic. For example, utf8_general_ci and latin1_swedish_ci are collations for the utf8 and latin1 character sets, respectively. The binary character set has a single collation, also named binary, with no suffixes. A language-specific collation includes a language name. For example, utf8_turkish_ci and utf8_hungarian_ci sort characters for the utf8 character set using the rules of Turkish and Hungarian, respectively. Collation suffixes indicate whether a collation is case and accent sensitive, or binary. The following table shows the suffixes used to indicate these characteristics. Suffix Meaning _ai Accent insensitive _as Accent insensitive _ci Case insensitive _cs Case sensitive _bin Binary Note: For now, TiDB supports on some of the collations in the above table. Database character set and collation Each database has a character set and a collation. You can use the CREATE DATABASE statement to specify the database character set and collation:CREATE DATABASE db_name [[DEFAULT] CHARACTER SET charset_name] [[DEFAULT] COLLATE collation_name] Where DATABASE can be replaced with SCHEMA.Different databases can use different character sets and collations. Use the character_set_database and collation_database to see the character set and collation of the current database:mysql> create schema test1 character set utf8 COLLATE uft8_general_ci; Query OK, 0 rows affected (0.09 sec) mysql> use test1; Database changed mysql> SELECT @@character_set_database, @@collation_database; +--------------------------|----------------------+ | @@character_set_database | @@collation_database | +--------------------------|----------------------+ | utf8 | uft8_general_ci | +--------------------------|----------------------+ 1 row in set (0.00 sec) mysql> create schema test2 character set latin1 COLLATE latin1_general_ci; Query OK, 0 rows affected (0.09 sec) mysql> use test2; Database changed mysql> SELECT @@character_set_database, @@collation_database; +--------------------------|----------------------+ | @@character_set_database | @@collation_database | +--------------------------|----------------------+ | latin1 | latin1_general_ci | +--------------------------|----------------------+ 1 row in set (0.00 sec) You can also see the two values in INFORMATION_SCHEMA:SELECT DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = 'db_name'; Table character set and collation You can use the following statement to specify the character set and collation for tables:CREATE TABLE tbl_name (column_list) [[DEFAULT] CHARACTER SET charset_name] [COLLATE collation_name]] ALTER TABLE tbl_name [[DEFAULT] CHARACTER SET charset_name] [COLLATE collation_name] For example:mysql> CREATE TABLE t1(a int) CHARACTER SET utf8 COLLATE utf8_general_ci; Query OK, 0 rows affected (0.08 sec) The table character set and collation are used as the default values for column definitions if the column character set and collation are not specified in individual column definitions.Column character set and collation See the following table for the character set and collation syntax for columns:col_name {CHAR | VARCHAR | TEXT} (col_length) [CHARACTER SET charset_name] [COLLATE collation_name] col_name {ENUM | SET} (val_list) [CHARACTER SET charset_name] [COLLATE collation_name] Connection character sets and collations The server character set and collation are the values of the character_set_server and collation_server system variables. The character set and collation of the default database are the values of the character_set_database and collation_database system variables. You can use character_set_connection and collation_connection to specify the character set and collation for each connection. The character_set_client variable is to set the client character set. Before returning the result, the character_set_results system variable indicates the character set in which the server returns query results to the client, including the metadata of the result. You can use the following statement to specify a particular collation that is related to the client: SET NAMES 'charset_name' [COLLATE 'collation_name']SET NAMES indicates what character set the client will use to send SQL statements to the server. SET NAMES utf8 indicates that all the requests from the client use utf8, as well as the results from the server.The SET NAMES 'charset_name' statement is equivalent to the following statement combination:SET character_set_client = charset_name; SET character_set_results = charset_name; SET character_set_connection = charset_name; COLLATE is optional, if absent, the default collation of the charset_name is used. SET CHARACTER SET 'charset_name'Similar to SET NAMES, the SET NAMES 'charset_name' statement is equivalent to the following statement combination:SET character_set_client = charset_name; SET character_set_results = charset_name; SET collation_connection = @@collation_database; For more information, see Connection Character Sets and Collations in MySQL."}, {"url": "https://pingcap.com/docs/op-guide/location-awareness/", "title": "Cluster Topology Configuration", "content": " Cluster Topology Configuration Overview PD schedules according to the topology of the TiKV cluster to maximize the TiKV’s capability for disaster recovery.Before you begin, see Deploy TiDB Using Ansible (Recommended) and Deploy TiDB Using Docker.TiKV reports the topological information TiKV reports the topological information to PD according to the startup parameter or configuration of TiKV.Assuming that the topology has three structures: zone > rack > host, use lables to specify the following information:Startup parameter:tikv-server --labels zone=<zone>,rack=<rack>,host=<host> Configuration:[server] labels = "zone=<zone>,rack=<rack>,host=<host>" PD understands the TiKV topology PD gets the topology of TiKV cluster through the PD configuration.[replication] max-replicas = 3 location-labels = ["zone", "rack", "host"] location-labels needs to correspond to the TiKV labels name so that PD can understand that the labels represents the TiKV topology.PD schedules based on the TiKV topology PD makes optimal scheduling according to the topological information. You just need to care about what kind of topology can achieve the desired effect.If you use 3 replicas and hope that the TiDB cluster is always highly available even when a data zone goes down, you need at least 4 data zones.Assume that you have 4 data zones, each zone has 2 racks, and each rack has 2 hosts. You can start 2 TiKV instances on each host:# zone=z1 tikv-server --labels zone=z1,rack=r1,host=h1 tikv-server --labels zone=z1,rack=r1,host=h2 tikv-server --labels zone=z1,rack=r2,host=h1 tikv-server --labels zone=z1,rack=r2,host=h2 # zone=z2 tikv-server --labels zone=z2,rack=r1,host=h1 tikv-server --labels zone=z2,rack=r1,host=h2 tikv-server --labels zone=z2,rack=r2,host=h1 tikv-server --labels zone=z2,rack=r2,host=h2 # zone=z3 tikv-server --labels zone=z3,rack=r1,host=h1 tikv-server --labels zone=z3,rack=r1,host=h2 tikv-server --labels zone=z3,rack=r2,host=h1 tikv-server --labels zone=z3,rack=r2,host=h2 # zone=z4 tikv-server --labels zone=z4,rack=r1,host=h1 tikv-server --labels zone=z4,rack=r1,host=h2 tikv-server --labels zone=z4,rack=r2,host=h1 tikv-server --labels zone=z4,rack=r2,host=h2 In other words, 16 TiKV instances are distributed across 4 data zones, 8 racks and 16 machines.In this case, PD will schedule different replicas of each datum to different data zones. If one of the data zones goes down, the high availability of the TiDB cluster is not affected. If the data zone cannot recover within a period of time, PD will remove the replica from this data zone. To sum up, PD maximizes the disaster recovery of the cluster according to the current topology. Therefore, if you want to reach a certain level of disaster recovery, deploy many machines in different sites according to the topology. The number of machines must be more than the number of max-replicas."}, {"url": "https://pingcap.com/docs/sql/comment-syntax/", "title": "Comment Syntax", "content": " Comment Syntax TiDB supports three comment styles: Use # to comment a line. Use -- to comment a line, and this style requires at least one whitespace after --. Use /* */ to comment a block or multiple lines. Example:mysql> SELECT 1+1; # This comment continues to the end of line +------+ | 1+1 | +------+ | 2 | +------+ 1 row in set (0.00 sec) mysql> SELECT 1+1; -- This comment continues to the end of line +------+ | 1+1 | +------+ | 2 | +------+ 1 row in set (0.00 sec) mysql> SELECT 1 /* this is an in-line comment */ + 1; +--------+ | 1 + 1 | +--------+ | 2 | +--------+ 1 row in set (0.01 sec) mysql> SELECT 1+ -> /* /*> this is a /*> multiple-line comment /*> */ -> 1; +-------+ | 1+ 1 | +-------+ | 2 | +-------+ 1 row in set (0.00 sec) mysql> SELECT 1+1--1; +--------+ | 1+1--1 | +--------+ | 3 | +--------+ 1 row in set (0.01 sec) Similar to MySQL, TiDB supports a variant of C comment style:/*! Specific code */ In this comment style, TiDB runs the statements in the comment. The syntax is used to make these SQL statements ignored in other databases and run only in TiDB.For example:SELECT /*! STRAIGHT_JOIN */ col1 FROM table1,table2 WHERE ... In TiDB, you can also use another version:SELECT STRAIGHT_JOIN col1 FROM table1,table2 WHERE ... If the server version number is specified in the comment, for example, /*!50110 KEY_BLOCK_SIZE=1024 */, in MySQL it means that the contents in this comment is processed only when the MySQL version is or higher than 5.1.10. But in TiDB, the version number does not work and all contents in the comment are processed.Another type of comment is specially treated as the Hint optimizer:SELECT /*+ hint */ FROM ...; Since Hint is involved in comments like /*+ xxx */, the MySQL client clears the comment by default in versions earlier than 5.7.7. To use Hint in those earlier versions, add the --comments option when you start the client. For example:mysql -h 127.0.0.1 -P 4000 -uroot --comments For details about the optimizer hints that TiDB supports, see Optimizer hint.For more information, see Comment Syntax."}, {"url": "https://pingcap.com/docs/v1.0/sql/comment-syntax/", "title": "Comment Syntax", "content": " Comment Syntax TiDB supports three comment styles: Use # to comment a line. Use -- to comment a line, and this style requires at least one whitespace after --. Use /* */ to comment a block or multiple lines. Example:mysql> SELECT 1+1; # This comment continues to the end of line +------+ | 1+1 | +------+ | 2 | +------+ 1 row in set (0.00 sec) mysql> SELECT 1+1; -- This comment continues to the end of line +------+ | 1+1 | +------+ | 2 | +------+ 1 row in set (0.00 sec) mysql> SELECT 1 /* this is an in-line comment */ + 1; +--------+ | 1 + 1 | +--------+ | 2 | +--------+ 1 row in set (0.01 sec) mysql> SELECT 1+ -> /* /*> this is a /*> multiple-line comment /*> */ -> 1; +-------+ | 1+ 1 | +-------+ | 2 | +-------+ 1 row in set (0.00 sec) mysql> SELECT 1+1--1; +--------+ | 1+1--1 | +--------+ | 3 | +--------+ 1 row in set (0.01 sec) Similar to MySQL, TiDB supports a variant of C comment style:/*! Specific code */ In this comment style, TiDB runs the statements in the comment. The syntax is used to make these SQL statements ignored in other databases and run only in TiDB.For example:SELECT /*! STRAIGHT_JOIN */ col1 FROM table1,table2 WHERE ... In TiDB, you can also use another version:SELECT STRAIGHT_JOIN col1 FROM table1,table2 WHERE ... If the server version number is specified in the comment, for example, /*!50110 KEY_BLOCK_SIZE=1024 */, in MySQL it means that the contents in this comment is processed only when the MySQL version is or higher than 5.1.10. But in TiDB, the version number does not work and all contents in the comment are processed.Another type of comment is specially treated as the Hint optimizer:SELECT /*+ hint */ FROM ...; Since Hint is involved in comments like /*+ xxx */, the MySQL client clears the comment by default in versions earlier than 5.7.7. To use Hint in those earlier versions, add the --comments option when you start the client. For example:mysql -h 127.0.0.1 -P 4000 -uroot --comments` Currently, TiDB supports the following specific types of Hint: TIDB_SMJ(t1, t2) SELECT /*+ TIDB_SMJ(t1, t2) */ * from t1,t2 where t1.id = t2.id The Hint optimizer uses the Sort Merge Join algorithm, which usually consumes less memory but takes longer to run. This is recommended when the amount of data is too large, or the system memory is insufficient. TIDB_INLJ(t1, t2) SELECT /*+ TIDB_INLJ(t1, t2) */ * from t1,t2 where t1.id = t2.id The Hint optimizer uses the Index Nested Loop Join algorithm. This algorithm is faster in some scenarios and consumes less system resources, while it may be slower in some other scenarios and consumes more system resources. For the scenarios that have a small result set (less than 10,000 lines) after the filtration of WHERE condition, you can try to use it. The parameter in TIDB_INLJ() is the candidate table of the driving table (outer table) when the query plan is created. In other words, TIDB_INLJ(t1) only uses t1 as the driving table to create the query plan.For more information, see Comment Syntax."}, {"url": "https://pingcap.com/docs/v2.0/sql/comment-syntax/", "title": "Comment Syntax", "content": " Comment Syntax TiDB supports three comment styles: Use # to comment a line. Use -- to comment a line, and this style requires at least one whitespace after --. Use /* */ to comment a block or multiple lines. Example:mysql> SELECT 1+1; # This comment continues to the end of line +------+ | 1+1 | +------+ | 2 | +------+ 1 row in set (0.00 sec) mysql> SELECT 1+1; -- This comment continues to the end of line +------+ | 1+1 | +------+ | 2 | +------+ 1 row in set (0.00 sec) mysql> SELECT 1 /* this is an in-line comment */ + 1; +--------+ | 1 + 1 | +--------+ | 2 | +--------+ 1 row in set (0.01 sec) mysql> SELECT 1+ -> /* /*> this is a /*> multiple-line comment /*> */ -> 1; +-------+ | 1+ 1 | +-------+ | 2 | +-------+ 1 row in set (0.00 sec) mysql> SELECT 1+1--1; +--------+ | 1+1--1 | +--------+ | 3 | +--------+ 1 row in set (0.01 sec) Similar to MySQL, TiDB supports a variant of C comment style:/*! Specific code */ In this comment style, TiDB runs the statements in the comment. The syntax is used to make these SQL statements ignored in other databases and run only in TiDB.For example:SELECT /*! STRAIGHT_JOIN */ col1 FROM table1,table2 WHERE ... In TiDB, you can also use another version:SELECT STRAIGHT_JOIN col1 FROM table1,table2 WHERE ... If the server version number is specified in the comment, for example, /*!50110 KEY_BLOCK_SIZE=1024 */, in MySQL it means that the contents in this comment is processed only when the MySQL version is or higher than 5.1.10. But in TiDB, the version number does not work and all contents in the comment are processed.Another type of comment is specially treated as the Hint optimizer:SELECT /*+ hint */ FROM ...; Since Hint is involved in comments like /*+ xxx */, the MySQL client clears the comment by default in versions earlier than 5.7.7. To use Hint in those earlier versions, add the --comments option when you start the client. For example:mysql -h 127.0.0.1 -P 4000 -uroot --comments For details about the optimizer hints that TiDB supports, see Optimizer hint.For more information, see Comment Syntax."}, {"url": "https://pingcap.com/community/", "title": "Communities", "content": ""}, {"url": "https://pingcap.com/docs/sql/mysql-compatibility/", "title": "Compatibility with MySQL", "content": " Compatibility with MySQL TiDB supports the majority of the MySQL 5.7 syntax, including cross-row transactions, JOIN, subquery, and so on. You can connect to TiDB directly using your own MySQL client. If your existing business is developed based on MySQL, you can replace MySQL with TiDB to power your application without changing a single line of code in most cases.TiDB is compatible with most of the MySQL database management & administration tools such as PHPMyAdmin, Navicat, MySQL Workbench, and so on. It also supports the database backup tools, such as mysqldump and mydumper/myloader.However, in TiDB, the following MySQL features are not supported for the time being or are different:Unsupported features Stored procedures and functions Views Triggers Events User-defined functions FOREIGN KEY constraints FULLTEXT functions and indexes SPATIAL functions and indexes Character sets other than utf8 Collations other than BINARY Add primary key Drop primary key SYS schema Optimizer trace XML Functions X-Protocol Savepoints Column-level privileges CREATE TABLE tblName AS SELECT stmt syntax CREATE TEMPORARY TABLE syntax XA syntax (TiDB uses a two-phase commit internally, but this is not exposed via an SQL interface) Features that are different from MySQL Auto-increment ID The auto-increment ID feature in TiDB is only guaranteed to be automatically incremental and unique but is not guaranteed to be allocated sequentially. Currently, TiDB is allocating IDs in batches. If data is inserted into multiple TiDB servers simultaneously, the allocated IDs are not sequential. Warning:If you use the auto-increment ID in a cluster with multiple tidb-server instances, do not mix the default value and the custom value, otherwise an error occurs in the following situation:Assume that you have a table with the auto-increment ID:create table t(id int unique key auto_increment, c int);The principle of the auto-increment ID in TiDB is that each tidb-server instance caches a section of ID values (currently 30000 IDs are cached) for allocation and fetches the next section after this section is used up.Assume that the cluster contains two tidb-server instances, namely Instance A and Instance B. Instance A caches the auto-increment ID of [1, 30000], while Instance B caches the auto-increment ID of [30001, 60000].The operations are executed as follows: The client issues the insert into t values (1, 1) statement to Instance B which sets the id to 1 and the statement is executed successfully. The client issues the insert into t (c) (1) statement to Instance A. This statement does not specify the value of id, so Instance A allocates the value. Currently, Instances A caches the auto-increment ID of [1, 30000], so it allocates the id value to 1 and adds 1 to the local counter. However, at this time the data with the id of 1 already exists in the cluster, therefore it reports Duplicated Error. Performance schema Performance schema tables return empty results in TiDB. TiDB uses a combination of Prometheus and Grafana for performance metrics instead.Built-in functions TiDB supports most of the MySQL built-in functions, but not all. See TiDB SQL Grammar for the supported functions.DDL TiDB implements the asynchronous schema changes algorithm in F1. The Data Manipulation Language (DML) operations cannot be blocked during DDL the execution. Currently, the supported DDL includes: Create Database Drop Database Create Table Drop Table Add Index: Does not support creating multiple indexes at the same time. Drop Index Add Column: Does not support creating multiple columns at the same time. Does not support setting a column as the primary key, or creating a unique index, or specifying auto_increment while adding it. Drop Column: Does not support dropping the primary key column or index column. Alter Column Change/Modify Column Supports changing/modifying the types among the following integer types: TinyInt, SmallInt, MediumInt, Int, BigInt. Supports changing/modifying the types among the following string types: Char, Varchar, Text, TinyText, MediumText, LongText Support changing/modifying the types among the following string types: Blob, TinyBlob, MediumBlob, LongBlob. Note: The changing/modifying column operation cannot make the length of the original type become shorter and it cannot change the unsigned/charset/collate attributes of the column. Supports changing the following type definitions: default value, comment, null, not null and OnUpdate, but does not support changing from null to not null. Supports parsing the LOCK [=] {DEFAULT|NONE|SHARED|EXCLUSIVE} syntax, but there is no actual operation. Truncate Table Rename Table Create Table Like Transaction model TiDB implements an optimistic transaction model. Unlike MySQL, which uses row-level locking to avoid write conflict, in TiDB, the write conflict is checked only in the commit process during the execution of the statements like Update, Insert, Delete, and so on.Similarly, functions such as GET_LOCK() and RELEASE_LOCK() and statements such as SELECT .. FOR UPDATE do not work in the same way as in MySQL.Note: On the business side, remember to check the returned results of commit because even there is no error in the execution, there might be errors in the commit process.Large transactions Due to the distributed, 2-phase commit requirement of TiDB, large transactions that modify data can be particularly problematic. TiDB intentionally sets some limits on transaction sizes to reduce this impact: Each Key-Value entry is no more than 6MB The total number of Key-Value entries is no more than 300,000 The total size of Key-Value entries is no more than 100MB Small transactions Since each transaction in TiDB requires two round trips to the PD leader, small transactions may have higher latencies in TiDB than MySQL. As a hypothetical example, the following query could be improved by moving from auto_commit to using an explicit transaction:# original version with auto_commit UPDATE my_table SET a='new_value' WHERE id = 1; UPDATE my_table SET a='newer_value' WHERE id = 2; UPDATE my_table SET a='newest_value' WHERE id = 3; # improved version START TRANSACTION; UPDATE my_table SET a='new_value' WHERE id = 1; UPDATE my_table SET a='newer_value' WHERE id = 2; UPDATE my_table SET a='newest_value' WHERE id = 3; COMMIT; Single-threaded workloads Due to its distributed nature, workloads that are single-threaded may perform worse in TiDB when compared to a single-instance deployment of MySQL. This difference is similar to the case of small transactions being potentially slower in TiDB.Load data Syntax:LOAD DATA LOCAL INFILE 'file_name' INTO TABLE table_name {FIELDS | COLUMNS} TERMINATED BY 'string' ENCLOSED BY 'char' ESCAPED BY 'char' LINES STARTING BY 'string' TERMINATED BY 'string' IGNORE n LINES (col_name ...); Currently, the supported ESCAPED BY characters are: //. TransactionWhen TiDB is in the execution of loading data, by default, a record with 20,000 rows of data is seen as a transaction for persistent storage. If a load data operation inserts more than 20,000 rows, it will be divided into multiple transactions to commit. If an error occurs in one transaction, this transaction in process will not be committed. However, transactions before that are committed successfully. In this case, a part of the load data operation is successfully inserted, and the rest of the data insertion fails. But MySQL treats a load data operation as a transaction, one error leads to the failure of the entire load data operation. Storage engines For compatibility reasons, TiDB supports the syntax to create tables with alternative storage engines. Metadata commands describe tables as being of engine InnoDB:mysql> CREATE TABLE t1 (a INT) ENGINE=MyISAM; Query OK, 0 rows affected (0.14 sec) mysql> SHOW CREATE TABLE t1G *************************** 1. row …"}, {"url": "https://pingcap.com/docs/v1.0/sql/mysql-compatibility/", "title": "Compatibility with MySQL", "content": " Compatibility with MySQL TiDB supports the majority of the MySQL grammar, including cross-row transactions, JOIN, subquery, and so on. You can connect to TiDB directly using your own MySQL client. If your existing business is developed based on MySQL, you can replace MySQL with TiDB to power your application without changing a single line of code in most cases.TiDB is compatible with most of the MySQL database management & administration tools such as PHPMyAdmin, Navicat, MySQL Workbench, and so on. It also supports the database backup tools, such as mysqldump and mydumper/myloader.However, in TiDB, the following MySQL features are not supported for the time being or are different:Unsupported features Stored Procedures View Trigger The user-defined functions The FOREIGN KEY constraints The FULLTEXT indexes The Spatial indexes The Non-UTF-8 characters The JSON data type Add primary key Drop primary key Features that are different from MySQL Auto-increment ID The auto-increment ID feature in TiDB is only guaranteed to be automatically incremental and unique but is not guaranteed to be allocated sequentially. Currently, TiDB is allocating IDs in batches. If data is inserted into multiple TiDB servers simultaneously, the allocated IDs are not sequential. Warning:If you use the auto-increment ID in a cluster with multiple TiDB servers, do not mix the default value and the custom value, because it reports an error in the following situation:In a cluster of two TiDB servers, namely TiDB A and TiDB B, TiDB A caches [1,5000] auto-increment ID, while TiDB B caches [5001,10000] auto-increment ID. Use the following statement to create a table with auto-increment ID:create table t(id int unique key auto_increment, c int); The statement is executed as follows: The client inserts a statement to TiDB B which sets the id to be 1 and the statement is executed successfully. The client inserts a record to TiDB A which sets the id set to the default value 1. In this case, it returns Duplicated Error. Built-in functions TiDB supports most of the MySQL built-in functions, but not all. See TiDB SQL Grammar for the supported functions.DDL TiDB implements the asynchronous schema changes algorithm in F1. The Data Manipulation Language (DML) operations cannot be blocked during DDL the execution. Currently, the supported DDL includes: Create Database Drop Database Create Table Drop Table Add Index: Does not support creating muliple indexs at the same time. Drop Index Add Column: Does not support creating muliple columns at the same time. Does not support setting a column as the primary key, or creating a unique index, or specifying auto_increment while adding it. Drop Column: Does not support dropping the primary key column or index column. Alter Column Change/Modify Column Supports changing/modifying the types among the following integer types: TinyInt,SmallInt,MediumInt,Int,BigInt. Supports changing/modifying the types among the following string types: Char,Varchar,Text,TinyText,MediumText,LongText Support changing/modifying the types among the following string types: Blob,TinyBlob,MediumBlob,LongBlob. Note: The change/modifying column operation cannot make the length of the original type become shorter and it cannot change the unsigned/charset/collate attributes of the column.- Supports changing the following type definitions: default value,comment,null,not null and OnUpdate, but does not support changing from null to not null. - Supports parsing the `LOCK [=] {DEFAULT|NONE|SHARED|EXCLUSIVE}` syntax, but there is no actual operation. Truncate Table Rename Table Create Table Like Transaction TiDB implements an optimistic transaction model. Unlike MySQL, which uses row-level locking to avoid write conflict, in TiDB, the write conflict is checked only in the commit process during the execution of the statements like Update, Insert, Delete, and so on.Note: On the business side, remember to check the returned results of commit because even there is no error in the execution, there might be errors in the commit process.Load data Syntax:LOAD DATA LOCAL INFILE 'file_name' INTO TABLE table_name {FIELDS | COLUMNS} TERMINATED BY 'string' ENCLOSED BY 'char' ESCAPED BY 'char' LINES STARTING BY 'string' TERMINATED BY 'string' (col_name ...); Currently, the supported ESCAPED BY characters are: //. TransactionWhen TiDB is in the execution of loading data, by default, a record with 20,000 rows of data is seen as a transaction for persistent storage. If a load data operation inserts more than 20,000 rows, it will be divided into multiple transactions to commit. If an error occurs in one transaction, this transaction in process will not be committed. However, transactions before that are committed successfully. In this case, a part of the load data operation is successfully inserted, and the rest of the data insertion fails. But MySQL treats a load data operation as a transaction, one error leads to the failure of the entire load data operation. "}, {"url": "https://pingcap.com/docs/v2.0/sql/mysql-compatibility/", "title": "Compatibility with MySQL", "content": " Compatibility with MySQL TiDB supports the majority of the MySQL 5.7 syntax, including cross-row transactions, JOIN, subquery, and so on. You can connect to TiDB directly using your own MySQL client. If your existing business is developed based on MySQL, you can replace MySQL with TiDB to power your application without changing a single line of code in most cases.TiDB is compatible with most of the MySQL database management & administration tools such as PHPMyAdmin, Navicat, MySQL Workbench, and so on. It also supports the database backup tools, such as mysqldump and mydumper/myloader.However, in TiDB, the following MySQL features are not supported for the time being or are different:Unsupported features Stored Procedures View Trigger The user-defined functions The FOREIGN KEY constraints The FULLTEXT indexes The Spatial indexes The Non-UTF-8 characters Add primary key Drop primary key Features that are different from MySQL Auto-increment ID The auto-increment ID feature in TiDB is only guaranteed to be automatically incremental and unique but is not guaranteed to be allocated sequentially. Currently, TiDB is allocating IDs in batches. If data is inserted into multiple TiDB servers simultaneously, the allocated IDs are not sequential. Warning:If you use the auto-increment ID in a cluster with multiple tidb-server instances, do not mix the default value and the custom value, otherwise an error occurs in the following situation:Assume that you have a table with the auto-increment ID:create table t(id int unique key auto_increment, c int); The principle of the auto-increment ID in TiDB is that each tidb-server instance caches a section of ID values (currently 30000 IDs are cached) for allocation and fetches the next section after this section is used up.Assume that the cluster contains two tidb-server instances, namely Instance A and Instance B. Instance A caches the auto-increment ID of [1, 30000], while Instance B caches the auto-increment ID of [30001, 60000].The operations are executed as follows: The client issues the insert into t values (1, 1) statement to Instance B which sets the id to 1 and the statement is executed successfully. The client issues the insert into t (c) (1) statement to Instance A. This statement does not specify the value of id, so Instance A allocates the value. Currently, Instances A caches the auto-increment ID of [1, 30000], so it allocates the id value to 1 and adds 1 to the local counter. However, at this time the data with the id of 1 already exists in the cluster, therefore it reports Duplicated Error. Built-in functions TiDB supports most of the MySQL built-in functions, but not all. See TiDB SQL Grammar for the supported functions.DDL TiDB implements the asynchronous schema changes algorithm in F1. The Data Manipulation Language (DML) operations cannot be blocked during DDL the execution. Currently, the supported DDL includes: Create Database Drop Database Create Table Drop Table Add Index: Does not support creating multiple indexes at the same time. Drop Index Add Column: Does not support creating multiple columns at the same time. Does not support setting a column as the primary key, or creating a unique index, or specifying auto_increment while adding it. Drop Column: Does not support dropping the primary key column or index column. Alter Column Change/Modify Column Supports changing/modifying the types among the following integer types: TinyInt, SmallInt, MediumInt, Int, BigInt. Supports changing/modifying the types among the following string types: Char, Varchar, Text, TinyText, MediumText, LongText Support changing/modifying the types among the following string types: Blob, TinyBlob, MediumBlob, LongBlob. Note: The changing/modifying column operation cannot make the length of the original type become shorter and it cannot change the unsigned/charset/collate attributes of the column. Supports changing the following type definitions: default value, comment, null, not null and OnUpdate, but does not support changing from null to not null. Supports parsing the LOCK [=] {DEFAULT|NONE|SHARED|EXCLUSIVE} syntax, but there is no actual operation. Truncate Table Rename Table Create Table Like Transaction TiDB implements an optimistic transaction model. Unlike MySQL, which uses row-level locking to avoid write conflict, in TiDB, the write conflict is checked only in the commit process during the execution of the statements like Update, Insert, Delete, and so on.Note: On the business side, remember to check the returned results of commit because even there is no error in the execution, there might be errors in the commit process.Load data Syntax:LOAD DATA LOCAL INFILE 'file_name' INTO TABLE table_name {FIELDS | COLUMNS} TERMINATED BY 'string' ENCLOSED BY 'char' ESCAPED BY 'char' LINES STARTING BY 'string' TERMINATED BY 'string' (col_name ...); Currently, the supported ESCAPED BY characters are: //. TransactionWhen TiDB is in the execution of loading data, by default, a record with 20,000 rows of data is seen as a transaction for persistent storage. If a load data operation inserts more than 20,000 rows, it will be divided into multiple transactions to commit. If an error occurs in one transaction, this transaction in process will not be committed. However, transactions before that are committed successfully. In this case, a part of the load data operation is successfully inserted, and the rest of the data insertion fails. But MySQL treats a load data operation as a transaction, one error leads to the failure of the entire load data operation. Default differences Default character set: latin1 in MySQL 5.7 (UTF-8 in MySQL 8.0), while utf8mb4 in TiDB. Default collation: latin1_swedish_ci in MySQL 5.7, while binary in TiDB. Default value of lower_case_table_names: The default value in TiDB is 2 and currently TiDB only supports 2. The default value in MySQL: On Linux: 0 On Windows: 1 On macOS: 2 "}, {"url": "https://pingcap.com/docs/op-guide/configuration/", "title": "Configuration Flags", "content": " Configuration Flags TiDB, TiKV and PD are configurable using command-line flags and environment variables.TiDB The default TiDB ports are 4000 for client requests and 10080 for status report.--advertise-address The IP address on which to advertise the apiserver to the TiDB server Default: “” This address must be reachable by the rest of the TiDB cluster and the user. --binlog-socket The TiDB services use the unix socket file for internal connections, such as the Pump service Default: “” You can use “/tmp/pump.sock” to accept the communication of Pump unix socket file. --config The configuration file Default: “” If you have specified the configuration file, TiDB reads the configuration file. If the corresponding configuration also exists in the command line flags, TiDB uses the configuration in the command line flags to overwrite that in the configuration file. For detailed configuration information, see TiDB Configuration File Description --host The host address that the TiDB server monitors Default: “0.0.0.0” The TiDB server monitors this address. The “0.0.0.0” monitors all network cards by default. If you have multiple network cards, specify the network card that provides service, such as 192.168.100.113. -L The log level Default: “info” You can choose from “debug”, “info”, “warn”, “error”, or “fatal”. --log-file The log file Default: “” If this flag is not set, logs are output to “stderr”. If this flag is set, logs are output to the corresponding file, which is automatically rotated in the early morning every day, and the previous file is renamed as a backup. --log-slow-query The directory for the slow query log Default: “” If this flag is not set, logs are written to the file specified by --log-file by default. --metrics-addr The Prometheus Pushgateway address Default: “” Leaving it empty stops the Prometheus client from pushing. The format is:--metrics-addr=192.168.100.115:9091 --metrics-interval The Prometheus client push interval in seconds Default: 15s Setting the value to 0 stops the Prometheus client from pushing. -P The monitoring port of TiDB services Default: “4000” The TiDB server accepts MySQL client requests from this port. --path The path to the data directory for local storage engine like “mocktikv” For --store = tikv, you must specify the path; for --store = mocktikv, the default value is used if you do not specify the path. For the distributed storage engine like TiKV, --path specifies the actual PD address. Assuming that you deploy the PD server on 192.168.100.113:2379, 192.168.100.114:2379 and 192.168.100.115:2379, the value of --path is “192.168.100.113:2379, 192.168.100.114:2379, 192.168.100.115:2379”. Default: “/tmp/tidb” You can use tidb-server --store=mocktikv --path="" to enable a pure in-memory TiDB. --proxy-protocol-networks The list of proxy server’s IP addresses allowed by PROXY Protocol; if you need to configure multiple addresses, separate them using “,”. Default: “” Leaving it empty disables PROXY Protocol. The value can be the IP address (192.168.1.50) or CIDR (192.168.1.0/24). “*” means any IP addresses. --proxy-protocol-header-timeout Timeout for the PROXY protocol header read Default: 5 (seconds) Generally use the default value and do not set its value to 0. The unit is second. --report-status To enable(true) or disable(false) the status report and pprof tool Default: true The value can be (true) or (false). (true) is to enable metrics and pprof. (false) is to disable metrics and pprof. --run-ddl To see whether the tidb-server runs DDL statements, and set when the number of tidb-server is over two in the cluster Default: true The value can be (true) or (false). (true) indicates the tidb-server runs DDL itself. (false) indicates the tidb-server does not run DDL itself. --socket string The TiDB services use the unix socket file for external connections. Default: “” You can use “/tmp/tidb.sock” to open the unix socket file. --status The status report port for TiDB server Default: “10080” This is used to get server internal data. The data includes Prometheus metrics and pprof. Prometheus metrics can be got through “http://host:status_port/metrics". Pprof data can be got through “http://host:status_port/debug/pprof". --store To specify the storage engine used by TiDB in the bottom layer Default: “mocktikv” You can choose “mocktikv” or “tikv”. (“mocktikv” is the local storage engine; “tikv” is a distributed storage engine) --token-limit The number of sessions allowed to run concurrently in TiDB. It is used for traffic control. Default: 1000 If the number of the concurrent sessions is larger than token-limit, the request is blocked and waiting for the operations which have been finished to release tokens. -V Output the version of TiDB Default: “” Placement Driver (PD) --advertise-client-urls The advertise URL list for client traffic from outside Default: ${client-urls} If the client cannot connect to PD through the default listening client URLs, you must manually set the advertise client URLs explicitly. For example, the internal IP address of Docker is 172.17.0.1, while the IP address of the host is 192.168.100.113 and the port mapping is set to -p 2379:2379. In this case, you can set --advertise-client-urls to “http://192.168.100.113:2379". The client can find this service through “http://192.168.100.113:2379". --advertise-peer-urls The advertise URL list for peer traffic from outside Default: ${peer-urls} If the peer cannot connect to PD through the default listening peer URLs, you must manually set the advertise peer URLs explicitly. For example, the internal IP address of Docker is 172.17.0.1, while the IP address of the host is 192.168.100.113 and the port mapping is set to -p 2380:2380. In this case, you can set --advertise-peer-urls to “http://192.168.100.113:2380". The other PD nodes can find this service through “http://192.168.100.113:2380". --client-urls The listening URL list for client traffic Default: “http://127.0.0.1:2379" To deploy a cluster, you must use --client-urls to specify the IP address of the current host, such as “http://192.168.100.113:2379". If the cluster runs on Docker, specify the IP address of Docker as “http://0.0.0.0:2379". --peer-urls The listening URL list for peer traffic Default: “http://127.0.0.1:2380" To deploy a cluster, you must use --peer-urls to specify the IP address of the current host, such as “http://192.168.100.113:2380". If the cluster runs on Docker, specify the IP address of Docker as “http://0.0.0.0:2380". --config The configuration file Default: “” If you set the configuration using the command line, the same setting in the configuration file will be overwritten. --data-dir The path to the data directory Default: “default.${name}” --initial-cluster The initial cluster configuration for bootstrapping Default: “{name}=http://{advertise-peer-url}” For example, if name is “pd”, and advertise-peer-urls is “http://192.168.100.113:2380", the initial-cluster is “pd=http://192.168.100.113:2380". If you need to start three PD servers, the initial-cluster might be:pd1=http://192.168.100.113:2380, pd2=http://192.168.100.114:2380, pd3=192.168.100.115:2380 --join Join the cluster dynamically Default: “” If you want to join an existing cluster, you can use --join="${advertise-client-urls}", the advertise-client-url is any …"}, {"url": "https://pingcap.com/docs/v1.0/op-guide/configuration/", "title": "Configuration Flags", "content": " Configuration Flags TiDB, TiKV and PD are configurable using command-line flags and environment variables.TiDB The default TiDB ports are 4000 for client requests and 10080 for status report.--binlog-socket The TiDB services use the unix socket file for internal connections, such as the PUMP service Default: `` You can use “/tmp/pump.sock” to accept the communication of PUMP unix socket file. --cross-join To enable (true) or disable (false) the cross join without any equal conditions Default: true The value can be true or false. By default, true is to enable join without any equal conditions (the Where field). If you set the value to false, the server refuses to run the join statement. --host The host address that the TiDB server monitors Default: “0.0.0.0” The TiDB server monitors this address. The “0.0.0.0” monitors all network cards. If you have multiple network cards, specify the network card that provides service, such as 192.168.100.113. --join-concurrency int The number of goroutine when join-concurrency executes join concurrently Default: 5 The number depends on the amount of data and data distribution, usually the larger the better, and a larger number means a larger CPU overhead. -L The log level Default: “info” You can choose from debug, info, warn, error, or fatal. --lease The schema lease time in seconds Default: “10” This is the schema lease time that is used in online schema changes. The value will affect the DDL statement running time. Do not change it unless you understand the internal mechanism. --log-file The log file Default: “” If this flag is not set, logs will be written to stderr. Otherwise, logs will be stored in the log file which will be automatically rotated every day. --metrics-addr The Prometheus pushgateway address Default: “” Leaving it empty stops the Prometheus client from pushing. The format is:--metrics-addr=192.168.100.115:9091 --metrics-interval The Prometheus client push interval in seconds Default: 0 Setting the value to 0 stops the Prometheus client from pushing. -P The monitoring port of TiDB services Default: “4000” The TiDB server accepts MySQL client requests from this port. --path The path to the data directory for local storage engines like “goleveldb” and “BoltDB” Do not set --path for the “memory” storage engine. For the distributed storage engine like TiKV, --path specifies the actual PD address. Assuming that you deploy the PD server on 192.168.100.113:2379, 192.168.100.114:2379 and 192.168.100.115:2379, the value of --path is “192.168.100.113:2379, 192.168.100.114:2379, 192.168.100.115:2379”. Default: “/tmp/tidb” --perfschema To enable(true) or disable(false) the performance schema Default: false The value can be (true) or (false). (true) is to enable and (false) is to disable. The Performance Schema provides a way to inspect internal execution of the server at runtime. See performance schema for more information. If you enable the performance schema, the performance is affected. --privilege To enable(true) or disable(false) the privilege check(for debugging) Default: true The value can be (true) or (false). (true) is to enable and (false) is to disable. This option is deprecated and will be removed. --proxy-protocol-networks The list of proxy server’s IP addresses allowed by PROXY Protocol; if you need to configure multiple addresses, separate them using , Default: “” (empty string) Leaving it empty disables PROXY Protocol. The value can be the IP address (192.168.1.50) or CIDR (192.168.1.0/24). * means any IP addresses. --proxy-protocol-header-timeout Timeout for the PROXY protocol header read Default: 5 (seconds) Generally use the default value and do not set its value to 0. The unit is second. --query-log-max-len int The maximum length of SQL statements recorded in the log Default: 2048 Overlong requests are truncated when output to the log. --report-status To enable(true) or disable(false) the status report and pprof tool Default: true The value can be (true) or (false). (true) is to enable metrics and pprof. (false) is to disable metrics and pprof. --retry-limit int The maximum number of retries when a transaction meets conflicts Default: 10 A large number of retries affects the TiDB cluster performance. --run-ddl To see whether the tidb-server runs DDL statements, and set when the number of tidb-server is over two in the cluster Default: true The value can be (true) or (false). (true) indicates the tidb-server runs DDL itself. (false) indicates the tidb-server does not run DDL itself. --skip-grant-table To enable anyone to connect without a password and with all privileges Default: false The value can be (true) or (false). This option is usually used to reset password, and enabling it requires the root privileges. --slow-threshold int The SQL statements with a larger value of this parameter are recorded. Default: 300 The value can only be an integer (int), and the unit is millisecond. --socket string The TiDB services use the unix socket file for external connections. Default: “” You can use “/tmp/tidb.sock” to open the unix socket file. --ssl-ca The path to a file in PEM format that contains a list of trusted SSL certificate authorities. Default: “” When this option is specified along with --ssl-cert and --ssl-key, the server verifies the client’s certificate via this CA list if the client provides its certificate accordingly. The secure connection will be established without client verification if the client does not provide a certificate even when this option is set. --ssl-cert The path to an SSL certificate file in PEM format to use for establishing a secure connection. Default: “” When this option is specified along with --ssl-key, the server permits but does not require secure connections. If the specified certificate or key is not valid, the server still starts normally but does not permit secure connections. --ssl-key The path to an SSL key file in PEM format to use for establishing a secure connection, namely the private key of the certificate you specified by --ssl-cert. Default: “” Currently TiDB does not support keys protected by a passphrase. --status The status report port for TiDB server Default: “10080” This is used to get server internal data. The data includes prometheus metrics and pprof. Prometheus metrics can be got through “http://host:status_port/metrics". Pprof data can be got through “http://host:status_port/debug/pprof". --statsLease string Scan the full table incrementally, and analyze information like the data amount and index of the table Default: 3s Before you use --statsLease string, run analyze table name manually. The statistics are updated automatically and stored in TiKV, taking up some memory. --store The storage engine type Human-readable name for this member. Default: “goleveldb” You can choose from “memory”, “goleveldb”, “BoltDB” or “TiKV”. The first three are all local storage engines. TiKV is a distributed storage engine. --tcp-keep-alive keepalive is enabled in the tcp layer of TiDB. Default: false Placement Driver (PD) --advertise-client-urls The advertise URL list for client traffic from outside Default: ${client-urls} If the client cannot connect to PD through the default listening client URLs, you must manually set the advertise client URLs explicitly. For example, the internal IP address of Docker is 172.17.0.1, while the IP address of the host is 192.168.100.113 and the port mapping is set to -p 2379:2379. In this case, you can set --advertise-client-urls to “http://192.168.100.113:2379". The client can find this service through …"}, {"url": "https://pingcap.com/docs/v2.0/op-guide/configuration/", "title": "Configuration Flags", "content": " Configuration Flags TiDB, TiKV and PD are configurable using command-line flags and environment variables.TiDB The default TiDB ports are 4000 for client requests and 10080 for status report.--advertise-address The IP address on which to advertise the apiserver to the TiDB server Default: “” This address must be reachable by the rest of the TiDB cluster and the user. --binlog-socket The TiDB services use the unix socket file for internal connections, such as the Pump service Default: “” You can use “/tmp/pump.sock” to accept the communication of Pump unix socket file. --config The configuration file Default: “” If you have specified the configuration file, TiDB reads the configuration file. If the corresponding configuration also exists in the command line flags, TiDB uses the configuration in the command line flags to overwrite that in the configuration file. For detailed configuration information, see TiDB Configuration File Description --host The host address that the TiDB server monitors Default: “0.0.0.0” The TiDB server monitors this address. The “0.0.0.0” monitors all network cards by default. If you have multiple network cards, specify the network card that provides service, such as 192.168.100.113. -L The log level Default: “info” You can choose from “debug”, “info”, “warn”, “error”, or “fatal”. --log-file The log file Default: “” If this flag is not set, logs are output to “stderr”. If this flag is set, logs are output to the corresponding file, which is automatically rotated in the early morning every day, and the previous file is renamed as a backup. --log-slow-query The directory for the slow query log Default: “” If this flag is not set, logs are written to the file specified by --log-file by default. --metrics-addr The Prometheus Pushgateway address Default: “” Leaving it empty stops the Prometheus client from pushing. The format is:--metrics-addr=192.168.100.115:9091 --metrics-interval The Prometheus client push interval in seconds Default: 15s Setting the value to 0 stops the Prometheus client from pushing. -P The monitoring port of TiDB services Default: “4000” The TiDB server accepts MySQL client requests from this port. --path The path to the data directory for local storage engine like “mocktikv” For --store = tikv, you must specify the path; for --store = mocktikv, the default value is used if you do not specify the path. For the distributed storage engine like TiKV, --path specifies the actual PD address. Assuming that you deploy the PD server on 192.168.100.113:2379, 192.168.100.114:2379 and 192.168.100.115:2379, the value of --path is “192.168.100.113:2379, 192.168.100.114:2379, 192.168.100.115:2379”. Default: “/tmp/tidb” You can use tidb-server --store=mocktikv --path="" to enable a pure in-memory TiDB. --proxy-protocol-networks The list of proxy server’s IP addresses allowed by PROXY Protocol; if you need to configure multiple addresses, separate them using “,”. Default: “” Leaving it empty disables PROXY Protocol. The value can be the IP address (192.168.1.50) or CIDR (192.168.1.0/24). “*” means any IP addresses. --proxy-protocol-header-timeout Timeout for the PROXY protocol header read Default: 5 (seconds) Generally use the default value and do not set its value to 0. The unit is second. --report-status To enable(true) or disable(false) the status report and pprof tool Default: true The value can be (true) or (false). (true) is to enable metrics and pprof. (false) is to disable metrics and pprof. --run-ddl To see whether the tidb-server runs DDL statements, and set when the number of tidb-server is over two in the cluster Default: true The value can be (true) or (false). (true) indicates the tidb-server runs DDL itself. (false) indicates the tidb-server does not run DDL itself. --socket string The TiDB services use the unix socket file for external connections. Default: “” You can use “/tmp/tidb.sock” to open the unix socket file. --status The status report port for TiDB server Default: “10080” This is used to get server internal data. The data includes Prometheus metrics and pprof. Prometheus metrics can be got through “http://host:status_port/metrics". Pprof data can be got through “http://host:status_port/debug/pprof". --store To specify the storage engine used by TiDB in the bottom layer Default: “mocktikv” You can choose “mocktikv” or “tikv”. (“mocktikv” is the local storage engine; “tikv” is a distributed storage engine) --token-limit The number of sessions allowed to run concurrently in TiDB. It is used for traffic control. Default: 1000 If the number of the concurrent sessions is larger than token-limit, the request is blocked and waiting for the operations which have been finished to release tokens. -V Output the version of TiDB Default: “” Placement Driver (PD) --advertise-client-urls The advertise URL list for client traffic from outside Default: ${client-urls} If the client cannot connect to PD through the default listening client URLs, you must manually set the advertise client URLs explicitly. For example, the internal IP address of Docker is 172.17.0.1, while the IP address of the host is 192.168.100.113 and the port mapping is set to -p 2379:2379. In this case, you can set --advertise-client-urls to “http://192.168.100.113:2379". The client can find this service through “http://192.168.100.113:2379". --advertise-peer-urls The advertise URL list for peer traffic from outside Default: ${peer-urls} If the peer cannot connect to PD through the default listening peer URLs, you must manually set the advertise peer URLs explicitly. For example, the internal IP address of Docker is 172.17.0.1, while the IP address of the host is 192.168.100.113 and the port mapping is set to -p 2380:2380. In this case, you can set --advertise-peer-urls to “http://192.168.100.113:2380". The other PD nodes can find this service through “http://192.168.100.113:2380". --client-urls The listening URL list for client traffic Default: “http://127.0.0.1:2379" To deploy a cluster, you must use --client-urls to specify the IP address of the current host, such as “http://192.168.100.113:2379". If the cluster runs on Docker, specify the IP address of Docker as “http://0.0.0.0:2379". --peer-urls The listening URL list for peer traffic Default: “http://127.0.0.1:2380" To deploy a cluster, you must use --peer-urls to specify the IP address of the current host, such as “http://192.168.100.113:2380". If the cluster runs on Docker, specify the IP address of Docker as “http://0.0.0.0:2380". --config The configuration file Default: “” If you set the configuration using the command line, the same setting in the configuration file will be overwritten. --data-dir The path to the data directory Default: “default.${name}” --initial-cluster The initial cluster configuration for bootstrapping Default: “{name}=http://{advertise-peer-url}” For example, if name is “pd”, and advertise-peer-urls is “http://192.168.100.113:2380", the initial-cluster is “pd=http://192.168.100.113:2380". If you need to start three PD servers, the initial-cluster might be:pd1=http://192.168.100.113:2380, pd2=http://192.168.100.114:2380, pd3=192.168.100.115:2380 --join Join the cluster dynamically Default: “” If you want to join an existing cluster, you can use --join="${advertise-client-urls}", the advertise-client-url is any …"}, {"url": "https://pingcap.com/docs/community/", "title": "Connect with us", "content": " Connect with us Twitter: @PingCAP Reddit: https://www.reddit.com/r/TiDB/ Stack Overflow: https://stackoverflow.com/questions/tagged/tidb Mailing list: Google Group "}, {"url": "https://pingcap.com/docs/v1.0/community/", "title": "Connect with us", "content": " Connect with us Twitter: @PingCAP Reddit: https://www.reddit.com/r/TiDB/ Stack Overflow: https://stackoverflow.com/questions/tagged/tidb Mailing list: Google Group "}, {"url": "https://pingcap.com/docs/v2.0/community/", "title": "Connect with us", "content": " Connect with us Twitter: @PingCAP Reddit: https://www.reddit.com/r/TiDB/ Stack Overflow: https://stackoverflow.com/questions/tagged/tidb Mailing list: Google Group "}, {"url": "https://pingcap.com/docs/sql/connection-and-APIs/", "title": "Connectors and APIs", "content": " Connectors and APIs Database Connectors provide connectivity to the TiDB server for client programs. APIs provide low-level access to the MySQL protocol and MySQL resources. Both Connectors and the APIs enable you to connect and execute MySQL statements from another language or environment, including ODBC, Java (JDBC), Perl, Python, PHP, Ruby and C.TiDB is compatible with all Connectors and APIs of MySQL (5.6, 5.7), including: MySQL Connector/C MySQL Connector/C++ MySQL Connector/J MySQL Connector/Net MySQL Connector/ODBC MySQL Connector/Python MySQL C API MySQL PHP API MySQL Perl API MySQL Python API MySQL Ruby APIs MySQL Tcl API MySQL Eiffel Wrapper Mysql Go API Connect to TiDB using MySQL Connectors Oracle develops the following APIs and TiDB is compatible with all of them: MySQL Connector/C: a standalone replacement for the libmysqlclient, to be used for C applications MySQL Connector/C++:to enable C++ applications to connect to MySQL MySQL Connector/J:to enable Java applications to connect to MySQL using the standard JDBC API MySQL Connector/Net:to enable .Net applications to connect to MySQL; MySQL for Visual Studio uses this; support Microsoft Visual Studio 2012, 2013, 2015 and 2017 versions MySQL Connector/ODBC:the standard ODBC API; support Windows, Unix, and OS X platforms MySQL Connector/Python:to enable Python applications to connect to MySQL, compliant with the Python DB API version 2.0 Connect to TiDB using MySQL C API If you use C language programs to connect to TiDB, you can connect to libmysqlclient directly and use the MySQL C API. This is one of the major connection methods using C language, widely used by various clients and APIs, including Connector/C.Connect to TiDB using third-party MySQL APIs The third-party APIs are not developed by Oracle. The following table lists the commonly used third-party APIs: Environment API Type Notes Ada GNU Ada MySQL Bindings libmysqlclient See MySQL Bindings for GNU Ada C C API libmysqlclient See Section 27.8, “MySQL C API” C Connector/C Replacement for libmysqlclient See MySQL Connector/C Developer Guide C++ Connector/C++ libmysqlclient See MySQL Connector/C++ Developer Guide MySQL++ libmysqlclient See MySQL++ Web site MySQL wrapped libmysqlclient See MySQL wrapped Go go-sql-driver Native Driver See Mysql Go API Cocoa MySQL-Cocoa libmysqlclient Compatible with the Objective-C Cocoa environment. See http://mysql-cocoa.sourceforge.net/ D MySQL for D libmysqlclient See MySQL for D Eiffel Eiffel MySQL libmysqlclient See Section 27.14, “MySQL Eiffel Wrapper” Erlang erlang-mysql-driver libmysqlclient See erlang-mysql-driver Haskell Haskell MySQL Bindings Native Driver See Brian O’Sullivan’s pure Haskell MySQL bindings hsql-mysql libmysqlclient See MySQL driver for Haskell Java/JDBC Connector/J Native Driver See MySQL Connector/J 5.1 Developer Guide Kaya MyDB libmysqlclient See MyDB Lua LuaSQL libmysqlclient See LuaSQL .NET/Mono Connector/Net Native Driver See MySQL Connector/Net Developer Guide Objective Caml OBjective Caml MySQL Bindings libmysqlclient See MySQL Bindings for Objective Caml Octave Database bindings for GNU Octave libmysqlclient See Database bindings for GNU Octave ODBC Connector/ODBC libmysqlclient See MySQL Connector/ODBC Developer Guide Perl DBI/DBD::mysql libmysqlclient See Section 27.10, “MySQL Perl API” Net::MySQL Native Driver See Net::MySQL at CPAN PHP mysql, ext/mysqlinterface (deprecated) libmysqlclient See Original MySQL API mysqli, ext/mysqliinterface libmysqlclient See MySQL Improved Extension PDO_MYSQL libmysqlclient See MySQL Functions (PDO_MYSQL) PDO mysqlnd Native Driver Python Connector/Python Native Driver See MySQL Connector/Python Developer Guide Python Connector/Python C Extension libmysqlclient See MySQL Connector/Python Developer Guide MySQLdb libmysqlclient See Section 27.11, “MySQL Python API” Ruby MySQL/Ruby libmysqlclient Uses libmysqlclient. See Section 27.12.1, “The MySQL/Ruby API” Ruby/MySQL Native Driver See Section 27.12.2, “The Ruby/MySQL API” Scheme Myscsh libmysqlclient See Myscsh SPL sql_mysql libmysqlclient See sql_mysql for SPL Tcl MySQLtcl libmysqlclient See Section 27.13, “MySQL Tcl API” Connector versions supported by TiDB Connector Connector Version Connector/C 6.1.0 GA Connector/C++ 1.0.5 GA Connector/J 5.1.8 Connector/Net 6.9.9 GA Connector/Net 6.8.8 GA Connector/ODBC 5.1 Connector/ODBC 3.51 (Unicode not supported) Connector/Python 2.0 Connector/Python 1.2 "}, {"url": "https://pingcap.com/docs/v1.0/sql/connection-and-APIs/", "title": "Connectors and APIs", "content": " Connectors and APIs Database Connectors provide connectivity to the TiDB server for client programs. APIs provide low-level access to the MySQL protocol and MySQL resources. Both Connectors and the APIs enable you to connect and execute MySQL statements from another language or environment, including ODBC, Java (JDBC), Perl, Python, PHP, Ruby and C.TiDB is compatible with all Connectors and APIs of MySQL (5.6, 5.7), including: MySQL Connector/C MySQL Connector/C++ MySQL Connector/J MySQL Connector/Net MySQL Connector/ODBC MySQL Connector/Python MySQL C API MySQL PHP API MySQL Perl API MySQL Python API MySQL Ruby APIs MySQL Tcl API MySQL Eiffel Wrapper Mysql Go API Connect to TiDB using MySQL Connectors Oracle develops the following APIs and TiDB is compatible with all of them: MySQL Connector/C: a standalone replacement for the libmysqlclient, to be used for C applications MySQL Connector/C++:to enable C++ applications to connect to MySQL MySQL Connector/J:to enable Java applications to connect to MySQL using the standard JDBC API MySQL Connector/Net:to enable .Net applications to connect to MySQL; MySQL for Visual Studio uses this; support Microsoft Visual Studio 2012, 2013, 2015 and 2017 versions MySQL Connector/ODBC:the standard ODBC API; support Windows, Unix, and OS X platforms MySQL Connector/Python:to enable Python applications to connect to MySQL, compliant with the Python DB API version 2.0 Connect to TiDB using MySQL C API If you use C language programs to connect to TiDB, you can connect to libmysqlclient directly and use the MySQL C API. This is one of the major connection methods using C language, widely used by various clients and APIs, including Connector/C.Connect to TiDB using third-party MySQL APIs The third-party APIs are not developed by Oracle. The following table lists the commonly used third-party APIs: Environment API Type Notes Ada GNU Ada MySQL Bindings libmysqlclient See MySQL Bindings for GNU Ada C C API libmysqlclient See Section 27.8, “MySQL C API” C Connector/C Replacement for libmysqlclient See MySQL Connector/C Developer Guide C++ Connector/C++ libmysqlclient See MySQL Connector/C++ Developer Guide MySQL++ libmysqlclient See MySQL++ Web site MySQL wrapped libmysqlclient See MySQL wrapped Go go-sql-driver Native Driver See Mysql Go API Cocoa MySQL-Cocoa libmysqlclient Compatible with the Objective-C Cocoa environment. See http://mysql-cocoa.sourceforge.net/ D MySQL for D libmysqlclient See MySQL for D Eiffel Eiffel MySQL libmysqlclient See Section 27.14, “MySQL Eiffel Wrapper” Erlang erlang-mysql-driver libmysqlclient See erlang-mysql-driver Haskell Haskell MySQL Bindings Native Driver See Brian O’Sullivan’s pure Haskell MySQL bindings hsql-mysql libmysqlclient See MySQL driver for Haskell Java/JDBC Connector/J Native Driver See MySQL Connector/J 5.1 Developer Guide Kaya MyDB libmysqlclient See MyDB Lua LuaSQL libmysqlclient See LuaSQL .NET/Mono Connector/Net Native Driver See MySQL Connector/Net Developer Guide Objective Caml OBjective Caml MySQL Bindings libmysqlclient See MySQL Bindings for Objective Caml Octave Database bindings for GNU Octave libmysqlclient See Database bindings for GNU Octave ODBC Connector/ODBC libmysqlclient See MySQL Connector/ODBC Developer Guide Perl DBI/DBD::mysql libmysqlclient See Section 27.10, “MySQL Perl API” Net::MySQL Native Driver See Net::MySQL at CPAN PHP mysql, ext/mysqlinterface (deprecated) libmysqlclient See Original MySQL API mysqli, ext/mysqliinterface libmysqlclient See MySQL Improved Extension PDO_MYSQL libmysqlclient See MySQL Functions (PDO_MYSQL) PDO mysqlnd Native Driver Python Connector/Python Native Driver See MySQL Connector/Python Developer Guide Python Connector/Python C Extension libmysqlclient See MySQL Connector/Python Developer Guide MySQLdb libmysqlclient See Section 27.11, “MySQL Python API” Ruby MySQL/Ruby libmysqlclient Uses libmysqlclient. See Section 27.12.1, “The MySQL/Ruby API” Ruby/MySQL Native Driver See Section 27.12.2, “The Ruby/MySQL API” Scheme Myscsh libmysqlclient See Myscsh SPL sql_mysql libmysqlclient See sql_mysql for SPL Tcl MySQLtcl libmysqlclient See Section 27.13, “MySQL Tcl API” Connector versions supported by TiDB Connector Connector Version Connector/C 6.1.0 GA Connector/C++ 1.0.5 GA Connector/J 5.1.8 Connector/Net 6.9.9 GA Connector/Net 6.8.8 GA Connector/ODBC 5.1 Connector/ODBC 3.51 (Unicode not supported) Connector/Python 2.0 Connector/Python 1.2 "}, {"url": "https://pingcap.com/docs/v2.0/sql/connection-and-APIs/", "title": "Connectors and APIs", "content": " Connectors and APIs Database Connectors provide connectivity to the TiDB server for client programs. APIs provide low-level access to the MySQL protocol and MySQL resources. Both Connectors and the APIs enable you to connect and execute MySQL statements from another language or environment, including ODBC, Java (JDBC), Perl, Python, PHP, Ruby and C.TiDB is compatible with all Connectors and APIs of MySQL (5.6, 5.7), including: MySQL Connector/C MySQL Connector/C++ MySQL Connector/J MySQL Connector/Net MySQL Connector/ODBC MySQL Connector/Python MySQL C API MySQL PHP API MySQL Perl API MySQL Python API MySQL Ruby APIs MySQL Tcl API MySQL Eiffel Wrapper Mysql Go API Connect to TiDB using MySQL Connectors Oracle develops the following APIs and TiDB is compatible with all of them: MySQL Connector/C: a standalone replacement for the libmysqlclient, to be used for C applications MySQL Connector/C++:to enable C++ applications to connect to MySQL MySQL Connector/J:to enable Java applications to connect to MySQL using the standard JDBC API MySQL Connector/Net:to enable .Net applications to connect to MySQL; MySQL for Visual Studio uses this; support Microsoft Visual Studio 2012, 2013, 2015 and 2017 versions MySQL Connector/ODBC:the standard ODBC API; support Windows, Unix, and OS X platforms MySQL Connector/Python:to enable Python applications to connect to MySQL, compliant with the Python DB API version 2.0 Connect to TiDB using MySQL C API If you use C language programs to connect to TiDB, you can connect to libmysqlclient directly and use the MySQL C API. This is one of the major connection methods using C language, widely used by various clients and APIs, including Connector/C.Connect to TiDB using third-party MySQL APIs The third-party APIs are not developed by Oracle. The following table lists the commonly used third-party APIs: Environment API Type Notes Ada GNU Ada MySQL Bindings libmysqlclient See MySQL Bindings for GNU Ada C C API libmysqlclient See Section 27.8, “MySQL C API” C Connector/C Replacement for libmysqlclient See MySQL Connector/C Developer Guide C++ Connector/C++ libmysqlclient See MySQL Connector/C++ Developer Guide MySQL++ libmysqlclient See MySQL++ Web site MySQL wrapped libmysqlclient See MySQL wrapped Go go-sql-driver Native Driver See Mysql Go API Cocoa MySQL-Cocoa libmysqlclient Compatible with the Objective-C Cocoa environment. See http://mysql-cocoa.sourceforge.net/ D MySQL for D libmysqlclient See MySQL for D Eiffel Eiffel MySQL libmysqlclient See Section 27.14, “MySQL Eiffel Wrapper” Erlang erlang-mysql-driver libmysqlclient See erlang-mysql-driver Haskell Haskell MySQL Bindings Native Driver See Brian O’Sullivan’s pure Haskell MySQL bindings hsql-mysql libmysqlclient See MySQL driver for Haskell Java/JDBC Connector/J Native Driver See MySQL Connector/J 5.1 Developer Guide Kaya MyDB libmysqlclient See MyDB Lua LuaSQL libmysqlclient See LuaSQL .NET/Mono Connector/Net Native Driver See MySQL Connector/Net Developer Guide Objective Caml OBjective Caml MySQL Bindings libmysqlclient See MySQL Bindings for Objective Caml Octave Database bindings for GNU Octave libmysqlclient See Database bindings for GNU Octave ODBC Connector/ODBC libmysqlclient See MySQL Connector/ODBC Developer Guide Perl DBI/DBD::mysql libmysqlclient See Section 27.10, “MySQL Perl API” Net::MySQL Native Driver See Net::MySQL at CPAN PHP mysql, ext/mysqlinterface (deprecated) libmysqlclient See Original MySQL API mysqli, ext/mysqliinterface libmysqlclient See MySQL Improved Extension PDO_MYSQL libmysqlclient See MySQL Functions (PDO_MYSQL) PDO mysqlnd Native Driver Python Connector/Python Native Driver See MySQL Connector/Python Developer Guide Python Connector/Python C Extension libmysqlclient See MySQL Connector/Python Developer Guide MySQLdb libmysqlclient See Section 27.11, “MySQL Python API” Ruby MySQL/Ruby libmysqlclient Uses libmysqlclient. See Section 27.12.1, “The MySQL/Ruby API” Ruby/MySQL Native Driver See Section 27.12.2, “The Ruby/MySQL API” Scheme Myscsh libmysqlclient See Myscsh SPL sql_mysql libmysqlclient See sql_mysql for SPL Tcl MySQLtcl libmysqlclient See Section 27.13, “MySQL Tcl API” Connector versions supported by TiDB Connector Connector Version Connector/C 6.1.0 GA Connector/C++ 1.0.5 GA Connector/J 5.1.8 Connector/Net 6.9.9 GA Connector/Net 6.8.8 GA Connector/ODBC 5.1 Connector/ODBC 3.51 (Unicode not supported) Connector/Python 2.0 Connector/Python 1.2 "}, {"url": "https://pingcap.com/contact-us/", "title": "Contact Us", "content": ""}, {"url": "https://pingcap.com/recruit-cn/campus/campus-2019-content-strategist/", "title": "Content Strategist", "content": " Content Strategist Qualifications: Bachelor’s degree or above in software, computer science or engineering relevant majors with an understanding of the software industry; Excellent command of both written and oral English; Experience and passion in writing software relevant topics; Experience in marketing research is a strong plus; An excellent communicator with a clear and concise writing style; Detail-oriented with sharp eyes and good troubleshooting skills; Comfortable in a fast-paced environment and with meeting deadlines. Responsibilities: Communicate with the engineering team and write, review and update technical documents, tutorials and blogs; Building and developing brand awareness in technical communities and social media; Assist in preparing and refining the marketing collaterals. 待遇:8K - 15K,13薪 + 奖金,优秀者可面议联系方式:hire@pingcap.com工作地点:北京"}, {"url": "https://pingcap.com/recruit-cn/i18n/content-strategist/", "title": "Content Strategist", "content": " Content Strategist Qualifications: Bachelor’s degree or above in software, computer science or engineering relevant majors with an understanding of the software industry; Excellent command of both written and oral English; Experience and passion in writing software relevant topics; Experience in marketing research is a strong plus; An excellent communicator with a clear and concise writing style; Detail-oriented with sharp eyes and good troubleshooting skills; Comfortable in a fast-paced environment and with meeting deadlines. Responsibilities: Communicate with the engineering team and write, review and update technical documents, tutorials and blogs; Building and developing brand awareness in technical communities and social media; Assist in preparing and refining the marketing collaterals. 待遇:10K -30K,13薪 + 奖金,优秀者可面议联系方式:hire@pingcap.com工作地点:北京"}, {"url": "https://pingcap.com/recruit-cn/campus/content-strategist-intern/", "title": "Content Strategist Intern", "content": " Content Strategist Intern Qualifications: Bachelor’s degree or above in software, computer science or engineering relevant majors with an understanding of the software industry; Excellent command of both written and oral English; Experience and passion in writing software relevant topics; Experience in marketing research is a strong plus; An excellent communicator with a clear and concise writing style; Detail-oriented with sharp eyes and good troubleshooting skills; Comfortable in a fast-paced environment and with meeting deadlines. Responsibilities: Communicate with the engineering team and write, review and update technical documents, tutorials and blogs; Building and developing brand awareness in technical communities and social media; Assist in preparing and refining the marketing collaterals. 待遇:200 元/天,餐补,零食水果,生日会,Team Building联系方式:hire@pingcap.com工作地点:北京"}, {"url": "https://pingcap.com/docs/sql/control-flow-functions/", "title": "Control Flow Functions", "content": " Control Flow Functions Name Description CASE Case operator IF() If/else construct IFNULL() Null if/else construct NULLIF() Return NULL if expr1 = expr2 "}, {"url": "https://pingcap.com/docs/v1.0/sql/control-flow-functions/", "title": "Control Flow Functions", "content": " Control Flow Functions Name Description CASE Case operator IF() If/else construct IFNULL() Null if/else construct NULLIF() Return NULL if expr1 = expr2 "}, {"url": "https://pingcap.com/docs/v2.0/sql/control-flow-functions/", "title": "Control Flow Functions", "content": " Control Flow Functions Name Description CASE Case operator IF() If/else construct IFNULL() Null if/else construct NULLIF() Return NULL if expr1 = expr2 "}, {"url": "https://pingcap.com/tidb-academy/mysql_dbas/introduction/course-overview/", "title": "Course Overview", "content": " Course Overview Transcript Welcome to TiDB Academy!My name is Morgan, and I’ll be your instructor for TiDB for MySQL DBAs. To give myself a quick introduction, like you I have a background in MySQL Administration. I’ve been using it for over 15 years now, most recently I was product manager for the MySQL Server at Oracle. If you have a question about how something you do in MySQL works in TiDB, I’d be happy to provide an answer!TiDB for MySQL DBAs is an advanced course targeted for those with a strong MySQL background. We are assuming you have 3-5 years of MySQL experience, as a MySQL DBA or architect, because in many cases I will explain TiDB concepts by using a direct comparison to MySQL. So let’s start with an example of what I might say: In TiDB, the storage engine is based on RocksDB instead of InnoDB. RocksDB has similar semantics, as it is also a transactional storage engine with full ACID compliance. It has a couple of distinctive advantages for large databases: it has more efficient compression, and insert performance is sustained when the data set no longer fits in memory. Did that sentence make sense to you? If so, excellent!There is one more prerequisite for this course. And that is that we are assuming that you comfortable with using a command line interface for Bash and MySQL.(If this doesn’t describe you, we are planning other future TiDB academy courses for more beginner-level audiences, so stay tuned.)In this advanced course, you will learn the ins-and-outs of how a complex distributed database like TiDB works and how TiDB complements existing MySQL users like you, along with a set of hands-on labs to practice your new skills. As a teaser, here are some key topics we will cover: Architectural design components that support hybrid transactional/analytical processing (HTAP) workloads Horizontal scaling with a transactional model that keeps data strongly consistent and highly available Online DDL algorithm and implementation Ready? Let’s get started!"}, {"url": "https://pingcap.com/tidb-academy/mysql_dbas/conclusion/course-summary/", "title": "Course Summary", "content": " Course Summary Transcript Thank you for joining me on our TiDB for MySQL DBAs course. I hope you had as much fun attending the course, as I did creating it.In this video, I wanted to go over some of the major takeaways for each of the sections of the course. The goal in me doing so is that if I trigger something that is less familiar to you, you can use this as an opportunity to go back and watch the section again, or repeat the lab exercises.Starting with the TiDB Platform: Here we learned that the TiDB Platform consists of three major components, the TiDB server which is stateless and handles SQL processing, the TiKV server, which is a transactional Key-Value store, and PD which is the cluster manager. We also learned that there is an optional component called TiSpark which can be used to expose your TiKV data to Apache Spark for complex analytical workloads.We discussed using the KOST stack for deployment, which includes Kubernetes and Operator. Kubernetes is the container orchestrator and Operator helps manage the TiDB platform as a Kubernetes deployment.MySQL Compatibility: In this section we learned about what it means to be MySQL Compatible. Is it network protocol, SQL syntax, both? With TiDB being a distributed database, are there exceptions to this where some features don’t make sense to work the same.Query Optimization: In query optimization we looked at optimizing SQL statements. Both the format of EXPLAIN, and the potential execution strategies possible in TiDB’s query optimizer differ from MySQL - so this section is worth revisiting if you are stuck on a slow query. We also took a look at TiDB’s coprocessor, where parts of queries can be pushed down to TiKV for efficient execution.HTAP: In this section we revisited one of the TiDB platform’s major advantages in that it can run both OLTP and OLAP queries on the same tech stack with minimal ETL. I tried to give some context between what queries should be sent to TiDB servers versus Spark, and directionally where that is heading.Backup and Restore: In this section we covered a little bit of theory on the differences between HA and DR, and that one of the common reasons to restore from backup is accidental deletes. In TiDB there is a handy feature called tidb_snapshot which allows you to view what the data looked like at an earlier point in time. We had a lab using this, as well as a full backup and restore.Schema Changes: DDL is a major advantage in TiDB over MySQL. This section describes how TiDB’s DDL is online, while being distributed, using the asynchronous schema change algorithm first described in Google’s F1 paper.Scaling the TiDB Platform: In this section we describe how to scale the Kubernetes Cluster, TiDB servers and TiKV servers. We practice it with a number of lab exercises too, so while the process is quite straight forward I recommend DBAs having some practice with it.Updates, Upgrades and Migrations: We first categorized changes as an Update, Upgrade or Migration and the motivations of each. For updates in particular, a rolling update is quite straight forward in TiDB. For migrations and upgrades we talked about some of the typical risks and suggested some tools that could be used for closer evaluation.RocksDB: In this section we described the RocksDB storage engine, which has some technical advantages and different performance characteristics than what you may be used to with InnoDB.Monitoring and Observability: In monitoring and observability we discussed how PD and TiKV use Raft consensus to ensure high availability, and what the TiDB Platform uses instead of performance_schema for observability (hint: it’s Prometheus and Grafana).Okay, that’s it! In the next section we will quickly go over some recommendations of where you can go from here."}, {"url": "https://pingcap.com/docs/op-guide/cross-dc-deployment/", "title": "Cross-DC Deployment Solutions", "content": " Cross-DC Deployment Solutions As a NewSQL database, TiDB excels in the best features of the traditional relational database and the scalability of the NoSQL database and is of course, highly available across data centers (hereinafter referred to as DC). This document is to introduce different deployment solutions in cross-DC environment.3-DC Deployment Solution TiDB, TiKV and PD are distributed among 3 DCs, which is the most common deployment solution with the highest availability.Advantages All the replicas are distributed among 3 DCs. Even if one DC is down, the other 2 DCs will initiate leader election and resume service within a reasonable amount of time (within 20s in most cases) and no data is lost. See the following diagram for more information:Disadvantages The performance is greatly limited by the network latency. For writes, all the data has to be replicated to at least 2 DCs. Because TiDB uses 2-phase commit for writes, the write latency is at least twice the latency of the network between two DCs. The read performance will also suffer if the leader is not in the same DC as the TiDB node with the read request. Each TiDB transaction needs to obtain TimeStamp Oracle (TSO) from the PD leader. So if TiDB and PD leader are not in the same DC, the performance of the transactions will also be impacted by the network latency because each transaction with write request will have to get TSO twice. Optimizations If not all of the three DCs need to provide service to the applications, you can dispatch all the requests to one DC and configure the scheduling policy to migrate all the TiKV Region leader and PD leader to the same DC, as what we have done in the following test. In this way, neither obtaining TSO or reading TiKV Regions will be impacted by the network latency between DCs. If this DC is down, the PD leader and Region leader will be automatically elected in other surviving DCs, and you just need to switch the requests to the DC that are still online.3-DC in 2 cities Deployment Solution This solution is similar to the previous 3-DC deployment solution and can be considered as an optimization based on the business scenario. The difference is that the distance between the 2 DCs within the same city is short and thus the latency is very low. In this case, we can dispatch the requests to the two DCs within the same city and configure the TiKV leader and PD leader to be in the 2 DCs in the same city.Compared with the 3-DC deployment, the 3-DC in 2 cities deployment has the following advantages: Better write performance. Better usage of the resources because 2 DCs can provide services to the applications. Even if one DC is down, the TiDB cluster will be still available and no data is lost. However, the disadvantage is that if the 2 DCs within the same city goes down, whose probability is higher than that of the outage of 2 DCs in 2 cities, the TiDB cluster will not be available and some of the data will be lost.2-DC + Binlog Synchronization Deployment Solution The 2-DC + Binlog synchronization is similar to the MySQL Master-Slave solution. 2 complete sets of TiDB clusters (each complete set of the TiDB cluster includes TiDB, PD and TiKV) are deployed in 2 DCs, one acts as the Master and one as the Slave. Under normal circumstances, the Master DC handle all the requests and the data written to the Master DC is asynchronously written to the Slave DC via Binlog.If the Master DC goes down, the requests can be switched to the slave cluster. Similar to MySQL, some data might be lost. But different from MySQL, this solution can ensure the high availability within the same DC: if some nodes within the DC are down, the online business won’t be impacted and no manual efforts are needed because the cluster will automatically re-elect leaders to provide services.Some of our production users also adopt the 2-DC multi-active solution, which means: The application requests are separated and dispatched into 2 DCs. Each DC has 1 cluster and each cluster has two databases: A Master database to serve part of the application requests and a Slave database to act as the backup of the other DC’s Master database. Data written into the Master database is synchronized via Binlog to the Slave database in the other DC, forming a loop of backup. Please be noted that for the 2-DC + Binlog synchronization solution, data is asynchronously replicated via Binlog. If the network latency between 2 DCs is too high, the data in the Slave cluster will fall much behind of the Master cluster. If the Master cluster goes down, some data will be lost and it cannot be guaranteed the lost data is within 5 minutes.Overall analysis for HA and DR For the 3-DC deployment solution and 3-DC in 2 cities solution, we can guarantee that the cluster will automatically recover, no human interference is needed and that the data is strongly consistent even if any one of the 3 DCs goes down. All the scheduling policies are to tune the performance, but availability is the top 1 priority instead of performance in case of an outage.For 2-DC + Binlog synchronization solution, we can guarantee that the cluster will automatically recover, no human interference is needed and that the data is strongly consistent even if any some of the nodes within the Master cluster go down. When the entire Master cluster goes down, manual efforts will be needed to switch to the Slave and some data will be lost. The amount of the lost data depends on the network latency and is decided by the network condition."}, {"url": "https://pingcap.com/docs/v1.0/op-guide/location-awareness/", "title": "Cross-Region Deployment", "content": " Cross-Region Deployment Overview PD schedules according to the topology of the TiKV cluster to maximize the TiKV’s capability for disaster recovery.Before you begin, see Ansible Deployment (Recommended) and Docker Deployment.TiKV reports the topological information TiKV reports the topological information to PD according to the startup parameter or configuration of TiKV.Assuming that the topology has three structures: zone > rack > host, use lables to specify the following information:Startup parameter:tikv-server --labels zone=<zone>,rack=<rack>,host=<host> Configuration:[server] labels = "zone=<zone>,rack=<rack>,host=<host>" PD understands the TiKV topology PD gets the topology of TiKV cluster through the PD configuration.[replication] max-replicas = 3 location-labels = ["zone", "rack", "host"] location-labels needs to correspond to the TiKV labels name so that PD can understand that the labels represents the TiKV topology.PD schedules based on the TiKV topology PD makes optimal schedulings according to the topological information. You just need to care about what kind of topology can achieve the desired effect.If you use 3 replicas and hope that everything still works well when a data zone hangs up, you need at least 4 data zones. (Theoretically, three data zones are feasible but the current implementation cannot guarantee.)Assume that we have 4 data zones, each zone has 2 racks and each rack has 2 hosts. We can start 2 TiKV instances on each host:# zone=z1 tikv-server --labels zone=z1,rack=r1,host=h1 tikv-server --labels zone=z1,rack=r1,host=h2 tikv-server --labels zone=z1,rack=r2,host=h1 tikv-server --labels zone=z1,rack=r2,host=h2 # zone=z2 tikv-server --labels zone=z2,rack=r1,host=h1 tikv-server --labels zone=z2,rack=r1,host=h2 tikv-server --labels zone=z2,rack=r2,host=h1 tikv-server --labels zone=z2,rack=r2,host=h2 # zone=z3 tikv-server --labels zone=z3,rack=r1,host=h1 tikv-server --labels zone=z3,rack=r1,host=h2 tikv-server --labels zone=z3,rack=r2,host=h1 tikv-server --labels zone=z3,rack=r2,host=h2 # zone=z4 tikv-server --labels zone=z4,rack=r1,host=h1 tikv-server --labels zone=z4,rack=r1,host=h2 tikv-server --labels zone=z4,rack=r2,host=h1 tikv-server --labels zone=z4,rack=r2,host=h2 In other words, 16 TiKV instances are distributed across 4 data zones, 8 racks and 16 machines.In this case, PD will schedule different replicas of each datum to different data zones. - If one of the data zones hangs up, everything still works well. - If the data zone cannot recover within a period of time, PD will remove the replica from this data zone.To sum up, PD maximizes the disaster recovery of the cluster according to the current topology. Therefore, if you want to reach a certain level of disaster recovery, deploy many machines in different sites according to the topology. The number of machines must be more than the number of max-replicas."}, {"url": "https://pingcap.com/docs/v2.0/op-guide/location-awareness/", "title": "Cross-Region Deployment", "content": " Cross-Region Deployment Overview PD schedules according to the topology of the TiKV cluster to maximize the TiKV’s capability for disaster recovery.Before you begin, see Deploy TiDB Using Ansible (Recommended) and Deploy TiDB Using Docker.TiKV reports the topological information TiKV reports the topological information to PD according to the startup parameter or configuration of TiKV.Assuming that the topology has three structures: zone > rack > host, use lables to specify the following information:Startup parameter:tikv-server --labels zone=<zone>,rack=<rack>,host=<host> Configuration:[server] labels = "zone=<zone>,rack=<rack>,host=<host>" PD understands the TiKV topology PD gets the topology of TiKV cluster through the PD configuration.[replication] max-replicas = 3 location-labels = ["zone", "rack", "host"] location-labels needs to correspond to the TiKV labels name so that PD can understand that the labels represents the TiKV topology.PD schedules based on the TiKV topology PD makes optimal scheduling according to the topological information. You just need to care about what kind of topology can achieve the desired effect.If you use 3 replicas and hope that the TiDB cluster is always highly available even when a data zone goes down, you need at least 4 data zones.Assume that you have 4 data zones, each zone has 2 racks, and each rack has 2 hosts. You can start 2 TiKV instances on each host:# zone=z1 tikv-server --labels zone=z1,rack=r1,host=h1 tikv-server --labels zone=z1,rack=r1,host=h2 tikv-server --labels zone=z1,rack=r2,host=h1 tikv-server --labels zone=z1,rack=r2,host=h2 # zone=z2 tikv-server --labels zone=z2,rack=r1,host=h1 tikv-server --labels zone=z2,rack=r1,host=h2 tikv-server --labels zone=z2,rack=r2,host=h1 tikv-server --labels zone=z2,rack=r2,host=h2 # zone=z3 tikv-server --labels zone=z3,rack=r1,host=h1 tikv-server --labels zone=z3,rack=r1,host=h2 tikv-server --labels zone=z3,rack=r2,host=h1 tikv-server --labels zone=z3,rack=r2,host=h2 # zone=z4 tikv-server --labels zone=z4,rack=r1,host=h1 tikv-server --labels zone=z4,rack=r1,host=h2 tikv-server --labels zone=z4,rack=r2,host=h1 tikv-server --labels zone=z4,rack=r2,host=h2 In other words, 16 TiKV instances are distributed across 4 data zones, 8 racks and 16 machines.In this case, PD will schedule different replicas of each datum to different data zones. If one of the data zones goes down, the high availability of the TiDB cluster is not affected. If the data zone cannot recover within a period of time, PD will remove the replica from this data zone. To sum up, PD maximizes the disaster recovery of the cluster according to the current topology. Therefore, if you want to reach a certain level of disaster recovery, deploy many machines in different sites according to the topology. The number of machines must be more than the number of max-replicas."}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/ddl/", "title": "DDL", "content": " 数据定义语言 DDL(Data Definition Language)用于定义和管理数据库以及数据库中各种对象的语句。CREATE DATABASE 语法 CREATE {DATABASE | SCHEMA} [IF NOT EXISTS] db_name [create_specification] ... create_specification: [DEFAULT] CHARACTER SET [=] charset_name | [DEFAULT] COLLATE [=] collation_name CREATE DATABASE 用于创建数据库,并可以指定数据库的默认属性(如数据库默认字符集,校验规则。CREATE SCHEMA 跟 CREATE DATABASE 操作效果一样。当创建已存在的数据库且不指定使用 IF NOT EXISTS 时会报错。create_specification 选项用于指定数据库具体的 CHARACTER SET 和 COLLATE。目前这个选项只是语法支持。DROP DATABASE 语法 DROP {DATABASE | SCHEMA} [IF EXISTS] db_name DROP DATABASE 用于删除指定数据库以及它其中的所用表格。IF EXISTS 用于防止当数据库不存在时发生错误。CREATE TABLE 语法 CREATE TABLE [IF NOT EXISTS] tbl_name (create_definition,...) [table_options] CREATE TABLE [IF NOT EXISTS] tbl_name { LIKE old_tbl_name | (LIKE old_tbl_name) } create_definition: col_name column_definition | [CONSTRAINT [symbol]] PRIMARY KEY [index_type] (index_col_name,...) [index_option] ... | {INDEX|KEY} [index_name] [index_type] (index_col_name,...) [index_option] ... | [CONSTRAINT [symbol]] UNIQUE [INDEX|KEY] [index_name] [index_type] (index_col_name,...) [index_option] ... | {FULLTEXT} [INDEX|KEY] [index_name] (index_col_name,...) [index_option] ... | [CONSTRAINT [symbol]] FOREIGN KEY [index_name] (index_col_name,...) reference_definition column_definition: data_type [NOT NULL | NULL] [DEFAULT default_value] [AUTO_INCREMENT] [UNIQUE [KEY] | [PRIMARY] KEY] [COMMENT 'string'] [reference_definition] | data_type [GENERATED ALWAYS] AS (expression) [VIRTUAL | STORED] [UNIQUE [KEY]] [COMMENT comment] [NOT NULL | NULL] [[PRIMARY] KEY] data_type: BIT[(length)] | TINYINT[(length)] [UNSIGNED] [ZEROFILL] | SMALLINT[(length)] [UNSIGNED] [ZEROFILL] | MEDIUMINT[(length)] [UNSIGNED] [ZEROFILL] | INT[(length)] [UNSIGNED] [ZEROFILL] | INTEGER[(length)] [UNSIGNED] [ZEROFILL] | BIGINT[(length)] [UNSIGNED] [ZEROFILL] | REAL[(length,decimals)] [UNSIGNED] [ZEROFILL] | DOUBLE[(length,decimals)] [UNSIGNED] [ZEROFILL] | FLOAT[(length,decimals)] [UNSIGNED] [ZEROFILL] | DECIMAL[(length[,decimals])] [UNSIGNED] [ZEROFILL] | NUMERIC[(length[,decimals])] [UNSIGNED] [ZEROFILL] | DATE | TIME[(fsp)] | TIMESTAMP[(fsp)] | DATETIME[(fsp)] | YEAR | CHAR[(length)] [BINARY] [CHARACTER SET charset_name] [COLLATE collation_name] | VARCHAR(length) [BINARY] [CHARACTER SET charset_name] [COLLATE collation_name] | BINARY[(length)] | VARBINARY(length) | TINYBLOB | BLOB | MEDIUMBLOB | LONGBLOB | TINYTEXT [BINARY] [CHARACTER SET charset_name] [COLLATE collation_name] | TEXT [BINARY] [CHARACTER SET charset_name] [COLLATE collation_name] | MEDIUMTEXT [BINARY] [CHARACTER SET charset_name] [COLLATE collation_name] | LONGTEXT [BINARY] [CHARACTER SET charset_name] [COLLATE collation_name] | ENUM(value1,value2,value3,...) [CHARACTER SET charset_name] [COLLATE collation_name] | SET(value1,value2,value3,...) [CHARACTER SET charset_name] [COLLATE collation_name] | JSON index_col_name: col_name [(length)] [ASC | DESC] index_type: USING {BTREE | HASH} index_option: KEY_BLOCK_SIZE [=] value | index_type | COMMENT 'string' reference_definition: REFERENCES tbl_name (index_col_name,...) [MATCH FULL | MATCH PARTIAL | MATCH SIMPLE] [ON DELETE reference_option] [ON UPDATE reference_option] reference_option: RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT table_options: table_option [[,] table_option] ... table_option: AUTO_INCREMENT [=] value | AVG_ROW_LENGTH [=] value | [DEFAULT] CHARACTER SET [=] charset_name | CHECKSUM [=] {0 | 1} | [DEFAULT] COLLATE [=] collation_name | COMMENT [=] 'string' | COMPRESSION [=] {'ZLIB'|'LZ4'|'NONE'} | CONNECTION [=] 'connect_string' | DELAY_KEY_WRITE [=] {0 | 1} | ENGINE [=] engine_name | KEY_BLOCK_SIZE [=] value | MAX_ROWS [=] value | MIN_ROWS [=] value | ROW_FORMAT [=] {DEFAULT|DYNAMIC|FIXED|COMPRESSED|REDUNDANT|COMPACT} | STATS_PERSISTENT [=] {DEFAULT|0|1} CREATE TABLE 用于创建一个表。目前不支持临时表,不支持 CHECK 约束,不支持创建表的同时从其它表导入数据功能。 在语法上也支持一些 Partition_options,但是并不完全,就不做列举了。 使用 IF NOT EXIST 时,即使创建的表已经存在,也不会报错,如果不指定时,则报错。 使用 LIKE 基于一个表的定义创建一个空表,包括这个表中的列属性和索引属性。 create_definition 中 FULLTEXT 和 FOREIGN KEY 目前只是语法上支持 data_type 请参考数据类型章节。 index_col_name 中 [ASC | DESC] 目前只是语法上支持。 index_type 目前只是语法上支持。 index_option 中 KEY_BLOCK_SIZE 目前只是语法上支持。 table_option 目前支持的只有 AUTO_INCREMENT,CHARACTER SET 和 COMMENT,其它只是语法上支持。具体内容参考下表,各个子句之间用逗号隔开。 参数 含义 举例 AUTO_INCREMENT 自增字段初始值 AUTO_INCREMENT = 5 CHARACTER SET 指定该表的字符串编码。目前支持 UTF8MB4 CHARACTER SET = ‘utf8mb4’ COMMENT 注释信息 COMMENT = ‘comment info’ AUTO_INCREMENT 说明 TiDB 的自增 ID (AUTO_INCREMENT ID) 只保证自增且唯一,并不保证连续分配。TiDB 目前采用批量分配的方式,所以如果在多台 TiDB 上同时插入数据,分配的自增 ID 会不连续。允许给整型类型的字段指定 AUTO_INCREMENT,且一个表只允许一个属性为 AUTO_INCREMENT 的字段。DROP TABLE 语法 DROP TABLE [IF EXISTS] tbl_name [, tbl_name] ... 可以同时删除多个表,表之间用 , 隔开。当删除不存在的表时且不指定使用 IF EXISTS 时会报错。TRUNCATE TABLE 语法 TRUNCATE [TABLE] tbl_name TRUNCATE TABLE 用于清除指定表中所有数据,但是保留表结构。此操作于删除指定表全表数据的操作类似,但是操作的执行速度会远快于删除全表的速度,且不受表内数据行数影响。 注意:使用此语句后,原先表内的 AUTO_INCREMENT 的值不会记录,会被重新计数。 RENAME TABLE 语法 RENAME TABLE tbl_name TO new_tbl_name RENAME TABLE 用于对一个表进行重命名。这个语句等价于如下的 ALTER TABLE 语句:ALTER TABLE old_table RENAME new_table; ALTER TABLE 语法 ALTER TABLE tbl_name [alter_specification] alter_specification: table_options | ADD [COLUMN] col_name column_definition [FIRST | AFTER col_name] | ADD [COLUMN] (col_name column_definition,...) | ADD {INDEX|KEY} [index_name] [index_type] (index_col_name,...) [index_option] ... | ADD [CONSTRAINT [symbol]] PRIMARY KEY [index_type] (index_col_name,...) [index_option] ... | ADD [CONSTRAINT [symbol]] UNIQUE [INDEX|KEY] [index_name] [index_type] (index_col_name,...) [index_option] ... | ADD FULLTEXT [INDEX|KEY] [index_name] (index_col_name,...) [index_option] ... | ADD [CONSTRAINT [symbol]] FOREIGN KEY [index_name] (index_col_name,...) reference_definition | ALTER [COLUMN] col_name {SET DEFAULT literal | DROP DEFAULT} | CHANGE [COLUMN] old_col_name new_col_name column_definition [FIRST|AFTER col_name] | {DISABLE|ENABLE} KEYS | DROP [COLUMN] col_name | DROP {INDEX|KEY} index_name | DROP PRIMARY KEY | DROP FOREIGN KEY fk_symbol | LOCK [=] {DEFAULT|NONE|SHARED|EXCLUSIVE} | MODIFY [COLUMN] col_name column_definition [FIRST | AFTER col_name] | RENAME [TO|AS] new_tbl_name | {WITHOUT|WITH} VALIDATION index_col_name: col_name [(length)] [ASC | DESC] index_type: USING {BTREE | HASH} index_option: KEY_BLOCK_SIZE [=] value | index_type | COMMENT 'string' table_options: table_option [[,] table_option] ... table_option: AVG_ROW_LENGTH [=] value | [DEFAULT] CHARACTER SET [=] charset_name | CHECKSUM [=] {0 | 1} | [DEFAULT] COLLATE [=] collation_name | COMMENT [=] 'string' | COMPRESSION [=] {'ZLIB'|'LZ4'|'NONE'} | CONNECTION [=] 'connect_string' | DELAY_KEY_WRITE [=] {0 | 1} | ENGINE [=] engine_name | KEY_BLOCK_SIZE [=] value | MAX_ROWS [=] value | MIN_ROWS [=] value | ROW_FORMAT [=] {DEFAULT|DYNAMIC|FIXED|COMPRESSED|REDUNDANT|COMPACT} | STATS_PERSISTENT [=] {DEFAULT|0|1} ALTER TABLE 用于修改已存在的表的结构,比如:修改表及表属性、新增或删除列、创建或删除索引、修改列及属性等. 以下是几个字段类型的描述: index_col_name、index_type 和 index_option 可以参考 CREATE INDEX 语法. table_option 目前支持都只是语法上支持。 下面介绍一下具体操作类型的支持情况。 ADD/DROP INDEX/COLUMN 操作目前不支持同时创建或删除多个索引或列。 ADD/DROP PRIMARY KEY 操作目前不支持。 DROP COLUMN 操作目前不支持删除的列为主键列或索引列。 ADD COLUMN 操作目前不支持同时将新添加的列设为主键或唯一索引,也不支持将此列设成 AUTO_INCREMENT 属性。 CHANGE/MODIFY COLUMN 操作目前支持部分语法,细节如下: 在修改类型方面,只支持整数类型之间修改,字符串类型之间修改和 Blob 类型之间的修改,且只能使原类型长度变长。此外,不能改变列的 unsigned/charset/collate 属性。这里的类型分类如下: 具体支持的整型类型有:TinyInt,SmallInt,MediumInt,Int,BigInt。 具体支持的字符串类型有:Char,Varchar,Text,TinyText,MediumText,LongText。 具体支持的 Blob 类型有:Blob,TinyBlob,MediumBlob,LongBlob。 在修改类型定义方面,支持的包括 default value,comment,null,not null 和 OnUpdate,但是不支持从 null 到 not null 的修改。 不支持对 enum 类型的列进行修改 LOCK [=] {DEFAULT|NONE|SHARED|EXCLUSIVE} 目前只是语法支持。 CREATE INDEX 语法 CREATE [UNIQUE] INDEX index_name [index_type] ON tbl_name (index_col_name,...) [index_option] ... index_col_name: col_name [(length)] [ASC | DESC] index_option: KEY_BLOCK_SIZE [=] value | …"}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/ddl/", "title": "DDL", "content": " 数据定义语言 DDL(Data Definition Language)用于定义和管理数据库以及数据库中各种对象的语句。CREATE DATABASE 语法 CREATE {DATABASE | SCHEMA} [IF NOT EXISTS] db_name [create_specification] ... create_specification: [DEFAULT] CHARACTER SET [=] charset_name | [DEFAULT] COLLATE [=] collation_name CREATE DATABASE 用于创建数据库,并可以指定数据库的默认属性(如数据库默认字符集,校验规则。CREATE SCHEMA 跟 CREATE DATABASE 操作效果一样。当创建已存在的数据库且不指定使用 IF NOT EXISTS 时会报错。create_specification 选项用于指定数据库具体的 CHARACTER SET 和 COLLATE。目前这个选项只是语法支持。DROP DATABASE 语法 DROP {DATABASE | SCHEMA} [IF EXISTS] db_name DROP DATABASE 用于删除指定数据库以及它其中的所用表格。IF EXISTS 用于防止当数据库不存在时发生错误。CREATE TABLE 语法 CREATE TABLE [IF NOT EXISTS] tbl_name (create_definition,...) [table_options] CREATE TABLE [IF NOT EXISTS] tbl_name { LIKE old_tbl_name | (LIKE old_tbl_name) } create_definition: col_name column_definition | [CONSTRAINT [symbol]] PRIMARY KEY [index_type] (index_col_name,...) [index_option] ... | {INDEX|KEY} [index_name] [index_type] (index_col_name,...) [index_option] ... | [CONSTRAINT [symbol]] UNIQUE [INDEX|KEY] [index_name] [index_type] (index_col_name,...) [index_option] ... | {FULLTEXT} [INDEX|KEY] [index_name] (index_col_name,...) [index_option] ... | [CONSTRAINT [symbol]] FOREIGN KEY [index_name] (index_col_name,...) reference_definition column_definition: data_type [NOT NULL | NULL] [DEFAULT default_value] [AUTO_INCREMENT] [UNIQUE [KEY] | [PRIMARY] KEY] [COMMENT 'string'] [reference_definition] | data_type [GENERATED ALWAYS] AS (expression) [VIRTUAL | STORED] [UNIQUE [KEY]] [COMMENT comment] [NOT NULL | NULL] [[PRIMARY] KEY] data_type: BIT[(length)] | TINYINT[(length)] [UNSIGNED] [ZEROFILL] | SMALLINT[(length)] [UNSIGNED] [ZEROFILL] | MEDIUMINT[(length)] [UNSIGNED] [ZEROFILL] | INT[(length)] [UNSIGNED] [ZEROFILL] | INTEGER[(length)] [UNSIGNED] [ZEROFILL] | BIGINT[(length)] [UNSIGNED] [ZEROFILL] | REAL[(length,decimals)] [UNSIGNED] [ZEROFILL] | DOUBLE[(length,decimals)] [UNSIGNED] [ZEROFILL] | FLOAT[(length,decimals)] [UNSIGNED] [ZEROFILL] | DECIMAL[(length[,decimals])] [UNSIGNED] [ZEROFILL] | NUMERIC[(length[,decimals])] [UNSIGNED] [ZEROFILL] | DATE | TIME[(fsp)] | TIMESTAMP[(fsp)] | DATETIME[(fsp)] | YEAR | CHAR[(length)] [BINARY] [CHARACTER SET charset_name] [COLLATE collation_name] | VARCHAR(length) [BINARY] [CHARACTER SET charset_name] [COLLATE collation_name] | BINARY[(length)] | VARBINARY(length) | TINYBLOB | BLOB | MEDIUMBLOB | LONGBLOB | TINYTEXT [BINARY] [CHARACTER SET charset_name] [COLLATE collation_name] | TEXT [BINARY] [CHARACTER SET charset_name] [COLLATE collation_name] | MEDIUMTEXT [BINARY] [CHARACTER SET charset_name] [COLLATE collation_name] | LONGTEXT [BINARY] [CHARACTER SET charset_name] [COLLATE collation_name] | ENUM(value1,value2,value3,...) [CHARACTER SET charset_name] [COLLATE collation_name] | SET(value1,value2,value3,...) [CHARACTER SET charset_name] [COLLATE collation_name] | JSON index_col_name: col_name [(length)] [ASC | DESC] index_type: USING {BTREE | HASH} index_option: KEY_BLOCK_SIZE [=] value | index_type | COMMENT 'string' reference_definition: REFERENCES tbl_name (index_col_name,...) [MATCH FULL | MATCH PARTIAL | MATCH SIMPLE] [ON DELETE reference_option] [ON UPDATE reference_option] reference_option: RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT table_options: table_option [[,] table_option] ... table_option: AUTO_INCREMENT [=] value | AVG_ROW_LENGTH [=] value | [DEFAULT] CHARACTER SET [=] charset_name | CHECKSUM [=] {0 | 1} | [DEFAULT] COLLATE [=] collation_name | COMMENT [=] 'string' | COMPRESSION [=] {'ZLIB'|'LZ4'|'NONE'} | CONNECTION [=] 'connect_string' | DELAY_KEY_WRITE [=] {0 | 1} | ENGINE [=] engine_name | KEY_BLOCK_SIZE [=] value | MAX_ROWS [=] value | MIN_ROWS [=] value | ROW_FORMAT [=] {DEFAULT|DYNAMIC|FIXED|COMPRESSED|REDUNDANT|COMPACT} | STATS_PERSISTENT [=] {DEFAULT|0|1} CREATE TABLE 用于创建一个表。目前不支持临时表,不支持 CHECK 约束,不支持创建表的同时从其它表导入数据功能。 在语法上也支持一些 Partition_options,但是并不完全,就不做列举了。 使用 IF NOT EXIST 时,即使创建的表已经存在,也不会报错,如果不指定时,则报错。 使用 LIKE 基于一个表的定义创建一个空表,包括这个表中的列属性和索引属性。 create_definition 中 FULLTEXT 和 FOREIGN KEY 目前只是语法上支持 data_type 请参考数据类型章节。 index_col_name 中 [ASC | DESC] 目前只是语法上支持。 index_type 目前只是语法上支持。 index_option 中 KEY_BLOCK_SIZE 目前只是语法上支持。 table_option 目前支持的只有 AUTO_INCREMENT,CHARACTER SET 和 COMMENT,其它只是语法上支持。具体内容参考下表,各个子句之间用逗号隔开。 参数 含义 举例 AUTO_INCREMENT 自增字段初始值 AUTO_INCREMENT = 5 CHARACTER SET 指定该表的字符串编码。目前支持 UTF8MB4 CHARACTER SET = ‘utf8mb4’ COMMENT 注释信息 COMMENT = ‘comment info’ AUTO_INCREMENT 说明 TiDB 的自增 ID (AUTO_INCREMENT ID) 只保证自增且唯一,并不保证连续分配。TiDB 目前采用批量分配的方式,所以如果在多台 TiDB 上同时插入数据,分配的自增 ID 会不连续。允许给整型类型的字段指定 AUTO_INCREMENT,且一个表只允许一个属性为 AUTO_INCREMENT 的字段。DROP TABLE 语法 DROP TABLE [IF EXISTS] tbl_name [, tbl_name] ... [RESTRICT | CASCADE] 可以同时删除多个表,表之间用 , 隔开。当删除不存在的表时且不指定使用 IF EXISTS 时会报错。关键字 RESTRICT 和 CASCADE 没有实际效果。其作用是与其他数据库兼容。TRUNCATE TABLE 语法 TRUNCATE [TABLE] tbl_name TRUNCATE TABLE 用于清除指定表中所有数据,但是保留表结构。此操作于删除指定表全表数据的操作类似,但是操作的执行速度会远快于删除全表的速度,且不受表内数据行数影响。 注意:使用此语句后,原先表内的 AUTO_INCREMENT 的值不会记录,会被重新计数。 RENAME TABLE 语法 RENAME TABLE tbl_name TO new_tbl_name RENAME TABLE 用于对一个表进行重命名。这个语句等价于如下的 ALTER TABLE 语句:ALTER TABLE old_table RENAME new_table; ALTER TABLE 语法 ALTER TABLE tbl_name [alter_specification] alter_specification: table_options | ADD [COLUMN] col_name column_definition [FIRST | AFTER col_name] | ADD [COLUMN] (col_name column_definition,...) | ADD {INDEX|KEY} [index_name] [index_type] (index_col_name,...) [index_option] ... | ADD [CONSTRAINT [symbol]] PRIMARY KEY [index_type] (index_col_name,...) [index_option] ... | ADD [CONSTRAINT [symbol]] UNIQUE [INDEX|KEY] [index_name] [index_type] (index_col_name,...) [index_option] ... | ADD FULLTEXT [INDEX|KEY] [index_name] (index_col_name,...) [index_option] ... | ADD [CONSTRAINT [symbol]] FOREIGN KEY [index_name] (index_col_name,...) reference_definition | ALTER [COLUMN] col_name {SET DEFAULT literal | DROP DEFAULT} | CHANGE [COLUMN] old_col_name new_col_name column_definition [FIRST|AFTER col_name] | {DISABLE|ENABLE} KEYS | DROP [COLUMN] col_name | DROP {INDEX|KEY} index_name | DROP PRIMARY KEY | DROP FOREIGN KEY fk_symbol | LOCK [=] {DEFAULT|NONE|SHARED|EXCLUSIVE} | MODIFY [COLUMN] col_name column_definition [FIRST | AFTER col_name] | RENAME [TO|AS] new_tbl_name | {WITHOUT|WITH} VALIDATION index_col_name: col_name [(length)] [ASC | DESC] index_type: USING {BTREE | HASH} index_option: KEY_BLOCK_SIZE [=] value | index_type | COMMENT 'string' table_options: table_option [[,] table_option] ... table_option: AVG_ROW_LENGTH [=] value | [DEFAULT] CHARACTER SET [=] charset_name | CHECKSUM [=] {0 | 1} | [DEFAULT] COLLATE [=] collation_name | COMMENT [=] 'string' | COMPRESSION [=] {'ZLIB'|'LZ4'|'NONE'} | CONNECTION [=] 'connect_string' | DELAY_KEY_WRITE [=] {0 | 1} | ENGINE [=] engine_name | KEY_BLOCK_SIZE [=] value | MAX_ROWS [=] value | MIN_ROWS [=] value | ROW_FORMAT [=] {DEFAULT|DYNAMIC|FIXED|COMPRESSED|REDUNDANT|COMPACT} | STATS_PERSISTENT [=] {DEFAULT|0|1} ALTER TABLE 用于修改已存在的表的结构,比如:修改表及表属性、新增或删除列、创建或删除索引、修改列及属性等. 以下是几个字段类型的描述: index_col_name、index_type 和 index_option 可以参考 CREATE INDEX 语法. table_option 目前支持都只是语法上支持。 下面介绍一下具体操作类型的支持情况。 ADD/DROP INDEX/COLUMN 操作目前不支持同时创建或删除多个索引或列。 ADD/DROP PRIMARY KEY 操作目前不支持。 DROP COLUMN 操作目前不支持删除的列为主键列或索引列。 ADD COLUMN 操作目前不支持同时将新添加的列设为主键或唯一索引,也不支持将此列设成 AUTO_INCREMENT 属性。 CHANGE/MODIFY COLUMN 操作目前支持部分语法,细节如下: 在修改类型方面,只支持整数类型之间修改,字符串类型之间修改和 Blob 类型之间的修改,且只能使原类型长度变长。此外,不能改变列的 unsigned/charset/collate 属性。这里的类型分类如下: 具体支持的整型类型有:TinyInt,SmallInt,MediumInt,Int,BigInt。 具体支持的字符串类型有:Char,Varchar,Text,TinyText,MediumText,LongText。 具体支持的 Blob 类型有:Blob,TinyBlob,MediumBlob,LongBlob。 在修改类型定义方面,支持的包括 default value,comment,null,not null 和 OnUpdate,但是不支持从 null 到 not null 的修改。 不支持对 enum 类型的列进行修改 LOCK [=] {DEFAULT|NONE|SHARED|EXCLUSIVE} 目前只是语法支持。 CREATE INDEX 语法 CREATE [UNIQUE] INDEX index_name [index_type] ON tbl_name (index_col_name,...) [index_option] ... index_col_name: col_name …"}, {"url": "https://pingcap.com/docs/tools/dm-worker-intro/", "title": "DM-worker Introduction", "content": " DM-worker Introduction DM-worker is a tool used to synchronize data from MySQL/MariaDB to TiDB.It has the following features: Acts as a slave of any MySQL or MariaDB server Reads the binlog events from MySQL/MariaDB and persists them to the local storage A single DM-worker supports synchronizing the data of one MySQL/MariaDB instance to multiple TiDB instances Multiple DM-workers support synchronizing the data of multiple MySQL/MariaDB instances to one TiDB instance DM-worker processing unit A DM-worker task contains multiple logic units, including relay log, Dumper, Loader, and binlog replication.Relay log The relay log persistently stores the binlog data from the upstream MySQL/MariaDB and provides the feature of accessing binlog events for the binlog replication.Its rationale and features are similar to the slave relay log of MySQL. For details, see The Slave Relay Log.Dumper Dumper dumps the full data from the upstream MySQL/MariaDB to the local disk.Loader Loader reads the files of Dumper and then loads these files to the downstream TiDB.Binlog replication/Syncer Binlog replication/Syncer reads the binlog events of the relay log, transforms these events to SQL statements, and then applies these statements to the downstream TiDB.Privileges required by DM-worker This section describes the upstream and downstream database users’ privileges required by DM-worker, and the user privileges required by the respective processing unit.Upstream database user privileges The upstream database (MySQL/MariaDB) user must have the following privileges: Privilege Scope SELECT Tables RELOAD Global REPLICATION SLAVE Global REPLICATION CLIENT Global If you need to synchronize the data from db1 to TiDB, execute the following GRANT statement:GRANT RELOAD,REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'your_user'@'your_wildcard_of_host' GRANT SELECT ON db1.* TO 'your_user'@'your_wildcard_of_host'; If you also need to synchronize the data from other databases into TiDB, make sure the same privileges are granted to the user of the respective databases.Downstream database user privileges The downstream database (TiDB) user must have the following privileges: Privilege Scope SELECT Tables INSERT Tables UPDATE Tables DELETE Tables CREATE Databases, tables DROP Databases, tables ALTER Tables INDEX Tables Execute the following GRANT statement for the databases or tables that you need to synchronize:GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP,ALTER,INDEX ON db.table TO 'your_user'@'your_wildcard_of_host'; Minimal privilege required by each processing unit Processing unit Minimal upstream (MySQL/MariaDB) privilege Minimal downstream (TiDB) privilege Minimal system privilege Relay log REPLICATION SLAVE (reads the binlog)REPLICATION CLIENT (show master status, show slave status) NULL Read/Write local files Dumper SELECTRELOAD (flushes tables with Read lock and unlocks tables) NULL Write local files Loader NULL SELECT (Query the checkpoint history)CREATE (creates a database/table)DELETE (deletes checkpoint)INSERT (Inserts the Dump data) Read/Write local files Binlog replication REPLICATION SLAVE (reads the binlog)REPLICATION CLIENT (show master status, show slave status) SELECT (shows the index and column)INSERT (DML)UPDATE (DML)DELETE (DML)CREATE (creates a database/table)DROP (drops databases/tables)ALTER (alters a table)INDEX (creates/drops an index) Read/Write local files Note: These privileges are not immutable and they change as the request changes. "}, {"url": "https://pingcap.com/docs/sql/ddl/", "title": "Data Definition Statements", "content": " Data Definition Statements DDL (Data Definition Language) is used to define the database structure or schema, and to manage the database and statements of various objects in the database.Currently, TiDB has implemented concurrent execution of the ADD INDEX operation and the GENERAL operation (namely the non-ADD INDEX DDL operation) across different tables. In this case, two workers process the ADD INDEX operation and a GENERAL operation respectively. When the operation requests are on the same table, workers execute these operations in the order of receiving the DDL operation requests. This feature is to guarantee the ADD INDEX operation (its execution time is longer than that of other operations in TiDB) does not block other DDL operations.CREATE DATABASE syntax CREATE {DATABASE | SCHEMA} [IF NOT EXISTS] db_name [create_specification] ... create_specification: [DEFAULT] CHARACTER SET [=] charset_name | [DEFAULT] COLLATE [=] collation_name The CREATE DATABASE statement is used to create a database, and to specify the default properties of the database, such as the default character set and validation rules. CREATE SCHEMA is a synonym for CREATE DATABASE.If you create an existing database and does not specify IF NOT EXISTS, an error is displayed.The create_specification option is used to specify the specific CHARACTER SET and COLLATE in the database. Currently, the option is only supported in syntax.DROP DATABASE syntax DROP {DATABASE | SCHEMA} [IF EXISTS] db_name The DROP DATABASE statement is used to delete the specified database and its tables.The IF EXISTS statement is used to prevent an error if the database does not exist.CREATE TABLE syntax CREATE TABLE [IF NOT EXISTS] tbl_name (create_definition,...) [table_options] CREATE TABLE [IF NOT EXISTS] tbl_name { LIKE old_tbl_name | (LIKE old_tbl_name) } create_definition: col_name column_definition | [CONSTRAINT [symbol]] PRIMARY KEY [index_type] (index_col_name,...) [index_option] ... | {INDEX|KEY} [index_name] [index_type] (index_col_name,...) [index_option] ... | [CONSTRAINT [symbol]] UNIQUE [INDEX|KEY] [index_name] [index_type] (index_col_name,...) [index_option] ... | {FULLTEXT} [INDEX|KEY] [index_name] (index_col_name,...) [index_option] ... | [CONSTRAINT [symbol]] FOREIGN KEY [index_name] (index_col_name,...) reference_definition column_definition: data_type [NOT NULL | NULL] [DEFAULT default_value] [AUTO_INCREMENT] [UNIQUE [KEY] | [PRIMARY] KEY] [COMMENT 'string'] [reference_definition] | data_type [GENERATED ALWAYS] AS (expression) [VIRTUAL | STORED] [UNIQUE [KEY]] [COMMENT comment] [NOT NULL | NULL] [[PRIMARY] KEY] data_type: BIT[(length)] | TINYINT[(length)] [UNSIGNED] [ZEROFILL] | SMALLINT[(length)] [UNSIGNED] [ZEROFILL] | MEDIUMINT[(length)] [UNSIGNED] [ZEROFILL] | INT[(length)] [UNSIGNED] [ZEROFILL] | INTEGER[(length)] [UNSIGNED] [ZEROFILL] | BIGINT[(length)] [UNSIGNED] [ZEROFILL] | REAL[(length,decimals)] [UNSIGNED] [ZEROFILL] | DOUBLE[(length,decimals)] [UNSIGNED] [ZEROFILL] | FLOAT[(length,decimals)] [UNSIGNED] [ZEROFILL] | DECIMAL[(length[,decimals])] [UNSIGNED] [ZEROFILL] | NUMERIC[(length[,decimals])] [UNSIGNED] [ZEROFILL] | DATE | TIME[(fsp)] | TIMESTAMP[(fsp)] | DATETIME[(fsp)] | YEAR | CHAR[(length)] [BINARY] [CHARACTER SET charset_name] [COLLATE collation_name] | VARCHAR(length) [BINARY] [CHARACTER SET charset_name] [COLLATE collation_name] | BINARY[(length)] | VARBINARY(length) | TINYBLOB | BLOB | MEDIUMBLOB | LONGBLOB | TINYTEXT [BINARY] [CHARACTER SET charset_name] [COLLATE collation_name] | TEXT [BINARY] [CHARACTER SET charset_name] [COLLATE collation_name] | MEDIUMTEXT [BINARY] [CHARACTER SET charset_name] [COLLATE collation_name] | LONGTEXT [BINARY] [CHARACTER SET charset_name] [COLLATE collation_name] | ENUM(value1,value2,value3,...) [CHARACTER SET charset_name] [COLLATE collation_name] | SET(value1,value2,value3,...) [CHARACTER SET charset_name] [COLLATE collation_name] | JSON index_col_name: col_name [(length)] [ASC | DESC] index_type: USING {BTREE | HASH} index_option: KEY_BLOCK_SIZE [=] value | index_type | COMMENT 'string' reference_definition: REFERENCES tbl_name (index_col_name,...) [MATCH FULL | MATCH PARTIAL | MATCH SIMPLE] [ON DELETE reference_option] [ON UPDATE reference_option] reference_option: RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT table_options: table_option [[,] table_option] ... table_option: AUTO_INCREMENT [=] value | AVG_ROW_LENGTH [=] value | [DEFAULT] CHARACTER SET [=] charset_name | CHECKSUM [=] {0 | 1} | [DEFAULT] COLLATE [=] collation_name | COMMENT [=] 'string' | COMPRESSION [=] {'ZLIB'|'LZ4'|'NONE'} | CONNECTION [=] 'connect_string' | DELAY_KEY_WRITE [=] {0 | 1} | ENGINE [=] engine_name | KEY_BLOCK_SIZE [=] value | MAX_ROWS [=] value | MIN_ROWS [=] value | ROW_FORMAT [=] {DEFAULT|DYNAMIC|FIXED|COMPRESSED|REDUNDANT|COMPACT} | STATS_PERSISTENT [=] {DEFAULT|0|1} The CREATE TABLE statement is used to create a table. Currently, it does not support temporary tables, CHECK constraints, or importing data from other tables while creating tables. It supports some of the Partition_options in syntax. When you create an existing table and if you specify IF NOT EXIST, it does not report an error. Otherwise, it reports an error. Use LIKE to create an empty table based on the definition of another table including its column and index properties. The FULLTEXT and FOREIGN KEY in create_definition are currently only supported in syntax. For the data_type, see Data Types. The [ASC | DESC] in index_col_name is currently only supported in syntax. The index_type is currently only supported in syntax. The KEY_BLOCK_SIZE in index_option is currently only supported in syntax. The table_option currently only supports AUTO_INCREMENT, CHARACTER SET and COMMENT, while the others are only supported in syntax. The clauses are separated by a comma ,. See the following table for details: Parameters Description Example AUTO_INCREMENT The initial value of the increment field AUTO_INCREMENT = 5 CHARACTER SET To specify the string code for the table; currently only support UTF8MB4 CHARACTER SET = ‘utf8mb4’ COMMENT The comment information COMMENT = ‘comment info’ AUTO_INCREMENT description The TiDB automatic increment ID (AUTO_INCREMENT ID) only guarantees automatic increment and uniqueness and does not guarantee continuous allocation. Currently, TiDB adopts bulk allocation. If you insert data into multiple TiDB servers at the same time, the allocated automatic increment ID is not continuous.You can specify the AUTO_INCREMENT for integer fields. A table only supports one field with the AUTO_INCREMENT property.DROP TABLE syntax DROP TABLE [IF EXISTS] tbl_name [, tbl_name] ... [RESTRICT | CASCADE] You can delete multiple tables at the same time. The tables are separated by a comma ,.If you delete a table that does not exist and does not specify the use of IF EXISTS, an error is displayed.The RESTRICT and CASCADE keywords do nothing. They are permitted to make porting easier from other database systems.TRUNCATE TABLE syntax TRUNCATE [TABLE] tbl_name The TRUNCATE TABLE statement is used to clear all the data in the specified table but keeps the table structure.This operation is similar to deleting all the data of a specified table, but it is much faster and is not affected by the number of rows in the table. Note: If you use the TRUNCATE TABLE statement, the value of AUTO_INCREMENT in the original table is reset to its starting value. RENAME TABLE syntax RENAME TABLE tbl_name TO new_tbl_name The RENAME TABLE statement is used to rename a table.This statement is equivalent to the following ALTER TABLE statement:ALTER TABLE old_table RENAME new_table; ALTER TABLE syntax ALTER TABLE tbl_name [alter_specification] alter_specification: table_options | ADD [COLUMN] col_name column_definition [FIRST | AFTER col_name] | ADD [COLUMN] (col_name column_definition,...) | ADD {INDEX|KEY} …"}, {"url": "https://pingcap.com/docs/v1.0/sql/ddl/", "title": "Data Definition Statements", "content": " Data Definition Statements DDL (Data Definition Language) is used to define the database structure or schema, and to manage the database and statements of various objects in the database.CREATE DATABASE syntax CREATE {DATABASE | SCHEMA} [IF NOT EXISTS] db_name [create_specification] ... create_specification: [DEFAULT] CHARACTER SET [=] charset_name | [DEFAULT] COLLATE [=] collation_name The CREATE DATABASE statement is used to create a database, and to specify the default properties of the database, such as the default character set and validation rules. CREATE SCHEMA is a synonym for CREATE DATABASE.If you create an existing database and does not specify IF NOT EXISTS, an error is displayed.The create_specification option is used to specify the specific CHARACTER SET and COLLATE in the database. Currently, the option is only supported in syntax.DROP DATABASE syntax DROP {DATABASE | SCHEMA} [IF EXISTS] db_name The DROP DATABASE statement is used to delete the specified database and its tables.The IF EXISTS statement is used to prevent an error if the database does not exist.CREATE TABLE syntax CREATE TABLE [IF NOT EXISTS] tbl_name (create_definition,...) [table_options] CREATE TABLE [IF NOT EXISTS] tbl_name { LIKE old_tbl_name | (LIKE old_tbl_name) } create_definition: col_name column_definition | [CONSTRAINT [symbol]] PRIMARY KEY [index_type] (index_col_name,...) [index_option] ... | {INDEX|KEY} [index_name] [index_type] (index_col_name,...) [index_option] ... | [CONSTRAINT [symbol]] UNIQUE [INDEX|KEY] [index_name] [index_type] (index_col_name,...) [index_option] ... | {FULLTEXT} [INDEX|KEY] [index_name] (index_col_name,...) [index_option] ... | [CONSTRAINT [symbol]] FOREIGN KEY [index_name] (index_col_name,...) reference_definition column_definition: data_type [NOT NULL | NULL] [DEFAULT default_value] [AUTO_INCREMENT] [UNIQUE [KEY] | [PRIMARY] KEY] [COMMENT 'string'] [reference_definition] | data_type [GENERATED ALWAYS] AS (expression) [VIRTUAL | STORED] [UNIQUE [KEY]] [COMMENT comment] [NOT NULL | NULL] [[PRIMARY] KEY] data_type: BIT[(length)] | TINYINT[(length)] [UNSIGNED] [ZEROFILL] | SMALLINT[(length)] [UNSIGNED] [ZEROFILL] | MEDIUMINT[(length)] [UNSIGNED] [ZEROFILL] | INT[(length)] [UNSIGNED] [ZEROFILL] | INTEGER[(length)] [UNSIGNED] [ZEROFILL] | BIGINT[(length)] [UNSIGNED] [ZEROFILL] | REAL[(length,decimals)] [UNSIGNED] [ZEROFILL] | DOUBLE[(length,decimals)] [UNSIGNED] [ZEROFILL] | FLOAT[(length,decimals)] [UNSIGNED] [ZEROFILL] | DECIMAL[(length[,decimals])] [UNSIGNED] [ZEROFILL] | NUMERIC[(length[,decimals])] [UNSIGNED] [ZEROFILL] | DATE | TIME[(fsp)] | TIMESTAMP[(fsp)] | DATETIME[(fsp)] | YEAR | CHAR[(length)] [BINARY] [CHARACTER SET charset_name] [COLLATE collation_name] | VARCHAR(length) [BINARY] [CHARACTER SET charset_name] [COLLATE collation_name] | BINARY[(length)] | VARBINARY(length) | TINYBLOB | BLOB | MEDIUMBLOB | LONGBLOB | TINYTEXT [BINARY] [CHARACTER SET charset_name] [COLLATE collation_name] | TEXT [BINARY] [CHARACTER SET charset_name] [COLLATE collation_name] | MEDIUMTEXT [BINARY] [CHARACTER SET charset_name] [COLLATE collation_name] | LONGTEXT [BINARY] [CHARACTER SET charset_name] [COLLATE collation_name] | ENUM(value1,value2,value3,...) [CHARACTER SET charset_name] [COLLATE collation_name] | SET(value1,value2,value3,...) [CHARACTER SET charset_name] [COLLATE collation_name] | JSON index_col_name: col_name [(length)] [ASC | DESC] index_type: USING {BTREE | HASH} index_option: KEY_BLOCK_SIZE [=] value | index_type | COMMENT 'string' reference_definition: REFERENCES tbl_name (index_col_name,...) [MATCH FULL | MATCH PARTIAL | MATCH SIMPLE] [ON DELETE reference_option] [ON UPDATE reference_option] reference_option: RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT table_options: table_option [[,] table_option] ... table_option: AUTO_INCREMENT [=] value | AVG_ROW_LENGTH [=] value | [DEFAULT] CHARACTER SET [=] charset_name | CHECKSUM [=] {0 | 1} | [DEFAULT] COLLATE [=] collation_name | COMMENT [=] 'string' | COMPRESSION [=] {'ZLIB'|'LZ4'|'NONE'} | CONNECTION [=] 'connect_string' | DELAY_KEY_WRITE [=] {0 | 1} | ENGINE [=] engine_name | KEY_BLOCK_SIZE [=] value | MAX_ROWS [=] value | MIN_ROWS [=] value | ROW_FORMAT [=] {DEFAULT|DYNAMIC|FIXED|COMPRESSED|REDUNDANT|COMPACT} | STATS_PERSISTENT [=] {DEFAULT|0|1} The CREATE TABLE statement is used to create a table. Currently, it does not support temporary tables, CHECK constraints, or importing data from other tables while creating tables. It supports some of the Partition_options in syntax. When you create an existing table and if you specify IF NOT EXIST, it does not report an error. Otherwise, it reports an error. Use LIKE to create an empty table based on the definition of another table including its column and index properties. The FULLTEXT and FOREIGN KEY in create_definition are currently only supported in syntax. For the data_type, see Data Types. The [ASC | DESC] in index_col_name is currently only supported in syntax. The index_type is currently only supported in syntax. The KEY_BLOCK_SIZE in index_option is currently only supported in syntax. The table_option currently only supports AUTO_INCREMENT, CHARACTER SET and COMMENT, while the others are only supported in syntax. The clauses are separated by a comma ,. See the following table for details: Parameters Description Example AUTO_INCREMENT The initial value of the increment field AUTO_INCREMENT = 5 CHARACTER SET To specify the string code for the table; currently only support UTF8MB4 CHARACTER SET = ‘utf8mb4’ COMMENT The comment information COMMENT = ‘comment info’ AUTO_INCREMENT description The TiDB automatic increment ID (AUTO_INCREMENT ID) only guarantees automatic increment and uniqueness and does not guarantee continuous allocation. Currently, TiDB adopts bulk allocation. If you insert data into multiple TiDB servers at the same time, the allocated automatic increment ID is not continuous.You can specify the AUTO_INCREMENT for integer fields. A table only supports one field with the AUTO_INCREMENT property.DROP TABLE syntax DROP TABLE [IF EXISTS] tbl_name [, tbl_name] ... [RESTRICT | CASCADE] You can delete multiple tables at the same time. The tables are separated by a comma ,.If you delete a table that does not exist and does not specify the use of IF EXISTS, an error is displayed.The RESTRICT and CASCADE keywords do nothing. They are permitted to make porting easier from other database systems.TRUNCATE TABLE syntax TRUNCATE [TABLE] tbl_name The TRUNCATE TABLE statement is used to clear all the data in the specified table but keeps the table structure.This operation is similar to deleting all the data of a specified table, but it is much faster and is not affected by the number of rows in the table. Note: If you use the TRUNCATE TABLE statement, the value of AUTO_INCREMENT in the original table is reset to its starting value. RENAME TABLE syntax RENAME TABLE tbl_name TO new_tbl_name The RENAME TABLE statement is used to rename a table.This statement is equivalent to the following ALTER TABLE statement:ALTER TABLE old_table RENAME new_table; ALTER TABLE syntax ALTER TABLE tbl_name [alter_specification] alter_specification: table_options | ADD [COLUMN] col_name column_definition [FIRST | AFTER col_name] | ADD [COLUMN] (col_name column_definition,...) | ADD {INDEX|KEY} [index_name] [index_type] (index_col_name,...) [index_option] ... | ADD [CONSTRAINT [symbol]] PRIMARY KEY [index_type] (index_col_name,...) [index_option] ... | ADD [CONSTRAINT [symbol]] UNIQUE [INDEX|KEY] [index_name] [index_type] (index_col_name,...) [index_option] ... | ADD FULLTEXT [INDEX|KEY] [index_name] (index_col_name,...) [index_option] ... | ADD [CONSTRAINT [symbol]] FOREIGN KEY [index_name] (index_col_name,...) reference_definition | ALTER [COLUMN] col_name {SET DEFAULT literal | DROP DEFAULT} | CHANGE [COLUMN] old_col_name new_col_name …"}, {"url": "https://pingcap.com/docs/v2.0/sql/ddl/", "title": "Data Definition Statements", "content": " Data Definition Statements DDL (Data Definition Language) is used to define the database structure or schema, and to manage the database and statements of various objects in the database.CREATE DATABASE syntax CREATE {DATABASE | SCHEMA} [IF NOT EXISTS] db_name [create_specification] ... create_specification: [DEFAULT] CHARACTER SET [=] charset_name | [DEFAULT] COLLATE [=] collation_name The CREATE DATABASE statement is used to create a database, and to specify the default properties of the database, such as the default character set and validation rules. CREATE SCHEMA is a synonym for CREATE DATABASE.If you create an existing database and does not specify IF NOT EXISTS, an error is displayed.The create_specification option is used to specify the specific CHARACTER SET and COLLATE in the database. Currently, the option is only supported in syntax.DROP DATABASE syntax DROP {DATABASE | SCHEMA} [IF EXISTS] db_name The DROP DATABASE statement is used to delete the specified database and its tables.The IF EXISTS statement is used to prevent an error if the database does not exist.CREATE TABLE syntax CREATE TABLE [IF NOT EXISTS] tbl_name (create_definition,...) [table_options] CREATE TABLE [IF NOT EXISTS] tbl_name { LIKE old_tbl_name | (LIKE old_tbl_name) } create_definition: col_name column_definition | [CONSTRAINT [symbol]] PRIMARY KEY [index_type] (index_col_name,...) [index_option] ... | {INDEX|KEY} [index_name] [index_type] (index_col_name,...) [index_option] ... | [CONSTRAINT [symbol]] UNIQUE [INDEX|KEY] [index_name] [index_type] (index_col_name,...) [index_option] ... | {FULLTEXT} [INDEX|KEY] [index_name] (index_col_name,...) [index_option] ... | [CONSTRAINT [symbol]] FOREIGN KEY [index_name] (index_col_name,...) reference_definition column_definition: data_type [NOT NULL | NULL] [DEFAULT default_value] [AUTO_INCREMENT] [UNIQUE [KEY] | [PRIMARY] KEY] [COMMENT 'string'] [reference_definition] | data_type [GENERATED ALWAYS] AS (expression) [VIRTUAL | STORED] [UNIQUE [KEY]] [COMMENT comment] [NOT NULL | NULL] [[PRIMARY] KEY] data_type: BIT[(length)] | TINYINT[(length)] [UNSIGNED] [ZEROFILL] | SMALLINT[(length)] [UNSIGNED] [ZEROFILL] | MEDIUMINT[(length)] [UNSIGNED] [ZEROFILL] | INT[(length)] [UNSIGNED] [ZEROFILL] | INTEGER[(length)] [UNSIGNED] [ZEROFILL] | BIGINT[(length)] [UNSIGNED] [ZEROFILL] | REAL[(length,decimals)] [UNSIGNED] [ZEROFILL] | DOUBLE[(length,decimals)] [UNSIGNED] [ZEROFILL] | FLOAT[(length,decimals)] [UNSIGNED] [ZEROFILL] | DECIMAL[(length[,decimals])] [UNSIGNED] [ZEROFILL] | NUMERIC[(length[,decimals])] [UNSIGNED] [ZEROFILL] | DATE | TIME[(fsp)] | TIMESTAMP[(fsp)] | DATETIME[(fsp)] | YEAR | CHAR[(length)] [BINARY] [CHARACTER SET charset_name] [COLLATE collation_name] | VARCHAR(length) [BINARY] [CHARACTER SET charset_name] [COLLATE collation_name] | BINARY[(length)] | VARBINARY(length) | TINYBLOB | BLOB | MEDIUMBLOB | LONGBLOB | TINYTEXT [BINARY] [CHARACTER SET charset_name] [COLLATE collation_name] | TEXT [BINARY] [CHARACTER SET charset_name] [COLLATE collation_name] | MEDIUMTEXT [BINARY] [CHARACTER SET charset_name] [COLLATE collation_name] | LONGTEXT [BINARY] [CHARACTER SET charset_name] [COLLATE collation_name] | ENUM(value1,value2,value3,...) [CHARACTER SET charset_name] [COLLATE collation_name] | SET(value1,value2,value3,...) [CHARACTER SET charset_name] [COLLATE collation_name] | JSON index_col_name: col_name [(length)] [ASC | DESC] index_type: USING {BTREE | HASH} index_option: KEY_BLOCK_SIZE [=] value | index_type | COMMENT 'string' reference_definition: REFERENCES tbl_name (index_col_name,...) [MATCH FULL | MATCH PARTIAL | MATCH SIMPLE] [ON DELETE reference_option] [ON UPDATE reference_option] reference_option: RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT table_options: table_option [[,] table_option] ... table_option: AUTO_INCREMENT [=] value | AVG_ROW_LENGTH [=] value | [DEFAULT] CHARACTER SET [=] charset_name | CHECKSUM [=] {0 | 1} | [DEFAULT] COLLATE [=] collation_name | COMMENT [=] 'string' | COMPRESSION [=] {'ZLIB'|'LZ4'|'NONE'} | CONNECTION [=] 'connect_string' | DELAY_KEY_WRITE [=] {0 | 1} | ENGINE [=] engine_name | KEY_BLOCK_SIZE [=] value | MAX_ROWS [=] value | MIN_ROWS [=] value | ROW_FORMAT [=] {DEFAULT|DYNAMIC|FIXED|COMPRESSED|REDUNDANT|COMPACT} | STATS_PERSISTENT [=] {DEFAULT|0|1} The CREATE TABLE statement is used to create a table. Currently, it does not support temporary tables, CHECK constraints, or importing data from other tables while creating tables. It supports some of the Partition_options in syntax. When you create an existing table and if you specify IF NOT EXIST, it does not report an error. Otherwise, it reports an error. Use LIKE to create an empty table based on the definition of another table including its column and index properties. The FULLTEXT and FOREIGN KEY in create_definition are currently only supported in syntax. For the data_type, see Data Types. The [ASC | DESC] in index_col_name is currently only supported in syntax. The index_type is currently only supported in syntax. The KEY_BLOCK_SIZE in index_option is currently only supported in syntax. The table_option currently only supports AUTO_INCREMENT, CHARACTER SET and COMMENT, while the others are only supported in syntax. The clauses are separated by a comma ,. See the following table for details: Parameters Description Example AUTO_INCREMENT The initial value of the increment field AUTO_INCREMENT = 5 CHARACTER SET To specify the string code for the table; currently only support UTF8MB4 CHARACTER SET = ‘utf8mb4’ COMMENT The comment information COMMENT = ‘comment info’ AUTO_INCREMENT description The TiDB automatic increment ID (AUTO_INCREMENT ID) only guarantees automatic increment and uniqueness and does not guarantee continuous allocation. Currently, TiDB adopts bulk allocation. If you insert data into multiple TiDB servers at the same time, the allocated automatic increment ID is not continuous.You can specify the AUTO_INCREMENT for integer fields. A table only supports one field with the AUTO_INCREMENT property.DROP TABLE syntax DROP TABLE [IF EXISTS] tbl_name [, tbl_name] ... [RESTRICT | CASCADE] You can delete multiple tables at the same time. The tables are separated by a comma ,.If you delete a table that does not exist and does not specify the use of IF EXISTS, an error is displayed.The RESTRICT and CASCADE keywords do nothing. They are permitted to make porting easier from other database systems.TRUNCATE TABLE syntax TRUNCATE [TABLE] tbl_name The TRUNCATE TABLE statement is used to clear all the data in the specified table but keeps the table structure.This operation is similar to deleting all the data of a specified table, but it is much faster and is not affected by the number of rows in the table. Note: If you use the TRUNCATE TABLE statement, the value of AUTO_INCREMENT in the original table is reset to its starting value. RENAME TABLE syntax RENAME TABLE tbl_name TO new_tbl_name The RENAME TABLE statement is used to rename a table.This statement is equivalent to the following ALTER TABLE statement:ALTER TABLE old_table RENAME new_table; ALTER TABLE syntax ALTER TABLE tbl_name [alter_specification] alter_specification: table_options | ADD [COLUMN] col_name column_definition [FIRST | AFTER col_name] | ADD [COLUMN] (col_name column_definition,...) | ADD {INDEX|KEY} [index_name] [index_type] (index_col_name,...) [index_option] ... | ADD [CONSTRAINT [symbol]] PRIMARY KEY [index_type] (index_col_name,...) [index_option] ... | ADD [CONSTRAINT [symbol]] UNIQUE [INDEX|KEY] [index_name] [index_type] (index_col_name,...) [index_option] ... | ADD FULLTEXT [INDEX|KEY] [index_name] (index_col_name,...) [index_option] ... | ADD [CONSTRAINT [symbol]] FOREIGN KEY [index_name] (index_col_name,...) reference_definition | ALTER [COLUMN] col_name {SET DEFAULT literal | DROP DEFAULT} | CHANGE [COLUMN] old_col_name new_col_name …"}, {"url": "https://pingcap.com/docs/tools/data-migration-cluster-operations/", "title": "Data Migration Cluster Operations", "content": " Data Migration Cluster Operations This document introduces the DM cluster operations and considerations when you administer a DM cluster using DM-Ansible.Start a cluster Run the following command to start all the components (including DM-master, DM-worker and the monitoring component) of the whole DM cluster:$ ansible-playbook start.yml Stop a cluster Run the following command to stop all the components (including DM-master, DM-worker and the monitoring component) of the whole DM cluster:$ ansible-playbook stop.yml Restart cluster components You need to update the DM cluster components in the following cases: You want to upgrade the component version. A serious bug occurs and you have to restart the component for temporary recovery. The machine that the DM cluster is located in is restarted for certain reasons. Restarting considerations This sections describes the considerations that you need to know when you restart DM components.Restarting DM-worker considerations In the process of full data loading:For the SQL files during full data import, DM uses the downstream database to record the checkpoint information. When DM-worker is restarted, it checks the checkpoint information and you can use the start-task command to recover the data synchronization task automatically.In the process of incremental data synchronization:For the binlog during incremental data import, DM uses the downstream database to record the checkpoint information, and enables the safe mode within the first 5 minutes after the synchronization task is started or recovered. Sharding DDL statements synchronization is not enabledIf the sharding DDL statements synchronization is not enabled in the task running on DM-worker, when DM-worker is restarted, it checks the checkpoint information and you can use the start-task command to recover the data synchronization task automatically. Sharding DDL statements synchronization is enabled When DM is synchronizing the sharding DDL statements, if DM-worker successfully executes (or skips) the sharding DDL binlog event, then the checkpoints of all tables related to sharding DDL in the DM-worker are updated to the position after the binlog event corresponding to the DDL statement. When DM-worker is restarted before or after synchronizing sharding DDL statements, it checks the checkpoint information and you can use the start-task command to recover the data synchronization task automatically. When DM-worker is restarted during the process of synchronizing sharding DDL statements, the issue might occur that the DM-worker owner has executed the DDL statement and successfully changed the downstream database table schema, while other DM-worker instances are restarted but fail to skip the DDL statement and update the checkpoints.At this time, DM tries again to synchronize these DDL statements that are not skipped. However, the restarted DM-worker instances will be blocked at the position of the binlog event corresponding to the DDL binlog event, because the DM-worker instance that is not restarted has executed to the place after this DDL binlog event.To resolve this issue, follow the steps described in Troubleshooting Sharding DDL Locks Restarting DM-master considerations The information maintained by DM-master includes the following two major types, and these data are not being persisted when you restart DM-master. The corresponding relationship between the task and DM-worker The sharding DDL lock related information When DM-master is restarted, it automatically requests the task information from each DM-worker instance and rebuilds the corresponding relationship between the task and DM-worker. However, at this time, DM-worker does not resend the sharding DDL information, so it might occur that the sharding DDL lock synchronization cannot be finished automatically because of the lost lock information.To resolve this issue, follow the steps described in Troubleshooting Sharding DDL Locks.Restarting dmctl considerations The dmctl component is stateless. You can restart it at any time you like.Restart DM-worker Note: Try to avoid restarting DM-worker during the process of synchronizing sharding DDL statements. To restart the DM-worker component, you can use either of the following two approaches: Perform a rolling update on DM-worker$ ansible-playbook rolling_update.yml --tags=dm-worker Stop DM-worker first and then restart it$ ansible-playbook stop.yml --tags=dm-worker $ ansible-playbook start.yml --tags=dm-worker Restart DM-master Note: Try to avoid restarting DM-master during the process of synchronizing sharding DDL statements. To restart the DM-master component, you can use either of the following two approaches: Perform a rolling update on DM-master$ ansible-playbook rolling_update.yml --tags=dm-master Stop DM-master first and then restart it$ ansible-playbook stop.yml --tags=dm-master $ ansible-playbook start.yml --tags=dm-master Restart dmctl To stop and restart dmctl, use the following command, instead of using DM-Ansible:$ exit # Stops the running dmctl $ sh dmctl.sh # Restart dmctl Upgrade the component version Download the DM binary file. Delete the existing file in the downloads directory.$ cd /home/tidb/dm-ansible $ rm -rf downloads Use Playbook to download the latest DM binary file and replace the existing binary in the /home/tidb/dm-ansible/resource/bin/ directory with it automatically.$ ansible-playbook local_prepare.yml Use Ansible to perform the rolling update. Perform a rolling update on the DM-worker instance:ansible-playbook rolling_update.yml --tags=dm-worker Perform a rolling update on the DM-master instance:ansible-playbook rolling_update.yml --tags=dm-master Upgrade dmctl:ansible-playbook rolling_update.yml --tags=dmctl Perform a rolling update on DM-worker, DM-master and dmctl:ansible-playbook rolling_update.yml Add a DM-worker instance Assuming that you want to add a DM-worker instance on the 172.16.10.74 machine and the alias of the instance is dm_worker3, perform the following steps: Configure the SSH mutual trust and sudo rules on the Control Machine. Refer to Configure the SSH mutual trust and sudo rules on the Control Machine, log in to the Control Machine using the tidb user account and add 172.16.10.74 to the [servers] section of the hosts.ini file.$ cd /home/tidb/dm-ansible $ vi hosts.ini [servers] 172.16.10.74 [all:vars] username = tidb Run the following command and enter the root user password for deploying 172.16.10.74 according to the prompt.$ ansible-playbook -i hosts.ini create_users.yml -u root -k This step creates a tidb user on the 172.16.10.74 machine, and configures sudo rules and the SSH mutual trust between the Control Machine and the 172.16.10.74 machine. Edit the inventory.ini file and add the new DM-worker instance dm_worker3.[dm_worker_servers] dm_worker1 ansible_host=172.16.10.72 server_id=101 mysql_host=172.16.10.81 mysql_user=root mysql_password='VjX8cEeTX+qcvZ3bPaO4h0C80pe/1aU=' mysql_port=3306 dm_worker2 ansible_host=172.16.10.73 server_id=102 mysql_host=172.16.10.82 mysql_user=root mysql_password='VjX8cEeTX+qcvZ3bPaO4h0C80pe/1aU=' mysql_port=3306 dm_worker3 ansible_host=172.16.10.74 server_id=103 mysql_host=172.16.10.83 mysql_user=root mysql_password='VjX8cEeTX+qcvZ3bPaO4h0C80pe/1aU=' mysql_port=3306 Deploy the new DM-worker instance.$ ansible-playbook deploy.yml --tags=dm-worker -l dm_worker3 Start the new DM-worker instance.$ ansible-playbook start.yml --tags=dm-worker -l dm_worker3 Configure and restart the DM-master service.$ ansible-playbook rolling_update.yml --tags=dm-master Configure and restart the Prometheus service.$ ansible-playbook rolling_update_monitor.yml --tags=prometheus Remove a DM-worker instance Assuming that you want to remove the dm_worker3 instance, perform the following steps: Stop the DM-worker instance that you need to remove.$ ansible-playbook stop.yml --tags=dm-worker -l dm_worker3 Edit the inventory.ini file and comment or …"}, {"url": "https://pingcap.com/docs/tools/dm-configuration-file-overview/", "title": "Data Migration Configuration File Overview", "content": " Data Migration Configuration File Overview This document gives an overview of configuration files of DM (Data Migration).DM process configuration files inventory.ini: The configuration file of deploying DM using DM-Ansible. You need to edit it based on your machine topology. For details, see Edit the inventory.ini file to orchestrate the DM cluster. dm-master.toml: The configuration file of running the DM-master process, including the topology information of the DM cluster and the corresponding relationship between the MySQL instance and DM-worker (must be one-to-one relationship). When you use DM-Ansible to deploy DM, dm-master.toml is generated automatically. dm-worker.toml: The configuration file of running the DM-worker process, including the configuration information of upstream MySQL instance. When you use DM-Ansible to deploy DM, dm-worker.toml is generated automatically. DM synchronization task configuration DM task configuration file When you use DM-Ansible to deploy DM, you can find the following task configuration file template in <path-to-dm-ansible>/conf: task.yaml.exmaple: The standard configuration file of the data synchronization task (a specific task corresponds to a task.yaml). For the introduction of the configuration file, see Task Configuration File. Data synchronization task creation You can perform the following steps to create a data synchronization task based on task.yaml.example: Copy task.yaml.example as your_task.yaml. Refer to the description in the Task Configuration File and modify the configuration in your_task.yaml. Create your data synchronization task using dmctl. Important concepts This section shows description of some important concepts. Concept Description Configuration File instance-id Specifies a MySQL/MariaDB instance (if you deploy DM using DM-ansible, host:port is used to construct this ID) mysql-instance of dm-master.toml;instance-id of task.yaml DM-worker ID Specifies a DM-worker (from the worker-addr parameter of dm-worker.toml) worker-addr of dm-worker.toml;the -worker/-w flag of the dmctl command line Note: You must keep mysql-instance and DM-worker at a one-to-one relationship. "}, {"url": "https://pingcap.com/docs/tools/dm-monitor/", "title": "Data Migration Monitoring Metrics", "content": " Data Migration Monitoring Metrics If your DM cluster is deployed using DM-Ansible, the monitoring system is also deployed at the same time. This document describes the monitoring metrics provided by DM-worker. Note: Currently, DM-master does not provide monitoring metrics yet. Task Metric name Description Alert task state the state of subtasks 10 minutes after subtasks become paused Relay log Metric name Description Alert storage capacity The storage capacity of the disk occupied by the relay log N/A storage remain The remaining storage capacity of the disk occupied by the relay log An alert is needed once the value is smaller than 10G. process exits with error The relay log encounters an error within the DM-worker and exits. Immediate alerts relay log data corruption The number of corrupted relay log files Immediate alerts fail to read binlog from master The number of errors encountered when the relay log reads the binlog from the upstream MySQL Immediate alerts fail to write relay log The number of errors encountered when the relay log writes the binlog to disks Immediate alerts binlog file index The largest index number of relay log files. For example, “value = 1” indicates “relay-log.000001”. N/A binlog file gap between master and relay The number of binlog files in the relay log that are behind the upstream master When the number of binlog files in relay that are behind the upstream master exceeds one (>1) and the condition lasts over 10 minutes binlog pos The write offset of the latest relay log file N/A read binlog duration The duration that the relay log reads binlog from the upstream MySQL (in seconds) N/A write relay log duration The duration that the relay log writes binlog into the disks each time (in seconds) N/A binlog size The size of a single binlog event that the relay log writes into the disks N/A Dumper The following metric shows only when task-mode is in the full or all mode. Metric name Description Alert dump process exits with error Dumper encounters an error within the DM-worker and exits. Immediate alerts Loader The following metrics show only when task-mode is in the full or all mode. Metric name Description Alert load progress The data import process percentage of Loader. The value range is 0% ~ 100%. N/A data file size The total size of the data files in the full data imported by Loader (including the INSERT INTO statement) N/A load process exits with error Loader encounters an error within the DM-worker and exits. Immediate alerts table count The total number of tables in the full data imported by Loader N/A data file count The total number of data files in the full data imported by Loader (including the INSERT INTO statement) N/A latency of execute transaction The duration that Loader executes a transaction (in seconds) N/A latency of query The duration that Loader executes a query (in seconds) N/A Binlog replication The following metrics show only when task-mode is in the incremental or all mode. Metric name Description Alert remaining time to sync The predicted remaining time it takes Syncer to be completely synchronized with the master (in minutes) N/A replicate lag The latency time it takes to replicate the binlog from master to Syncer (in seconds) N/A process exist with error The binlog replication process encounters an error within the DM-worker and exits. Immediate alerts binlog file gap between master and syncer The number of binlog files in Syncer that are behind the master When the number of binlog files in Syncer that are behind the master exceeds one (>1) and the condition lasts over 10 minutes binlog file gap between relay and syncer The number of binlog files in Syncer that are behind relay When the number of binlog files in Syncer that are behind relay exceeds one (>1) and the condition lasts over 10 minutes binlog event qps The number of binlog events received per unit of time (this number does not include the events that need to be skipped) N/A skipped binlog event qps The number of binlog events received per unit of time that need to be skipped N/A cost of binlog event transform The time it takes Syncer to parse and transform the binlog into SQL statements (in seconds) N/A total sqls jobs The number of newly added jobs per unit of time N/A finished sqls jobs The number of finished jobs per unit of time N/A execution latency The time it takes Syncer to execute the transaction to the downstream (in seconds) N/A "}, {"url": "https://pingcap.com/docs/tools/data-migration-overview/", "title": "Data Migration Overview", "content": " Data Migration Overview Data Migration (DM) is an integrated data synchronization task management platform that supports the full data migration and the incremental data migration from MySQL/MariaDB into TiDB. It can help to reduce the operations cost and simplify the troubleshooting process.Architecture The Data Migration tool includes three components: DM-master, DM-worker, and dmctl.DM-master DM-master manages and schedules the operation of data synchronization tasks. Storing the topology information of the DM cluster Monitoring the running state of DM-worker processes Monitoring the running state of data synchronization tasks Providing a unified portal for the management of data synchronization tasks Coordinating the DDL synchronization of sharded tables in each instance under the sharding scenario DM-worker DM-worker executes specific data synchronization tasks. Persisting the binlog data to the local storage Storing the configuration information of the data synchronization subtasks Orchestrating the operation of the data synchronization subtasks Monitoring the running state of the data synchronization subtasks For details about DM-worker, see DM-worker Introduction.dmctl dmctl is the command line tool used to control the DM cluster. Creating/Updating/Dropping data synchronization tasks Checking the state of data synchronization tasks Handling the errors during data synchronization tasks Verifying the configuration correctness of data synchronization tasks Data synchronization introduction This section describes the data synchronization feature provided by Data Migration in detail.Black and white lists synchronization at the schema and table levels The black and white lists filtering rule of the upstream database instances is similar to MySQL replication-rules-db/tables, which can be used to filter or only synchronize all operations of some databases or some tables.Binlog event filtering Binlog event filtering is a more fine-grained filtering rule than the black and white lists filtering rule at the schema and table levels. You can use statements like INSERT and TRUNCATE TABLE to specify the Binlog events of the database(s) or table(s) that you need to synchronize or filter out.Column mapping Column mapping is used to resolve the conflicts occurred when the sharding auto-increment primary key IDs are merged for sharded tables. The value of the auto-increment primary key ID can be modified according to the instance-id, which is configured by the user, and the schema/table ID.Sharding support DM supports merging the original sharded instances and tables into TiDB, with some restrictions.Incompatible DDL handling Currently, TiDB is not compatible with all the DDL statements that MySQL supports. See the DDL statements supported by TiDB.DM reports an error when it encounters an incompatible DDL statement. To solve this error, you need to manually handle it using dmctl, either skipping this DDL statement or replacing it with a specified DDL statement(s). For details, see Skip or replace abnormal SQL statements."}, {"url": "https://pingcap.com/docs/tools/dm-sharding-solution/", "title": "Data Migration Sharding Solution", "content": " Data Migration Sharding Solution This document introduces the sharding solution provided by Data Migration, its background, design details, and sharding DDL restrictions.Data Migration supports merging the data of multiple sharded MySQL instances and tables into a single TiDB instance. Generally, Data Migration does it automatically and you need to do nothing. But when some abnormal conditions occur, you need to handle them manually. For details, see Troubleshooting Sharding DDL Locks.Background Currently, Syncer adopts the ROW format of binlog that does not contain the column name. The ROW format of binlog has the nature of self-description on a single machine. In this case, only one binlog updates the target database, and the column values corresponding to the newly added or modified column can be determined according to the downstream table schema, so the DML statements can be constructed correctly.However, in the case of merging multiple sharded instances and tables, multiple binlogs update the target database, and the DDL statements cannot be completely updated synchronously, so the DML statements might be inconsistent with the table schema.Here is an example:Assume that the table schema is as below:( `id` int(11) primary key ) When the following operations are executed, the row data and columns cannot match according to the binlog logic. order_0 executes ALTER TABLE order_0 ADD COLUMN name and is synchronized to order. order_1 executes INSERT INTO order_1 VALUES(12). Design details This section describes the constraints and processing of sharding data migration.Constraints Deploy the DM-workers supporting the sharding data synchronization task. You can only execute a single DDL statement on a single table. Execute this DDL statement on all the upstream tables to be merged into a same downstream table. Processing To complete the sharding data synchronization task, Data Migration uses the global DDL lock in the following two layers of DDL synchronization: The first layer: It is the DDL synchronization within the DM-worker. The synchronization related information is saved by DM-worker. Only after the synchronization is finished at this layer, the second layer of synchronization is carried out. The second layer: The synchronization is executed by coordinating the DM-workers using the global DDL lock. The synchronization related information is saved by both DM-master and DM-worker. The processing details are as follows: DM-worker creates a sharding group for all upstream tables to be merged into the same target table (first layer synchronization; members are the upstream tables) DM-master creates a sharding group for all DM-workers that perform the target table merging task (the second layer synchronization; the members are all DM-workers that are doing the task) When a certain upstream table in the sharding group within the DM-worker encounters a DDL statement, the synchronization of the target table in the DM-worker is partially suspended (the DML statements before the DDL structure change continue to synchronize, while the DML statements after the DDL structure change and the subsequent DDL statements are ignored), but the synchronization of other target tables in this task continues. When all upstream tables in the sharding group within the DM-worker encounter this DDL statement, DM-worker suspends the execution of this task. (The synchronization of other target tables of the task is also suspended, so that the newly created synchronization stream in the subsequent step 8 catches up with the global synchronization stream.) The DM-worker requests the DM-master to create a DDL lock corresponding to the target table on the task. If the DDL lock already exists, the DM-worker registers its own information; if the DDL lock does not exist, the DM-master creates a DDL lock for the DM-worker, and the DM-worker registers its own information and becomes the DDL lock owner. The DDL lock is identified by related information. When the DM-worker registers information, the DM-master judges whether all DDL statements are synchronized according to the task group information (of the second layer synchronization). If they are all synchronized, the DM-master notifies the DDL lock owner to execute the DDL statement. (Assuming that the DDL lock owner crashes in the process, if the owner restarts, it redoes the first layer synchronization, and triggers redoing the second layer synchronization when the first layer synchronization is finished, which means it automatically recovers; if the owner does not restart, you need to use the unlock-ddl-lock command to manually specify another DM-worker to execute the DDL statement to complete the synchronization.) The DM-master checks whether the DDL lock owner successfully executes the DDL statement. If the execution is successful, it notifies all the DM-workers that are waiting for the execution of this DDL statement to continue to synchronize after this DDL statement. When the DM-worker resumes synchronization after recovering from the DDL lock, it creates a new task synchronization stream and re-executes the DML/DDL statements ignored in step 3 to complete the previously skipped data. After the DM-worker completes the DML statements, it continues the normal synchronization. Sharding DDL usage restrictions Data Migration has the following sharding DDL usage restrictions: All the tables in a sharding group must execute the same DDL statements in the same order. Currently, Data Migration does not support executing the sharding DDL statements in an unordered and crossed way. The whole synchronization process hangs up whenever a certain DDL statement on a table is not executed. Only after one DDL operation is completed in the whole sharding group, this group can execute the next DDL statement. The sharding group synchronization task does not support DROP DATABASE/DROP TABLE. The sharding group synchronization task supports RENAME TABLE, but with the following limits: A table can only be renamed to a new name that is not used by any other table. A single RENAME TABLE statement can only involve a single RENAME operation. (Online DDL is supported in another solution) The synchronization point where each table starts the task should be before or after all sharding DDL operations that need to be synchronized If some of the sharding DDL statements have been executed when you start to synchronize the synchronization points, the sharding DDL operation can never be synchronized successfully. If you need to change router-rules, you need to wait for synchronization of all sharding DDL operations to complete. While in the process of sharding DDL synchronization, it reports an error if you use dmctl to change router-rules. If you need to CREATE a new table to an existing sharding group, you need to keep the table schema the same as the newly altered table schema. For example, the original table_a, table_b initially has two columns (a, b), and after the sharding DDL has three columns (a, b, c), the table of the new CREATE after the synchronization is completed should have three columns (a, b, c). While the sharding DDL lock is waiting for synchronization, if DM-master is restarted, the synchronization process can be blocked because of the lock information loss. "}, {"url": "https://pingcap.com/docs/tools/dm-task-configuration-file-intro/", "title": "Data Migration Task Configuration File", "content": " Data Migration Task Configuration File This document introduces the task configuration file of Data Migration – task.yaml, including Global configuration and Instance configuration.For description of configuration items, see Data Migration Task Configuration Options.Important concepts For description of important concepts including instance-id and the DM-worker ID, see Important concepts.Global configuration Basic information configuration name: test # The name of the task. Should be globally unique. task-mode: all # The task mode. Can be set to `full`/`incremental`/`all`. is-sharding: true # Whether it is a sharding task meta-schema: "dm_meta" # The downstream database that stores the `meta` information remove-meta: false # Whether to remove the `meta` information (`checkpoint` and `onlineddl`) before starting the # synchronization task target-database: # Configuration of the downstream database instance host: "192.168.0.1" port: 4000 user: "root" password: "" For more details of task-mode, see Task configuration argument description.Feature configuration set Global configuration includes the following feature configuration set.routes: # The routing mapping rule set between the upstream and downstream tables user-route-rules-schema: # `schema-pattern`/`table-pattern` uses the wildcard matching rule. schema-pattern: "test_*" table-pattern: "t_*" target-schema: "test" target-table: "t" filters: # The binlog event filter rule set of the matched table of the upstream # database instance user-filter-1: schema-pattern: "test_*" table-pattern: "t_*" events: ["truncate table", "drop table"] action: Ignore black-white-list: # The filter rule set of the black white list of the matched table of the # upstream database instance instance: do-dbs: ["~^test.*", "do"] ignore-dbs: ["mysql", "ignored"] do-tables: - db-name: "~^test.*" tbl-name: "~^t.*" column-mappings: # The column mapping rule set of the matched table of the upstream database # instance instance-1: schema-pattern: "test_*" table-pattern: "t_*" expression: "partition id" source-column: "id" target-column: "id" arguments: ["1", "test_", "t_"] mydumpers: # Configuration arguments of running mydumper global: mydumper-path: "./mydumper" # The mydumper binary file path. It is generated by the Ansible deployment # application automatically and needs no configuration. threads: 16 # The number of the threads mydumper dumps from the upstream database instance chunk-filesize: 64 # The size of the file mydumper generates skip-tz-utc: true extra-args: "-B test -T t1,t2 --no-locks" loaders: # Configuration arguments of running Loader global: pool-size: 16 # The number of threads that execute mydumper SQL files concurrently in Loader dir: "./dumped_data" # The directory output by mydumper that Loader reads. Directories for # different tasks of the same instance must be different. (mydumper outputs the # SQL file based on the directory) syncers: # Configuration arguments of running Syncer global: worker-count: 16 # The number of threads that synchronize binlog events concurrently in Syncer batch: 1000 # The number of SQL statements in a transaction batch that Syncer # synchronizes to the downstream database max-retry: 100 # The retry times of the transactions with an error that Syncer synchronizes # to the downstream database (only for DML operations) References: For details of user-filter-1, see Filtering rules of binlog events. For details of instance, see Black and white lists filtering rule. For details of instance-1 of column-mappings, see Column mapping rule. Instance configuration This part defines the subtask of data synchronization. DM supports synchronizing data from one or multiple MySQL instances to the same instance.mysql-instances: - config: # The upstream database configuration corresponding to `instance-id` host: "192.168.199.118" port: 4306 user: "root" password: "1234" # Requires the password encrypted by dmctl instance-id: "instance118-4306" # The MySQL instance ID. It corresponds to the upstream MySQL instance. It is # not allowed to set it to an ID of a MySQL instance that is not within the # DM-master cluster topology. meta: # The position where the binlog synchronization starts when the checkpoint of # the downstream database does not exist. If the checkpoint exits, this # configuration does not work. binlog-name: binlog-00001 binlog-pos: 4 route-rules: ["user-route-rules-schema", "user-route-rules"] # Routing rules selected from `routes` above filter-rules: ["user-filter-1", "user-filter-2"] # Filter rules selected from `filters` above column-mapping-rules: ["instance-1"] # Column mapping rules selected from `column-mappings` above black-white-list: "instance" # The black white list item selected from `black-white-list` above mydumper-config-name: "global" # The mydumper configuration name. You cannot set it # and `mydumper` at the same time. loader-config-name: "global" # The Loader configuration name. You cannot set it and # `loader` at the same time. syncer-config-name: "global" # The Syncer configuration name. You cannot set it and # `syncer` at the same time. - config: host: "192.168.199.118" port: 5306 user: "root" password: "1234" instance-id: "instance118-5306" mydumper: # The mydumper configuration. You cannot set it and # `mydumper-config-name` at the same time. mydumper-path: "./mydumper" # The mydumper binary file path. It is generated by # Ansible deployment application and needs no # configuration. threads: 4 chunk-filesize: 8 skip-tz-utc: true extra-args: "-B test -T t1,t2" loader: # The Loader configuration. You cannot set it and # `loader-config-name` at the same time. pool-size: 32 # The number of threads that execute mydumper SQL # files concurrently in Loader dir: "./dumped_data" syncer: # The Syncer configuration. You cannot set it and # `syncer-config-name` at the same time. worker-count: 32 # The number of threads that synchronize binlog events # concurrently in Syncer batch: 2000 max-retry: 200 For the configuration details of the above options, see the corresponding part in Feature configuration set, as shown in the following table. Option Corresponding part route-rules routes filter-rules filters column-mapping-rules column-mappings black-white-list black-white-list mydumper-config-name mydumpers loader-config-name loaders syncer-config-name syncers "}, {"url": "https://pingcap.com/docs/tools/dm-task-config-argument-description/", "title": "Data Migration Task Configuration Options", "content": " Data Migration Task Configuration Options This document introduces the configuration options that apply to Data Migration tasks.task-mode String (full/incremental/all) The task mode of data migration to be executed Default value: all full: Only makes a full backup of the upstream database and then restores it to the downstream database. incremental: Only synchronizes the incremental data of the upstream database to the downstream database using the binlog. all: full + incremental. Makes a full backup of the upstream database, imports the full data to the downstream database, and then uses the binlog to make an incremental synchronization to the downstream database starting from the exported position during the full backup process (binlog position/GTID). Routing rule # `schema-pattern`/`table-pattern` uses the wildcard matching rule schema level: schema-pattern: "test_*" target-schema: "test" table level: schema-pattern: "test_*" table-pattern: "t_*" target-schema: "test" target-table: "t" Description: Synchronizes the upstream table data that matches schema-pattern/table-pattern to the downstream target-schema/target-table. You can set the routing rule at the schema/table level.Taking the above code block as an example: Schema level: Synchronizes all the upstream tables that match the test_* schema to the downstream test schema.For example, schema: test_1 - tables [a, b, c] => schema:test - tables [a, b, c] Table level: Synchronizes the t_* matched upstream tables with test_* matched schema to the downstream schema:test table:t table. Notes: The table level rule has a higher priority than the schema level rule. You can set one routing rule at most at one level. Black and white lists filtering rule instance: do-dbs: ["~^test.*", "do"] # Starts with "~", indicating it is a regular expression ignore-dbs: ["mysql", "ignored"] do-tables: - db-name: "~^test.*" tbl-name: "~^t.*" - db-name: "do" tbl-name: "do" ignore-tables: - db-name: "do" tbl-name: "do" The black and white lists filtering rule of the upstream database instances is similar to MySQL replication-rules-db/replication-rules-table.The filter process is as follows: Filter at the schema level: If do-dbs is not empty, judge whether a matched schema exists in do-dbs. If yes, continue to filter at the table level. If not, ignore it and exit. If do-dbs is empty, and ignore-dbs is not empty, judge whether a matched schema exits in ignore-dbs. If yes, ignore it and exit. If not, continue to filter at the table level. If both do-dbs and ignore-dbs are empty, continue to filter at the table level. Filter at the table level: If do-tables is not empty, judge whether a matched rule exists in do-tables. If yes, exit and execute the statement. If not, continue to the next step. If ignore tables is not empty, judge whether a matched rule exists in ignore-tables. If yes, ignore it and exit. If not, continue to the next step. If do-tables is not empty, ignore it and exit. Otherwise, exit and execute the statement. Filtering rules of binlog events # table level user-filter-1: schema-pattern: "test_*" # `schema-pattern`/`table-pattern` uses the wildcard matching rule. table-pattern: "t_*" events: ["truncate table", "drop table"] sql-pattern: ["^DROPs+PROCEDURE", "^CREATEs+PROCEDURE"] action: Ignore # schema level user-filter-2: schema-pattern: "test_*" events: ["All DML"] action: Do Description: Configures the filtering rules for binlog events and DDL SQL statements of the upstream tables that match schema-pattern/table-pattern. events: the binlog event array Events Type Description all Includes all the events below all dml Includes all DML events below all ddl Includes all DDL events below none Includes none of the events below none ddl Includes none of the DDL events below none dml Includes none of the DML events below insert DML The INSERT DML event update DML The UPDATE DML event delete DML The DELETE DML event create database DDL The CREATE DATABASE DDL event drop database DDL The DROP DATABASE DDL event create table DDL The CREATE TABLE DDL event create index DDL The CREATE INDEX DDL event drop table DDL The DROP TABLE DDL event truncate table DDL The TRUNCATE TABLE DDL event rename table DDL The RENAME TABLE DDL event drop index DDL The DROP INDEX DDL event alter table DDL The ALTER TABLE DDL event sql-pattern Filters a specific DDL SQL statement. The matching rule supports using an regular expression, for example, "^DROPs+PROCEDURE". Note: If sql-pattern is empty, no filtering operation is performed. For the filtering rules, see the action description. action String (Do/Ignore) For rules that match schema-pattern/table-pattern, judge whether the DDL statement is in the events of the rule or sql-pattern. Black list: If action = Ignore, execute Ignore; otherwise execute Do. White list: If action = Ignore, execute Do; otherwise execute Ignore. Column mapping rule instance-1: schema-pattern: "test_*" # `schema-pattern`/`table-pattern` uses the wildcard matching rule table-pattern: "t_*" expression: "partition id" source-column: "id" target-column: "id" arguments: ["1", "test_", "t_"] instance-2: schema-pattern: "test_*" table-pattern: "t_*" expression: "partition id" source-column: "id" target-column: "id" arguments: ["2", "test_", "t_"] Description: the rules for mapping the columns of schema-pattern/table-pattern matched tables in upstream database instances. It is used to resolve the conflicts of auto-increment primary keys of sharded tables. source-column, target-column: Uses expression to compute the data of source-column as the data of target-column. expression: The expression used to convert the column data. Currently, only the following built-in expression is supported: partition id You need to set arguments to [instance_id, prefix of schema, prefix of table]. schema name = arguments[1] + schema ID(suffix of schema); schema ID == suffix of schema table name = argument[2] + table ID(suffix of table); table ID == suffix of table If argument[0] == “”, the partition ID takes up 0 bit in the figure below; otherwise, it takes up 4 bits (by default) If argument[1] == “”, the schema ID takes up 0 bit in the figure below; otherwise, it takes up 7 bits (by default) If argument[2] == “”, the table ID takes up 0 bit in the figure below; otherwise, it takes up 8 bits (by default) The origin ID is the value of the auto-increment ID column of a row in the table Restrictions: It is only applicable to the bigint column. The instance ID value should be (>= 0, <= 15) (4 bits by default) The schema ID value should be (>= 0, <= 127) (7 bits by default) The table ID value should be (>= 0, <= 255) (8 bits by default) The origin ID value should be (>= 0, <= 17592186044415) (44 bits by default) "}, {"url": "https://pingcap.com/docs/tools/data-migration-troubleshooting/", "title": "Data Migration Troubleshooting", "content": " Data Migration Troubleshooting This document summarizes some commonly encountered issues when you use Data Migration, and provides the solutions.If you encounter errors while running Data Migration, try the following solution: Check the log content related to the error you encountered. The log files are on the DM-master and DM-worker deployment nodes. You can then view common errors to find the corresponding solution. If the error you encountered is not involved yet, and you cannot solve the problem yourself by checking the log or monitoring metrics, you can contact the corresponding sales support staff. After the error is solved, restart the task using dmctl.resume-task ${task name} However, you need to reset the data synchronization task in some cases. For details about when to reset and how to reset, see Reset the data synchronization task.Common errors Access denied for user 'root'@'172.31.43.27' (using password: YES) shows when you query the task or check the log For database related passwords in all the DM configuration files, use the passwords encrypted by dmctl. If a database password is empty, it is unnecessary to encrypt it. For how to encrypt the plaintext password, see Encrypt the upstream MySQL user password using dmctl.In addition, the user of the upstream and downstream databases must have the corresponding read and write privileges. Data Migration also checks the corresponding privileges automatically while starting the data synchronization task.Incompatible DDL statements When you encounter the following error, you need to manually handle it using dmctl (skipping the DDL statement or replacing the DDL statement with a specified DDL statement). For details, see Skip or replace abnormal SQL statements.encountered incompatible DDL in TiDB: %s please confirm your DDL statement is correct and needed. for TiDB compatible DDL, please see the docs: English version: https://github.com/pingcap/docs/blob/master/sql/ddl.md Chinese version: https://github.com/pingcap/docs-cn/blob/master/sql/ddl.md if the DDL is not needed, you can use dm-ctl to skip it, otherwise u also can use dm-ctl to replace it. Note: Currently, TiDB is not compatible with all the DDL statements that MySQL supports. See the DDL statements supported by TiDB. Reset the data synchronization task You need to reset the entire data synchronization task in the following cases: RESET MASTER is artificially executed in the upstream database, which causes an error in the relay log synchronization. The relay log or the upstream binlog is corrupted or lost. Generally, at this time, the relay unit exits with an error and cannot be automatically restored gracefully. You need to manually restore the data synchronization and the steps are as follows: Use the stop-task command to stop all the synchronization tasks that are currently running. Use Ansible to stop the entire DM cluster. Manually clean up the relay log directory of the DM-worker corresponding to the MySQL master whose binlog is reset. If the cluster is deployed using DM-Ansible, the relay log is in the <deploy_dir>/relay_log directory. If the cluster is manually deployed using the binary, the relay log is in the directory set in the relay-dir parameter. Clean up downstream synchronized data. Use Ansible to start the entire DM cluster. Restart data synchronization with the new task name, or set remove-meta to true and task-mode to all. Skip or replace abnormal SQL statements If the sync unit encounters an error while executing a SQL (DDL/DML) statement, DM supports manually skipping the SQL statement using dmctl or replacing this execution with another user-specified SQL statement.When you manually handle the SQL statement that has an error, the frequently used commands include query-status, sql-skip, and sql-replace.The manual process of handling abnormal SQL statements Use query-status to query the current running status of the task. Whether an error caused the Paused status of a task in a DM-worker Whether the cause of the task error is an error in executing the SQL statement Record the returned binlog pos (SyncerBinlog) that Syncer has synchronized when executing query-status. According to the error condition, application scenario and so on, decide whether to skip or replace the current SQL statement that has an error. Skip or replace the current error SQL statement that has an error: To skip the current SQL statement that has an error, use sql-skip to specify the DM-worker, task name and binlog pos that need to perform SQL skip operations and perform the skip operations. To replace the current SQL statement that has an error, use sql-replace to specify the DM-worker, task name, binlog pos, and the new SQL statement(s) used to replace the original SQL statement. (You can specify multiple statements by separating them using ;.) Use resume-task and specify the DM-worker and task name to restore the task on the DM-worker that was paused due to an error. Use query-status to check whether the SQL statement skip or replacement is successful. How to find the binlog pos that needs to be specified in the parameter? In dm-worker.log, find current pos corresponding to the SQL statement has an error.Command line parameter description sql-skip worker: flag parameter, string, --worker, required; specifies the DM-worker where the SQL statement that needs to perform the skip operation is located task-name: non-flag parameter, string, required; specifies the task where the SQL statement that needs to perform the skip operation is located binlog-pos: non-flag parameter, string, required; specifies the binlog pos where the SQL statement that needs to perform the skip operation is located; the format is mysql-bin.000002:123 (: separates the binlog name and pos) sql-replace worker: flag parameter, string, --worker, required; specifies the DM-worker where the SQL statement that needs to perform the replacement operation is located task-name: non-flag parameter, string, required; specifies the task where the SQL statement that needs to perform the replacement operation is located binlog-pos: non-flag parameter, string, required; specifies the binlog pos where the SQL statement that needs to perform the replacement operation is located; the format is mysql-bin.000002:123 (: separates the binlog name and pos) sqls: non-flag parameter, string, required; specifies new SQL statements that are used to replace the original SQL statement (You can specify multiple statements by separating them using ;) "}, {"url": "https://pingcap.com/docs/sql/admin/", "title": "Database Administration Statements", "content": " Database Administration Statements TiDB manages the database using a number of statements, including granting privileges, modifying system variables, and querying database status.Privilege management See Privilege Management.SET statement The SET statement has multiple functions and forms.Assign values to variables SET variable_assignment [, variable_assignment] ... variable_assignment: user_var_name = expr | param_name = expr | local_var_name = expr | [GLOBAL | SESSION] system_var_name = expr | [@@global. | @@session. | @@] system_var_name = expr You can use the above syntax to assign values to variables in TiDB, which include system variables and user-defined variables. All user-defined variables are session variables. The system variables set using @@global. or GLOBAL are global variables, otherwise session variables. For more information, see The System Variables.SET CHARACTER statement and SET NAMES SET {CHARACTER SET | CHARSET} {'charset_name' | DEFAULT} SET NAMES {'charset_name' [COLLATE 'collation_name'] | DEFAULT} This statement sets three session system variables (character_set_client, character_set_results and character_set_connection) as given character set. Currently, the value of character_set_connection differs from MySQL and is set as the value of character_set_database in MySQL.Set the password SET PASSWORD [FOR user] = password_option password_option: { 'auth_string' | PASSWORD('auth_string') } This statement is used to set user passwords. For more information, see Privilege Management.Set the isolation level SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; This statement is used to set the transaction isolation level. For more information, see Transaction Isolation Level.SHOW statement TiDB supports part of SHOW statements, used to view the Database/Table/Column information and the internal status of the database. Currently supported statements:# Supported and similar to MySQL SHOW CHARACTER SET [like_or_where] SHOW COLLATION [like_or_where] SHOW [FULL] COLUMNS FROM tbl_name [FROM db_name] [like_or_where] SHOW CREATE {DATABASE|SCHEMA} db_name SHOW CREATE TABLE tbl_name SHOW DATABASES [like_or_where] SHOW GRANTS FOR user SHOW INDEX FROM tbl_name [FROM db_name] SHOW PRIVILEGES SHOW [FULL] PROCESSLIST SHOW [GLOBAL | SESSION] STATUS [like_or_where] SHOW TABLE STATUS [FROM db_name] [like_or_where] SHOW [FULL] TABLES [FROM db_name] [like_or_where] SHOW [GLOBAL | SESSION] VARIABLES [like_or_where] SHOW WARNINGS # Supported to improve compatibility but return null results SHOW ENGINE engine_name {STATUS | MUTEX} SHOW [STORAGE] ENGINES SHOW PLUGINS SHOW PROCEDURE STATUS [like_or_where] SHOW TRIGGERS [FROM db_name] [like_or_where] SHOW EVENTS SHOW FUNCTION STATUS [like_or_where] SHOW MASTER STATUS # TiDB-specific statements for viewing statistics SHOW STATS_META [like_or_where] SHOW STATS_HISTOGRAMS [like_or_where] SHOW STATS_BUCKETS [like_or_where] like_or_where: LIKE 'pattern' | WHERE expr Note: To view statistics using the SHOW statement, see View Statistics. For more information about the SHOW statement, see SHOW Syntax in MySQL. The UniqueID field returned from SHOW MASTER STATUS is the current TSO obtained directly from PD. The TSO is used during binlog increment and mydumper synchronization.mysql> show master status; +-------------|--------------------|--------------|------------------|-------------------+ | File | UniqueID | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +-------------|--------------------|--------------|------------------|-------------------+ | tidb-binlog | 403756327834484736 | | | | +-------------|--------------------|--------------|------------------|-------------------+ 1 row in set (0.00 sec) ADMIN statement This statement is a TiDB extension syntax, used to view the status of TiDB.ADMIN SHOW DDL ADMIN SHOW DDL JOBS ADMIN SHOW DDL JOB QUERIES job_id [, job_id] ... ADMIN CANCEL DDL JOBS job_id [, job_id] ... ADMIN SHOW DDL: To view the currently running DDL jobs. ADMIN SHOW DDL JOBS: To view all the results in the current DDL job queue (including tasks that are running and waiting to be run) and the last ten results in the completed DDL job queue. ADMIN SHOW DDL JOB QUERIES job_id [, job_id] ...: To view the original SQL statement of the DDL task corresponding to the job_id; the job_id only searches the running DDL job and the last ten results in the DDL history job queue ADMIN CANCEL DDL JOBS job_id [, job_id] ...: To cancel the currently running DDL jobs and return whether the corresponding jobs are successfully cancelled. If the operation fails to cancel the jobs, specific reasons are displayed. Note: This operation can cancel multiple DDL jobs at the same time. You can get the ID of DDL jobs using the ADMIN SHOW DDL JOBS statement. If the jobs you want to cancel are finished, the cancellation operation fails. "}, {"url": "https://pingcap.com/docs/v1.0/sql/admin/", "title": "Database Administration Statements", "content": " Database Administration Statements TiDB manages the database using a number of statements, including granting privileges, modifying system variables, and querying database status.Privilege management See Privilege Management.SET statement The SET statement has multiple functions and forms.Assign values to variables SET variable_assignment [, variable_assignment] ... variable_assignment: user_var_name = expr | param_name = expr | local_var_name = expr | [GLOBAL | SESSION] system_var_name = expr | [@@global. | @@session. | @@] system_var_name = expr You can use the above syntax to assign values to variables in TiDB, which include system variables and user-defined variables. All user-defined variables are session variables. The system variables set using @@global. or GLOBAL are global variables, otherwise session variables. For more information, see The System Variables.SET CHARACTER statement and SET NAMES SET {CHARACTER SET | CHARSET} {'charset_name' | DEFAULT} SET NAMES {'charset_name' [COLLATE 'collation_name'] | DEFAULT} This statement sets three session system variables (character_set_client, character_set_results and character_set_connection) as given character set. Currently, the value of character_set_connection differs from MySQL and is set as the value of character_set_database in MySQL.Set the password SET PASSWORD [FOR user] = password_option password_option: { 'auth_string' | PASSWORD('auth_string') } This statement is used to set user passwords. For more information, see Privilege Management.Set the isolation level SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; This statement is used to set the transaction isolation level. For more information, see Transaction Isolation Level.SHOW statement TiDB supports part of SHOW statements, used to view the Database/Table/Column information and the internal status of the database. Currently supported statements:# Supported and similar to MySQL SHOW CHARACTER SET [like_or_where] SHOW COLLATION [like_or_where] SHOW [FULL] COLUMNS FROM tbl_name [FROM db_name] [like_or_where] SHOW CREATE {DATABASE|SCHEMA} db_name SHOW CREATE TABLE tbl_name SHOW DATABASES [like_or_where] SHOW GRANTS FOR user SHOW INDEX FROM tbl_name [FROM db_name] SHOW PRIVILEGES SHOW [FULL] PROCESSLIST SHOW [GLOBAL | SESSION] STATUS [like_or_where] SHOW TABLE STATUS [FROM db_name] [like_or_where] SHOW [FULL] TABLES [FROM db_name] [like_or_where] SHOW [GLOBAL | SESSION] VARIABLES [like_or_where] SHOW WARNINGS # Supported to improve compatibility but return null results SHOW ENGINE engine_name {STATUS | MUTEX} SHOW [STORAGE] ENGINES SHOW PLUGINS SHOW PROCEDURE STATUS [like_or_where] SHOW TRIGGERS [FROM db_name] [like_or_where] SHOW EVENTS SHOW FUNCTION STATUS [like_or_where] # TiDB-specific statements for viewing statistics SHOW STATS_META [like_or_where] SHOW STATS_HISTOGRAMS [like_or_where] SHOW STATS_BUCKETS [like_or_where] like_or_where: LIKE 'pattern' | WHERE expr Note: To view statistics using the SHOW statement, see View Statistics. For more information about the SHOW statement, see SHOW Syntax in MySQL. ADMIN statement This statement is a TiDB extension syntax, used to view the status of TiDB.ADMIN SHOW DDL ADMIN SHOW DDL JOBS ADMIN CANCEL DDL JOBS 'job_id' [, 'job_id'] ... ADMIN SHOW DDL: To view the currently running DDL jobs. ADMIN SHOW DDL JOBS: To view all the results in the current DDL job queue (including tasks that are running and waiting to be run) and the last ten results in the completed DDL job queue. ADMIN CANCEL DDL JOBS 'job_id' [, 'job_id'] ...: To cancel the currently running DDL jobs and return whether the corresponding jobs are successfully cancelled. If the operation fails to cancel the jobs, specific reasons are displayed. Note: This operation can cancel multiple DDL jobs at the same time. You can get the ID of DDL jobs using the ADMIN SHOW DDL JOBS statement. If the jobs you want to cancel are finished, the cancellation operation fails. "}, {"url": "https://pingcap.com/docs/v2.0/sql/admin/", "title": "Database Administration Statements", "content": " Database Administration Statements TiDB manages the database using a number of statements, including granting privileges, modifying system variables, and querying database status.Privilege management See Privilege Management.SET statement The SET statement has multiple functions and forms.Assign values to variables SET variable_assignment [, variable_assignment] ... variable_assignment: user_var_name = expr | param_name = expr | local_var_name = expr | [GLOBAL | SESSION] system_var_name = expr | [@@global. | @@session. | @@] system_var_name = expr You can use the above syntax to assign values to variables in TiDB, which include system variables and user-defined variables. All user-defined variables are session variables. The system variables set using @@global. or GLOBAL are global variables, otherwise session variables. For more information, see The System Variables.SET CHARACTER statement and SET NAMES SET {CHARACTER SET | CHARSET} {'charset_name' | DEFAULT} SET NAMES {'charset_name' [COLLATE 'collation_name'] | DEFAULT} This statement sets three session system variables (character_set_client, character_set_results and character_set_connection) as given character set. Currently, the value of character_set_connection differs from MySQL and is set as the value of character_set_database in MySQL.Set the password SET PASSWORD [FOR user] = password_option password_option: { 'auth_string' | PASSWORD('auth_string') } This statement is used to set user passwords. For more information, see Privilege Management.Set the isolation level SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; This statement is used to set the transaction isolation level. For more information, see Transaction Isolation Level.SHOW statement TiDB supports part of SHOW statements, used to view the Database/Table/Column information and the internal status of the database. Currently supported statements:# Supported and similar to MySQL SHOW CHARACTER SET [like_or_where] SHOW COLLATION [like_or_where] SHOW [FULL] COLUMNS FROM tbl_name [FROM db_name] [like_or_where] SHOW CREATE {DATABASE|SCHEMA} db_name SHOW CREATE TABLE tbl_name SHOW DATABASES [like_or_where] SHOW GRANTS FOR user SHOW INDEX FROM tbl_name [FROM db_name] SHOW PRIVILEGES SHOW [FULL] PROCESSLIST SHOW [GLOBAL | SESSION] STATUS [like_or_where] SHOW TABLE STATUS [FROM db_name] [like_or_where] SHOW [FULL] TABLES [FROM db_name] [like_or_where] SHOW [GLOBAL | SESSION] VARIABLES [like_or_where] SHOW WARNINGS # Supported to improve compatibility but return null results SHOW ENGINE engine_name {STATUS | MUTEX} SHOW [STORAGE] ENGINES SHOW PLUGINS SHOW PROCEDURE STATUS [like_or_where] SHOW TRIGGERS [FROM db_name] [like_or_where] SHOW EVENTS SHOW FUNCTION STATUS [like_or_where] # TiDB-specific statements for viewing statistics SHOW STATS_META [like_or_where] SHOW STATS_HISTOGRAMS [like_or_where] SHOW STATS_BUCKETS [like_or_where] like_or_where: LIKE 'pattern' | WHERE expr Note: To view statistics using the SHOW statement, see View Statistics. For more information about the SHOW statement, see SHOW Syntax in MySQL. ADMIN statement This statement is a TiDB extension syntax, used to view the status of TiDB.ADMIN SHOW DDL ADMIN SHOW DDL JOBS ADMIN SHOW DDL JOB QUERIES job_id [, job_id] ... ADMIN CANCEL DDL JOBS job_id [, job_id] ... ADMIN SHOW DDL: To view the currently running DDL jobs. ADMIN SHOW DDL JOBS: To view all the results in the current DDL job queue (including tasks that are running and waiting to be run) and the last ten results in the completed DDL job queue. ADMIN SHOW DDL JOB QUERIES job_id [, job_id] ...: To view the original SQL statement of the DDL task corresponding to the job_id; the job_id only searches the running DDL job and the last ten results in the DDL history job queue ADMIN CANCEL DDL JOBS job_id [, job_id] ...: To cancel the currently running DDL jobs and return whether the corresponding jobs are successfully cancelled. If the operation fails to cancel the jobs, specific reasons are displayed. Note: This operation can cancel multiple DDL jobs at the same time. You can get the ID of DDL jobs using the ADMIN SHOW DDL JOBS statement. If the jobs you want to cancel are finished, the cancellation operation fails. "}, {"url": "https://pingcap.com/docs/sql/date-and-time-functions/", "title": "Date and Time Functions", "content": " Date and Time Functions The usage of date and time functions is similar to MySQL. For more information, see here.Date/Time functions Name Description ADDDATE() Add time values (intervals) to a date value ADDTIME() Add time CONVERT_TZ() Convert from one time zone to another CURDATE() Return the current date CURRENT_DATE(), CURRENT_DATE Synonyms for CURDATE() CURRENT_TIME(), CURRENT_TIME Synonyms for CURTIME() CURRENT_TIMESTAMP(), CURRENT_TIMESTAMP Synonyms for NOW() CURTIME() Return the current time DATE() Extract the date part of a date or datetime expression DATE_ADD() Add time values (intervals) to a date value DATE_FORMAT() Format date as specified DATE_SUB() Subtract a time value (interval) from a date DATEDIFF() Subtract two dates DAY() Synonym for DAYOFMONTH() DAYNAME() Return the name of the weekday DAYOFMONTH() Return the day of the month (0-31) DAYOFWEEK() Return the weekday index of the argument DAYOFYEAR() Return the day of the year (1-366) EXTRACT() Extract part of a date FROM_DAYS() Convert a day number to a date FROM_UNIXTIME() Format Unix timestamp as a date GET_FORMAT() Return a date format string HOUR() Extract the hour LAST_DAY Return the last day of the month for the argument LOCALTIME(), LOCALTIME Synonym for NOW() LOCALTIMESTAMP, LOCALTIMESTAMP() Synonym for NOW() MAKEDATE() Create a date from the year and day of year MAKETIME() Create time from hour, minute, second MICROSECOND() Return the microseconds from argument MINUTE() Return the minute from the argument MONTH() Return the month from the date passed MONTHNAME() Return the name of the month NOW() Return the current date and time PERIOD_ADD() Add a period to a year-month PERIOD_DIFF() Return the number of months between periods QUARTER() Return the quarter from a date argument SEC_TO_TIME() Converts seconds to ‘HH:MM:SS’ format SECOND() Return the second (0-59) STR_TO_DATE() Convert a string to a date SUBDATE() Synonym for DATE_SUB() when invoked with three arguments SUBTIME() Subtract times SYSDATE() Return the time at which the function executes TIME() Extract the time portion of the expression passed TIME_FORMAT() Format as time TIME_TO_SEC() Return the argument converted to seconds TIMEDIFF() Subtract time TIMESTAMP() With a single argument, this function returns the date or datetime expression; with two arguments, the sum of the arguments TIMESTAMPADD() Add an interval to a datetime expression TIMESTAMPDIFF() Subtract an interval from a datetime expression TO_DAYS() Return the date argument converted to days TO_SECONDS() Return the date or datetime argument converted to seconds since Year 0 UNIX_TIMESTAMP() Return a Unix timestamp UTC_DATE() Return the current UTC date UTC_TIME() Return the current UTC time UTC_TIMESTAMP() Return the current UTC date and time WEEK() Return the week number WEEKDAY() Return the weekday index WEEKOFYEAR() Return the calendar week of the date (1-53) YEAR() Return the year YEARWEEK() Return the year and week For details, see here."}, {"url": "https://pingcap.com/docs/v1.0/sql/date-and-time-functions/", "title": "Date and Time Functions", "content": " Date and Time Functions The usage of date and time functions is similar to MySQL. For more information, see here.Date/Time functions Name Description ADDDATE() Add time values (intervals) to a date value ADDTIME() Add time CONVERT_TZ() Convert from one time zone to another CURDATE() Return the current date CURRENT_DATE(), CURRENT_DATE Synonyms for CURDATE() CURRENT_TIME(), CURRENT_TIME Synonyms for CURTIME() CURRENT_TIMESTAMP(), CURRENT_TIMESTAMP Synonyms for NOW() CURTIME() Return the current time DATE() Extract the date part of a date or datetime expression DATE_ADD() Add time values (intervals) to a date value DATE_FORMAT() Format date as specified DATE_SUB() Subtract a time value (interval) from a date DATEDIFF() Subtract two dates DAY() Synonym for DAYOFMONTH() DAYNAME() Return the name of the weekday DAYOFMONTH() Return the day of the month (0-31) DAYOFWEEK() Return the weekday index of the argument DAYOFYEAR() Return the day of the year (1-366) EXTRACT() Extract part of a date FROM_DAYS() Convert a day number to a date FROM_UNIXTIME() Format Unix timestamp as a date GET_FORMAT() Return a date format string HOUR() Extract the hour LAST_DAY Return the last day of the month for the argument LOCALTIME(), LOCALTIME Synonym for NOW() LOCALTIMESTAMP, LOCALTIMESTAMP() Synonym for NOW() MAKEDATE() Create a date from the year and day of year MAKETIME() Create time from hour, minute, second MICROSECOND() Return the microseconds from argument MINUTE() Return the minute from the argument MONTH() Return the month from the date passed MONTHNAME() Return the name of the month NOW() Return the current date and time PERIOD_ADD() Add a period to a year-month PERIOD_DIFF() Return the number of months between periods QUARTER() Return the quarter from a date argument SEC_TO_TIME() Converts seconds to ‘HH:MM:SS’ format SECOND() Return the second (0-59) STR_TO_DATE() Convert a string to a date SUBDATE() Synonym for DATE_SUB() when invoked with three arguments SUBTIME() Subtract times SYSDATE() Return the time at which the function executes TIME() Extract the time portion of the expression passed TIME_FORMAT() Format as time TIME_TO_SEC() Return the argument converted to seconds TIMEDIFF() Subtract time TIMESTAMP() With a single argument, this function returns the date or datetime expression; with two arguments, the sum of the arguments TIMESTAMPADD() Add an interval to a datetime expression TIMESTAMPDIFF() Subtract an interval from a datetime expression TO_DAYS() Return the date argument converted to days TO_SECONDS() Return the date or datetime argument converted to seconds since Year 0 UNIX_TIMESTAMP() Return a Unix timestamp UTC_DATE() Return the current UTC date UTC_TIME() Return the current UTC time UTC_TIMESTAMP() Return the current UTC date and time WEEK() Return the week number WEEKDAY() Return the weekday index WEEKOFYEAR() Return the calendar week of the date (1-53) YEAR() Return the year YEARWEEK() Return the year and week For details, see here."}, {"url": "https://pingcap.com/docs/v2.0/sql/date-and-time-functions/", "title": "Date and Time Functions", "content": " Date and Time Functions The usage of date and time functions is similar to MySQL. For more information, see here.Date/Time functions Name Description ADDDATE() Add time values (intervals) to a date value ADDTIME() Add time CONVERT_TZ() Convert from one time zone to another CURDATE() Return the current date CURRENT_DATE(), CURRENT_DATE Synonyms for CURDATE() CURRENT_TIME(), CURRENT_TIME Synonyms for CURTIME() CURRENT_TIMESTAMP(), CURRENT_TIMESTAMP Synonyms for NOW() CURTIME() Return the current time DATE() Extract the date part of a date or datetime expression DATE_ADD() Add time values (intervals) to a date value DATE_FORMAT() Format date as specified DATE_SUB() Subtract a time value (interval) from a date DATEDIFF() Subtract two dates DAY() Synonym for DAYOFMONTH() DAYNAME() Return the name of the weekday DAYOFMONTH() Return the day of the month (0-31) DAYOFWEEK() Return the weekday index of the argument DAYOFYEAR() Return the day of the year (1-366) EXTRACT() Extract part of a date FROM_DAYS() Convert a day number to a date FROM_UNIXTIME() Format Unix timestamp as a date GET_FORMAT() Return a date format string HOUR() Extract the hour LAST_DAY Return the last day of the month for the argument LOCALTIME(), LOCALTIME Synonym for NOW() LOCALTIMESTAMP, LOCALTIMESTAMP() Synonym for NOW() MAKEDATE() Create a date from the year and day of year MAKETIME() Create time from hour, minute, second MICROSECOND() Return the microseconds from argument MINUTE() Return the minute from the argument MONTH() Return the month from the date passed MONTHNAME() Return the name of the month NOW() Return the current date and time PERIOD_ADD() Add a period to a year-month PERIOD_DIFF() Return the number of months between periods QUARTER() Return the quarter from a date argument SEC_TO_TIME() Converts seconds to ‘HH:MM:SS’ format SECOND() Return the second (0-59) STR_TO_DATE() Convert a string to a date SUBDATE() Synonym for DATE_SUB() when invoked with three arguments SUBTIME() Subtract times SYSDATE() Return the time at which the function executes TIME() Extract the time portion of the expression passed TIME_FORMAT() Format as time TIME_TO_SEC() Return the argument converted to seconds TIMEDIFF() Subtract time TIMESTAMP() With a single argument, this function returns the date or datetime expression; with two arguments, the sum of the arguments TIMESTAMPADD() Add an interval to a datetime expression TIMESTAMPDIFF() Subtract an interval from a datetime expression TO_DAYS() Return the date argument converted to days TO_SECONDS() Return the date or datetime argument converted to seconds since Year 0 UNIX_TIMESTAMP() Return a Unix timestamp UTC_DATE() Return the current UTC date UTC_TIME() Return the current UTC time UTC_TIMESTAMP() Return the current UTC date and time WEEK() Return the week number WEEKDAY() Return the weekday index WEEKOFYEAR() Return the calendar week of the date (1-53) YEAR() Return the year YEARWEEK() Return the year and week For details, see here."}, {"url": "https://pingcap.com/docs-cn/sql/literal-value-date-and-time-literals/", "title": "Date 和 Time 字面值", "content": " Date and Time Literals Date 跟 Time 字面值有几种格式,例如用字符串表示,或者直接用数字表示。在 TiDB 里面,当 TiDB 期望一个 Date 的时候,它会把 '2017-08-24', '20170824',20170824 当做是 Date。TiDB 的 Date 值有以下几种格式: 'YYYY-MM-DD' 或者 'YY-MM-DD',这里的 - 分隔符并不是严格的,可以是任意的标点符号。比如 '2017-08-24','2017&08&24', '2012@12^31' 都是一样的。唯一需要特别对待的是 ‘.’ 号,它被当做是小数点,用于分隔整数和小数部分。 Date 和 Time 部分可以被 ’T’ 分隔,它的作用跟空格符是一样的,例如 2017-8-24 10:42:00 跟 2017-8-24T10:42:00 是一样的。 'YYYYMMDDHHMMSS' 或者 'YYMMDDHHMMSS',例如 '20170824104520' 和 '170824104520' 被当做是 '2017-08-24 10:45:20',但是如果你提供了一个超过范围的值,例如'170824304520',那这就不是一个有效的 Date 字面值。 YYYYMMDDHHMMSS 或者 YYMMDDHHMMSS 注意这里没有单引号或者双引号,是一个数字。例如 20170824104520表示为 '2017-08-24 10:45:20'。 DATETIME 或者 TIMESTAMP 值可以接一个小数部分,用来表示微秒(精度最多到小数点后 6 位),用小数点 . 分隔。Dates 如果 year 部分只有两个数字,这是有歧义的(推荐使用四个数字的格式),TiDB 会尝试用以下的规则来解释: year 值如果在 70-99 范围,那么被转换成 1970-1999。 year 值如果在 00-69 范围,那么被转换成 2000-2069。 对于小于 10 的 month 或者 day 值,'2017-8-4' 跟 '2017-08-04' 是一样的。对于 Time 也是一样,比如 '2017-08-24 1:2:3' 跟 '2017-08-24 01:02:03'是一样的。在需要 Date 或者 Time 的语境下, 对于数值,TiDB 会根据数值的长度来选定指定的格式: 6 个数字,会被解释为 YYMMDD。 12 个数字,会被解释为 YYMMDDHHMMSS。 8 个数字,会解释为 YYYYMMDD。 14 个数字,会被解释为 YYYYMMDDHHMMSS。 对于 Time 类型,TiDB 用以下格式来表示: 'D HH:MM:SS',或者 'HH:MM:SS','HH:MM','D HH:MM','D HH','SS',这里的 D 表示 days,合法的范围是 0-34。 数值 HHMMSS,例如 231010 被解释为'23:10:10'。 数值 SS,MMSS,HHMMSS 都是可以被当做 Time。 Time 类型的小数点也是 .,精度最多小数点后 6 位。更多细节。"}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/literal-value-date-and-time-literals/", "title": "Date 和 Time 字面值", "content": " Date and Time Literals Date 跟 Time 字面值有几种格式,例如用字符串表示,或者直接用数字表示。在 TiDB 里面,当 TiDB 期望一个 Date 的时候,它会把 '2017-08-24', '20170824',20170824 当做是 Date。TiDB 的 Date 值有以下几种格式: 'YYYY-MM-DD' 或者 'YY-MM-DD',这里的 - 分隔符并不是严格的,可以是任意的标点符号。比如 '2017-08-24','2017&08&24', '2012@12^31' 都是一样的。唯一需要特别对待的是 ‘.’ 号,它被当做是小数点,用于分隔整数和小数部分。 Date 和 Time 部分可以被 ’T’ 分隔,它的作用跟空格符是一样的,例如 2017-8-24 10:42:00 跟 2017-8-24T10:42:00 是一样的。 'YYYYMMDDHHMMSS' 或者 'YYMMDDHHMMSS',例如 '20170824104520' 和 '170824104520' 被当做是 '2017-08-24 10:45:20',但是如果你提供了一个超过范围的值,例如'170824304520',那这就不是一个有效的 Date 字面值。 YYYYMMDDHHMMSS 或者 YYMMDDHHMMSS 注意这里没有单引号或者双引号,是一个数字。例如 20170824104520表示为 '2017-08-24 10:45:20'。 DATETIME 或者 TIMESTAMP 值可以接一个小数部分,用来表示微秒(精度最多到小数点后 6 位),用小数点 . 分隔。Dates 如果 year 部分只有两个数字,这是有歧义的(推荐使用四个数字的格式),TiDB 会尝试用以下的规则来解释: year 值如果在 70-99 范围,那么被转换成 1970-1999。 year 值如果在 00-69 范围,那么被转换成 2000-2069。 对于小于 10 的 month 或者 day 值,'2017-8-4' 跟 '2017-08-04' 是一样的。对于 Time 也是一样,比如 '2017-08-24 1:2:3' 跟 '2017-08-24 01:02:03'是一样的。在需要 Date 或者 Time 的语境下, 对于数值,TiDB 会根据数值的长度来选定指定的格式: 6 个数字,会被解释为 YYMMDD。 12 个数字,会被解释为 YYMMDDHHMMSS。 8 个数字,会解释为 YYYYMMDD。 14 个数字,会被解释为 YYYYMMDDHHMMSS。 对于 Time 类型,TiDB 用以下格式来表示: 'D HH:MM:SS',或者 'HH:MM:SS','HH:MM','D HH:MM','D HH','SS',这里的 D 表示 days,合法的范围是 0-34。 数值 HHMMSS,例如 231010 被解释为'23:10:10'。 数值 SS,MMSS,HHMMSS 都是可以被当做 Time。 Time 类型的小数点也是 .,精度最多小数点后 6 位。更多细节。"}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/literal-value-date-and-time-literals/", "title": "Date 和 Time 字面值", "content": " Date and Time Literals Date 跟 Time 字面值有几种格式,例如用字符串表示,或者直接用数字表示。在 TiDB 里面,当 TiDB 期望一个 Date 的时候,它会把 '2017-08-24', '20170824',20170824 当做是 Date。TiDB 的 Date 值有以下几种格式: 'YYYY-MM-DD' 或者 'YY-MM-DD',这里的 - 分隔符并不是严格的,可以是任意的标点符号。比如 '2017-08-24','2017&08&24', '2012@12^31' 都是一样的。唯一需要特别对待的是 ‘.’ 号,它被当做是小数点,用于分隔整数和小数部分。 Date 和 Time 部分可以被 ’T’ 分隔,它的作用跟空格符是一样的,例如 2017-8-24 10:42:00 跟 2017-8-24T10:42:00 是一样的。 'YYYYMMDDHHMMSS' 或者 'YYMMDDHHMMSS',例如 '20170824104520' 和 '170824104520' 被当做是 '2017-08-24 10:45:20',但是如果你提供了一个超过范围的值,例如'170824304520',那这就不是一个有效的 Date 字面值。 YYYYMMDDHHMMSS 或者 YYMMDDHHMMSS 注意这里没有单引号或者双引号,是一个数字。例如 20170824104520表示为 '2017-08-24 10:45:20'。 DATETIME 或者 TIMESTAMP 值可以接一个小数部分,用来表示微秒(精度最多到小数点后 6 位),用小数点 . 分隔。Dates 如果 year 部分只有两个数字,这是有歧义的(推荐使用四个数字的格式),TiDB 会尝试用以下的规则来解释: year 值如果在 70-99 范围,那么被转换成 1970-1999。 year 值如果在 00-69 范围,那么被转换成 2000-2069。 对于小于 10 的 month 或者 day 值,'2017-8-4' 跟 '2017-08-04' 是一样的。对于 Time 也是一样,比如 '2017-08-24 1:2:3' 跟 '2017-08-24 01:02:03'是一样的。在需要 Date 或者 Time 的语境下, 对于数值,TiDB 会根据数值的长度来选定指定的格式: 6 个数字,会被解释为 YYMMDD。 12 个数字,会被解释为 YYMMDDHHMMSS。 8 个数字,会解释为 YYYYMMDD。 14 个数字,会被解释为 YYYYMMDDHHMMSS。 对于 Time 类型,TiDB 用以下格式来表示: 'D HH:MM:SS',或者 'HH:MM:SS','HH:MM','D HH:MM','D HH','SS',这里的 D 表示 days,合法的范围是 0-34。 数值 HHMMSS,例如 231010 被解释为'23:10:10'。 数值 SS,MMSS,HHMMSS 都是可以被当做 Time。 Time 类型的小数点也是 .,精度最多小数点后 6 位。更多细节。"}, {"url": "https://pingcap.com/docs/tools/data-migration-deployment/", "title": "Deploy Data Migration Using DM-Ansible", "content": " Deploy Data Migration Using DM-Ansible DM-Ansible is a cluster deployment tool developed by PingCAP based on the Playbooks feature of Ansible (an IT automation tool). This guide shows how to quickly deploy a Data Migration (DM) cluster using DM-Ansible.Prepare Before you start, make sure you have the following machines as required. Several target machines that meet the following requirements: CentOS 7.3 (64-bit) or later, x86_64 architecture (AMD64) Network between machines Closing the firewall, or opening the service port A Control Machine that meets the following requirements: Note: The Control Machine can be one of the target machines. CentOS 7.3 (64-bit) or later, with Python 2.7 installed Access to the Internet Step 1: Install system dependencies on the Control Machine Log in to the Control Machine using the root user account, and run the corresponding command according to your operating system. If you use a Control Machine installed with CentOS 7, run the following command:# yum -y install epel-release git curl sshpass # yum -y install python-pip If you use a Control Machine installed with Ubuntu, run the following command:# apt-get -y install git curl sshpass python-pip Step 2: Create the tidb user on the Control Machine and generate the SSH key Make sure you have logged in to the Control Machine using the root user account, and then run the following command. Create the tidb user.# useradd -m -d /home/tidb tidb Set a password for the tidb user account.# passwd tidb Configure sudo without password for the tidb user account by adding tidb ALL=(ALL) NOPASSWD: ALL to the end of the sudo file:# visudo tidb ALL=(ALL) NOPASSWD: ALL Generate the SSH key.Execute the su command to switch the user from root to tidb.# su - tidb Create the SSH key for the tidb user account and hit the Enter key when Enter passphrase is prompted. After successful execution, the SSH private key file is /home/tidb/.ssh/id_rsa, and the SSH public key file is /home/tidb/.ssh/id_rsa.pub.$ ssh-keygen -t rsa Generating public/private rsa key pair. Enter file in which to save the key (/home/tidb/.ssh/id_rsa): Created directory '/home/tidb/.ssh'. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/tidb/.ssh/id_rsa. Your public key has been saved in /home/tidb/.ssh/id_rsa.pub. The key fingerprint is: SHA256:eIBykszR1KyECA/h0d7PRKz4fhAeli7IrVphhte7/So tidb@172.16.10.49 The key's randomart image is: +---[RSA 2048]----+ |=+o+.o. | |o=o+o.oo | | .O.=.= | | . B.B + | |o B * B S | | * + * + | | o + . | | o E+ . | |o ..+o. | +----[SHA256]-----+ Step 3: Download DM-Ansible to the Control Machine Log in to the Control Machine using the tidb user account and enter the /home/tidb directory. Run the following command to download DM-Ansible.$ wget http://download.pingcap.org/dm-ansible.tar.gz Step 4: Install Ansible and its dependencies on the Control Machine Make sure you have logged in to the Control Machine using the tidb user account.It is required to use pip to install Ansible and its dependencies, otherwise a compatibility issue occurs. Currently, DM-Ansible is compatible with Ansible 2.5 or later. Install Ansible and the dependencies on the Control Machine:$ tar -xzvf dm-ansible.tar.gz $ cd /home/tidb/dm-ansible $ sudo pip install -r ./requirements.txt Ansible and the related dependencies are in the dm-ansible/requirements.txt file. View the version of Ansible:$ ansible --version ansible 2.5.0 Step 5: Configure the SSH mutual trust and sudo rules on the Control Machine Make sure you have logged in to the Control Machine using the tidb user account. Add the IPs of your deployment target machines to the [servers] section of the hosts.ini file.$ cd /home/tidb/dm-ansible $ vi hosts.ini [servers] 172.16.10.71 172.16.10.72 172.16.10.73 [all:vars] username = tidb Run the following command and input the root user account password of your deployment target machines.$ ansible-playbook -i hosts.ini create_users.yml -u root -k This step creates the tidb user account on the deployment target machines, configures the sudo rules and the SSH mutual trust between the Control Machine and the deployment target machines. Step 6: Download DM and the monitoring component installation package to the Control Machine Make sure the Control Machine is connected to the Internet and run the following command:ansible-playbook local_prepare.yml Step 7: Edit the inventory.ini file to orchestrate the DM cluster Log in to the Control Machine using the tidb user account, and edit the /home/tidb/dm-ansible/inventory.ini file to orchestrate the DM cluster. Note: It is required to use the internal IP address to deploy. If the SSH port of the target machines is not the default 22 port, you need to add the ansible_port variable, as shown in the following example: dm-worker1 ansible_host=172.16.10.72 ansible_port=5555 server_id=101 mysql_host=172.16.10.72 mysql_user=root mysql_password='VjX8cEeTX+qcvZ3bPaO4h0C80pe/1aU=' mysql_port=3306 You can choose one of the following two types of cluster topology according to your scenario: The cluster topology of a single DM-worker instance on each nodeGenerally, it is recommended to deploy one DM-worker instance on each node. Howerver, if the CPU and memory of your machine is much better than the required in Hardware and Software Requirements, and you have more than 2 disks in one node or the capacity of one SSD is larger than 2 TB, you can deploy no more than 2 DM-worker instances on a single node. The cluster topology of multiple DM-worker instances on each node Option 1: Use the cluster topology of a single DM-worker instance on each node Name Host IP Services node1 172.16.10.71 DM-master, Prometheus, Grafana, Alertmanager node2 172.16.10.72 DM-worker1 node3 172.16.10.73 DM-worker2 ## DM modules [dm_master_servers] dm_master ansible_host=172.16.10.71 [dm_worker_servers] dm_worker1 ansible_host=172.16.10.72 server_id=101 mysql_host=172.16.10.81 mysql_user=root mysql_password='VjX8cEeTX+qcvZ3bPaO4h0C80pe/1aU=' mysql_port=3306 dm_worker2 ansible_host=172.16.10.73 server_id=102 mysql_host=172.16.10.82 mysql_user=root mysql_password='VjX8cEeTX+qcvZ3bPaO4h0C80pe/1aU=' mysql_port=3306 ## Monitoring modules [prometheus_servers] prometheus ansible_host=172.16.10.71 [grafana_servers] grafana ansible_host=172.16.10.71 [alertmanager_servers] alertmanager ansible_host=172.16.10.71 ## Global variables [all:vars] cluster_name = test-cluster ansible_user = tidb dm_version = latest deploy_dir = /data1/dm grafana_admin_user = "admin" grafana_admin_password = "admin" Option 2: Use the cluster topology of multiple DM-worker instances on each node Name Host IP Services node1 172.16.10.71 DM-master, Prometheus, Grafana, Alertmanager node2 172.16.10.72 DM-worker1-1, DM-worker1-2 node3 172.16.10.73 DM-worker2-1, DM-worker2-2 When you edit the inventory.ini file, pay attention to distinguish between the following variables: server_id, deploy_dir, dm_worker_port, and dm_worker_status_port.## DM modules [dm_master_servers] dm_master ansible_host=172.16.10.71 [dm_worker_servers] dm_worker1_1 ansible_host=172.16.10.72 server_id=101 deploy_dir=/data1/dm_worker dm_worker_port=10081 dm_worker_status_port=10082 mysql_host=172.16.10.81 mysql_user=root mysql_password='VjX8cEeTX+qcvZ3bPaO4h0C80pe/1aU=' mysql_port=3306 dm_worker1_2 ansible_host=172.16.10.72 server_id=102 deploy_dir=/data2/dm_worker dm_worker_port=10083 dm_worker_status_port=10084 mysql_host=172.16.10.82 mysql_user=root mysql_password='VjX8cEeTX+qcvZ3bPaO4h0C80pe/1aU=' mysql_port=3306 dm_worker2_1 ansible_host=172.16.10.73 server_id=103 deploy_dir=/data1/dm_worker dm_worker_port=10081 dm_worker_status_port=10082 mysql_host=172.16.10.83 mysql_user=root mysql_password='VjX8cEeTX+qcvZ3bPaO4h0C80pe/1aU=' mysql_port=3306 dm_worker2_2 ansible_host=172.16.10.73 server_id=104 …"}, {"url": "https://pingcap.com/tidb-academy/mysql_dbas/tidb-overview/lab/", "title": "Deploy KOST Stack on GKE", "content": " Deploy KOST Stack on GKE "}, {"url": "https://pingcap.com/docs/op-guide/offline-ansible-deployment/", "title": "Deploy TiDB Offline Using Ansible", "content": " Deploy TiDB Offline Using Ansible This guide describes how to deploy a TiDB cluster offline using Ansible.Prepare Before you start, make sure that you have: A download machine The machine must have access to the Internet in order to download TiDB-Ansible, TiDB and related packages. For Linux operating system, it is recommended to install CentOS 7.3 or later. Several target machines and one Control Machine For system requirements and configuration, see Prepare the environment. It is acceptable without access to the Internet. Step 1: Install system dependencies on the Control Machine Take the following steps to install system dependencies on the Control Machine installed with the CentOS 7 system. Download the pip offline installation package to the Control Machine.# tar -xzvf ansible-system-rpms.el7.tar.gz # cd ansible-system-rpms.el7 # chmod u+x install_ansible_system_rpms.sh # ./install_ansible_system_rpms.sh Note: This offline installation package includes pip and sshpass, and only supports the CentOS 7 system. After the installation is finished, you can use pip -V to check whether it is successfully installed.# pip -V pip 8.1.2 from /usr/lib/python2.7/site-packages (python 2.7) Note: If pip is already installed to your system, make sure that the version is 8.1.2 or later. Otherwise, compatibility error occurs when you install Ansible and its dependencies offline. Step 2: Create the tidb user on the Control Machine and generate the SSH key See Create the tidb user on the Control Machine and generate the SSH key.Step 3: Install Ansible and its dependencies offline on the Control Machine Currently, the TiDB 2.0 GA version and the master version are compatible with Ansible 2.5. Ansible and the related dependencies are in the tidb-ansible/requirements.txt file. Download Ansible 2.5 offline installation package. Install Ansible and its dependencies offline.# tar -xzvf ansible-2.5.0-pip.tar.gz # cd ansible-2.5.0-pip/ # chmod u+x install_ansible.sh # ./install_ansible.sh View the version of Ansible.After Ansible is installed, you can view the version using ansible --version.# ansible --version ansible 2.5.0 Step 4: Download TiDB-Ansible and TiDB packages on the download machine Install Ansible on the download machine.Use the following method to install Ansible online on the download machine installed with the CentOS 7 system. After Ansible is installed, you can view the version using ansible --version.# yum install epel-release # yum install ansible curl # ansible --version ansible 2.5.0 Note: Make sure that the version of Ansible is 2.5, otherwise a compatibility issue occurs. Download TiDB-Ansible.Use the following command to download the corresponding version of TiDB-Ansible from the GitHub TiDB-Ansible project. The default folder name is tidb-ansible. The following are examples of downloading various versions, and you can turn to the official team for advice on which version to choose.Download the 2.0 version:git clone -b release-2.0 https://github.com/pingcap/tidb-ansible.git orDownload the master version:git clone https://github.com/pingcap/tidb-ansible.git Run the local_prepare.yml playbook, and download TiDB binary online to the download machine.cd tidb-ansible ansible-playbook local_prepare.yml After running the above command, copy the tidb-ansible folder to the /home/tidb directory of the Control Machine. The ownership authority of the file must be the tidb user. Step 5: Configure the SSH mutual trust and sudo rules on the Control Machine See Configure the SSH mutual trust and sudo rules on the Control Machine.Step 6: Install the NTP service on the target machines See Install the NTP service on the target machines. Note: If the time and time zone of all your target machines are same, the NTP service is on and is normally synchronizing time, you can ignore this step. See How to check whether the NTP service is normal. Step 7: Configure the CPUfreq governor mode on the target machine See Configure the CPUfreq governor mode on the target machine.Step 8: Mount the data disk ext4 filesystem with options on the target machines See Mount the data disk ext4 filesystem with options on the target machines.Step 9: Edit the inventory.ini file to orchestrate the TiDB cluster See Edit the inventory.ini file to orchestrate the TiDB cluster.Step 10: Deploy the TiDB cluster You do not need to run the playbook in ansible-playbook local_prepare.yml. You can use the Report button on the Grafana Dashboard to generate the PDF file. This function depends on the fontconfig package and English fonts. To use this function, download the offline installation package, upload it to the grafana_servers machine, and install it. This package includes fontconfig and open-sans-fonts, and only supports the CentOS 7 system.$ tar -xzvf grafana-font-rpms.el7.tar.gz $ cd grafana-font-rpms.el7 $ chmod u+x install_grafana_font_rpms.sh $ ./install_grafana_font_rpms.sh See Deploy the TiDB cluster. Test the TiDB cluster See Test the TiDB cluster."}, {"url": "https://pingcap.com/docs/v2.0/op-guide/offline-ansible-deployment/", "title": "Deploy TiDB Offline Using Ansible", "content": " Deploy TiDB Offline Using Ansible This guide describes how to deploy a TiDB cluster offline using Ansible.Prepare Before you start, make sure that you have: A download machine The machine must have access to the Internet in order to download TiDB-Ansible, TiDB and related packages. For Linux operating system, it is recommended to install CentOS 7.3 or later. Several target machines and one Control Machine For system requirements and configuration, see Prepare the environment. It is acceptable without access to the Internet. Step 1: Install system dependencies on the Control Machine Take the following steps to install system dependencies on the Control Machine installed with the CentOS 7 system. Download the pip offline installation package to the Control Machine.# tar -xzvf ansible-system-rpms.el7.tar.gz # cd ansible-system-rpms.el7 # chmod u+x install_ansible_system_rpms.sh # ./install_ansible_system_rpms.sh Note: This offline installation package includes pip and sshpass, and only supports the CentOS 7 system. After the installation is finished, you can use pip -V to check whether it is successfully installed.# pip -V pip 8.1.2 from /usr/lib/python2.7/site-packages (python 2.7) Note: If pip is already installed to your system, make sure that the version is 8.1.2 or later. Otherwise, compatibility error occurs when you install Ansible and its dependencies offline. Step 2: Create the tidb user on the Control Machine and generate the SSH key See Create the tidb user on the Control Machine and generate the SSH key.Step 3: Install Ansible and its dependencies offline on the Control Machine Currently, the TiDB 2.0 GA version and the master version are compatible with Ansible 2.5. Ansible and the related dependencies are in the tidb-ansible/requirements.txt file. Download Ansible 2.5 offline installation package. Install Ansible and its dependencies offline.# tar -xzvf ansible-2.5.0-pip.tar.gz # cd ansible-2.5.0-pip/ # chmod u+x install_ansible.sh # ./install_ansible.sh View the version of Ansible.After Ansible is installed, you can view the version using ansible --version.# ansible --version ansible 2.5.0 Step 4: Download TiDB-Ansible and TiDB packages on the download machine Install Ansible on the download machine.Use the following method to install Ansible online on the download machine installed with the CentOS 7 system. After Ansible is installed, you can view the version using ansible --version.# yum install epel-release # yum install ansible curl # ansible --version ansible 2.5.0 Note: Make sure that the version of Ansible is 2.5, otherwise a compatibility issue occurs. Download TiDB-Ansible.Use the following command to download the corresponding version of TiDB-Ansible from the GitHub TiDB-Ansible project. The default folder name is tidb-ansible. The following are examples of downloading various versions, and you can turn to the official team for advice on which version to choose.Download the 2.0 version:git clone -b release-2.0 https://github.com/pingcap/tidb-ansible.git orDownload the master version:git clone https://github.com/pingcap/tidb-ansible.git Run the local_prepare.yml playbook, and download TiDB binary online to the download machine.cd tidb-ansible ansible-playbook local_prepare.yml After running the above command, copy the tidb-ansible folder to the /home/tidb directory of the Control Machine. The ownership authority of the file must be the tidb user. Step 5: Configure the SSH mutual trust and sudo rules on the Control Machine See Configure the SSH mutual trust and sudo rules on the Control Machine.Step 6: Install the NTP service on the target machines See Install the NTP service on the target machines. Note: If the time and time zone of all your target machines are same, the NTP service is on and is normally synchronizing time, you can ignore this step. See How to check whether the NTP service is normal. Step 7: Configure the CPUfreq governor mode on the target machine See Configure the CPUfreq governor mode on the target machine.Step 8: Mount the data disk ext4 filesystem with options on the target machines See Mount the data disk ext4 filesystem with options on the target machines.Step 9: Edit the inventory.ini file to orchestrate the TiDB cluster See Edit the inventory.ini file to orchestrate the TiDB cluster.Step 10: Deploy the TiDB cluster You do not need to run the playbook in ansible-playbook local_prepare.yml. You can use the Report button on the Grafana Dashboard to generate the PDF file. This function depends on the fontconfig package and English fonts. To use this function, download the offline installation package, upload it to the grafana_servers machine, and install it. This package includes fontconfig and open-sans-fonts, and only supports the CentOS 7 system.$ tar -xzvf grafana-font-rpms.el7.tar.gz $ cd grafana-font-rpms.el7 $ chmod u+x install_grafana_font_rpms.sh $ ./install_grafana_font_rpms.sh See Deploy the TiDB cluster. Test the TiDB cluster See Test the TiDB cluster."}, {"url": "https://pingcap.com/docs/op-guide/ansible-deployment/", "title": "Deploy TiDB Using Ansible", "content": " Deploy TiDB Using Ansible This guide describes how to deploy a TiDB cluster using Ansible. For the production environment, it is recommended to deploy TiDB using Ansible.Overview Ansible is an IT automation tool that can configure systems, deploy software, and orchestrate more advanced IT tasks such as continuous deployments or zero downtime rolling updates.TiDB-Ansible is a TiDB cluster deployment tool developed by PingCAP, based on Ansible playbook. TiDB-Ansible enables you to quickly deploy a new TiDB cluster which includes PD, TiDB, TiKV, and the cluster monitoring modules.You can use the TiDB-Ansible configuration file to set up the cluster topology and complete all the following operation tasks: Initialize operating system parameters Deploy the whole TiDB cluster Start the TiDB cluster Stop the TiDB cluster Modify component configuration Scale the TiDB cluster Upgrade the component version Enable the cluster binlog Clean up data of the TiDB cluster Destroy the TiDB cluster Prepare Before you start, make sure you have: Several target machines that meet the following requirements: 4 or more machinesA standard TiDB cluster contains 6 machines. You can use 4 machines for testing. For more details, see Software and Hardware Requirements. CentOS 7.3 (64 bit) or later, x86_64 architecture (AMD64) Network between machines Note: When you deploy TiDB using Ansible, use SSD disks for the data directory of TiKV and PD nodes. Otherwise, it cannot pass the check. If you only want to try TiDB out and explore the features, it is recommended to deploy TiDB using Docker Compose on a single machine. A Control Machine that meets the following requirements: Note: The Control Machine can be one of the target machines. CentOS 7.3 (64 bit) or later with Python 2.7 installed Access to the Internet Step 1: Install system dependencies on the Control Machine Log in to the Control Machine using the root user account, and run the corresponding command according to your operating system. If you use a Control Machine installed with CentOS 7, run the following command:# yum -y install epel-release git curl sshpass # yum -y install python-pip If you use a Control Machine installed with Ubuntu, run the following command:# apt-get -y install git curl sshpass python-pip Step 2: Create the tidb user on the Control Machine and generate the SSH key Make sure you have logged in to the Control Machine using the root user account, and then run the following command. Create the tidb user.# useradd -m -d /home/tidb tidb Set a password for the tidb user account.# passwd tidb Configure sudo without password for the tidb user account by adding tidb ALL=(ALL) NOPASSWD: ALL to the end of the sudo file:# visudo tidb ALL=(ALL) NOPASSWD: ALL Generate the SSH key.Execute the su command to switch the user from root to tidb.# su - tidb Create the SSH key for the tidb user account and hit the Enter key when Enter passphrase is prompted. After successful execution, the SSH private key file is /home/tidb/.ssh/id_rsa, and the SSH public key file is /home/tidb/.ssh/id_rsa.pub.$ ssh-keygen -t rsa Generating public/private rsa key pair. Enter file in which to save the key (/home/tidb/.ssh/id_rsa): Created directory '/home/tidb/.ssh'. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/tidb/.ssh/id_rsa. Your public key has been saved in /home/tidb/.ssh/id_rsa.pub. The key fingerprint is: SHA256:eIBykszR1KyECA/h0d7PRKz4fhAeli7IrVphhte7/So tidb@172.16.10.49 The key's randomart image is: +---[RSA 2048]----+ |=+o+.o. | |o=o+o.oo | | .O.=.= | | . B.B + | |o B * B S | | * + * + | | o + . | | o E+ . | |o ..+o. | +----[SHA256]-----+ Step 3: Download TiDB-Ansible to the Control Machine Log in to the Control Machine using the tidb user account and enter the /home/tidb directory. The corresponding relationship between the tidb-ansible branch and TiDB versions is as follows: tidb-ansible branch TiDB version Note release-2.0 2.0 version The latest 2.0 stable version. You can use it in the production environment. release-2.1 2.1 version The latest 2.1 stable version. You can use it in the production environment (recommended). master master version This version includes the latest features with a daily update. Download the corresponding TiDB-Ansible branch from the TiDB-Ansible project. The default folder name is tidb-ansible. Download the 2.0 version:$ git clone -b release-2.0 https://github.com/pingcap/tidb-ansible.git Download the 2.1 version:$ git clone -b release-2.1 https://github.com/pingcap/tidb-ansible.git Download the master version:$ git clone https://github.com/pingcap/tidb-ansible.git Note: It is required to download tidb-ansible to the /home/tidb directory using the tidb user account. If you download it to the /root directory, a privilege issue occurs. If you have questions regarding which version to use, email to info@pingcap.com for more information or file an issue. Step 4: Install Ansible and its dependencies on the Control Machine Make sure you have logged in to the Control Machine using the tidb user account.It is required to use pip to install Ansible and its dependencies, otherwise a compatibility issue occurs. Currently, the release-2.0, release-2.1, and master branches of TiDB-Ansible are compatible with Ansible 2.4 and Ansible 2.5. Install Ansible and the dependencies on the Control Machine:$ cd /home/tidb/tidb-ansible $ sudo pip install -r ./requirements.txt Ansible and the related dependencies are in the tidb-ansible/requirements.txt file. View the version of Ansible:$ ansible --version ansible 2.5.0 Step 5: Configure the SSH mutual trust and sudo rules on the Control Machine Make sure you have logged in to the Control Machine using the tidb user account. Add the IPs of your target machines to the [servers] section of the hosts.ini file.$ cd /home/tidb/tidb-ansible $ vi hosts.ini [servers] 172.16.10.1 172.16.10.2 172.16.10.3 172.16.10.4 172.16.10.5 172.16.10.6 [all:vars] username = tidb ntp_server = pool.ntp.org Run the following command and input the root user account password of your target machines.$ ansible-playbook -i hosts.ini create_users.yml -u root -k This step creates the tidb user account on the target machines, configures the sudo rules and the SSH mutual trust between the Control Machine and the target machines. To configure the SSH mutual trust and sudo without password manually, see How to manually configure the SSH mutual trust and sudo without password Step 6: Install the NTP service on the target machines Note: If the time and time zone of all your target machines are same, the NTP service is on and is normally synchronizing time, you can ignore this step. See How to check whether the NTP service is normal. Make sure you have logged in to the Control Machine using the tidb user account, run the following command:$ cd /home/tidb/tidb-ansible $ ansible-playbook -i hosts.ini deploy_ntp.yml -u tidb -b The NTP service is installed and started using the software repository that comes with the system on the target machines. The default NTP server list in the installation package is used. The related server parameter is in the /etc/ntp.conf configuration file.To make the NTP service start synchronizing as soon as possible, the system executes the ntpdate command to set the local date and time by polling ntp_server in the hosts.ini file. The default server is pool.ntp.org, and you can also replace it with your NTP server.Step 7: Configure the CPUfreq governor mode on the target machine For details about CPUfreq, see the CPUfreq Governor documentation.Set the CPUfreq governor mode to performance to make full use of CPU performance.Check the governor modes supported by the system You can run the cpupower frequency-info --governors command to check the governor modes which the system supports:# cpupower frequency-info --governors analyzing CPU 0: available cpufreq governors: …"}, {"url": "https://pingcap.com/docs/v2.0/op-guide/ansible-deployment/", "title": "Deploy TiDB Using Ansible", "content": " Deploy TiDB Using Ansible This guide describes how to deploy a TiDB cluster using Ansible. For the production environment, it is recommended to deploy TiDB using Ansible.Overview Ansible is an IT automation tool that can configure systems, deploy software, and orchestrate more advanced IT tasks such as continuous deployments or zero downtime rolling updates.TiDB-Ansible is a TiDB cluster deployment tool developed by PingCAP, based on Ansible playbook. TiDB-Ansible enables you to quickly deploy a new TiDB cluster which includes PD, TiDB, TiKV, and the cluster monitoring modules.You can use the TiDB-Ansible configuration file to set up the cluster topology and complete all the following operation tasks: Initialize operating system parameters Deploy the whole TiDB cluster Start the TiDB cluster Stop the TiDB cluster Modify component configuration Scale the TiDB cluster Upgrade the component version Clean up data of the TiDB cluster Destroy the TiDB cluster Prepare Before you start, make sure you have: Several target machines that meet the following requirements: 4 or more machinesA standard TiDB cluster contains 6 machines. You can use 4 machines for testing. For more details, see Software and Hardware Requirements. CentOS 7.3 (64 bit) or later, x86_64 architecture (AMD64) Network between machines Note: When you deploy TiDB using Ansible, use SSD disks for the data directory of TiKV and PD nodes. Otherwise, it cannot pass the check. If you only want to try TiDB out and explore the features, it is recommended to deploy TiDB using Docker Compose on a single machine. A Control Machine that meets the following requirements: Note: The Control Machine can be one of the target machines. CentOS 7.3 (64 bit) or later with Python 2.7 installed Access to the Internet Step 1: Install system dependencies on the Control Machine Log in to the Control Machine using the root user account, and run the corresponding command according to your operating system. If you use a Control Machine installed with CentOS 7, run the following command:# yum -y install epel-release git curl sshpass # yum -y install python-pip If you use a Control Machine installed with Ubuntu, run the following command:# apt-get -y install git curl sshpass python-pip Step 2: Create the tidb user on the Control Machine and generate the SSH key Make sure you have logged in to the Control Machine using the root user account, and then run the following command. Create the tidb user.# useradd -m -d /home/tidb tidb Set a password for the tidb user account.# passwd tidb Configure sudo without password for the tidb user account by adding tidb ALL=(ALL) NOPASSWD: ALL to the end of the sudo file:# visudo tidb ALL=(ALL) NOPASSWD: ALL Generate the SSH key.Execute the su command to switch the user from root to tidb. Create the SSH key for the tidb user account and hit the Enter key when Enter passphrase is prompted. After successful execution, the SSH private key file is /home/tidb/.ssh/id_rsa, and the SSH public key file is /home/tidb/.ssh/id_rsa.pub.# su - tidb $ ssh-keygen -t rsa Generating public/private rsa key pair. Enter file in which to save the key (/home/tidb/.ssh/id_rsa): Created directory '/home/tidb/.ssh'. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/tidb/.ssh/id_rsa. Your public key has been saved in /home/tidb/.ssh/id_rsa.pub. The key fingerprint is: SHA256:eIBykszR1KyECA/h0d7PRKz4fhAeli7IrVphhte7/So tidb@172.16.10.49 The key's randomart image is: +---[RSA 2048]----+ |=+o+.o. | |o=o+o.oo | | .O.=.= | | . B.B + | |o B * B S | | * + * + | | o + . | | o E+ . | |o ..+o. | +----[SHA256]-----+ Step 3: Download TiDB-Ansible to the Control Machine Log in to the Control Machine using the tidb user account and enter the /home/tidb directory. Download the corresponding TiDB-Ansible version from the TiDB-Ansible project. The default folder name is tidb-ansible. Download the 2.0 GA version:$ git clone -b release-2.0 https://github.com/pingcap/tidb-ansible.git Download the master version:$ git clone https://github.com/pingcap/tidb-ansible.git Note: It is required to download tidb-ansible to the /home/tidb directory using the tidb user account. If you download it to the /root directory, a privilege issue occurs. If you have questions regarding which version to use, email to info@pingcap.com for more information or file an issue. Step 4: Install Ansible and its dependencies on the Control Machine Make sure you have logged in to the Control Machine using the tidb user account.It is required to use pip to install Ansible and its dependencies, otherwise a compatibility issue occurs. Currently, the TiDB 2.0 GA version and the master version are compatible with Ansible 2.4 and Ansible 2.5. Install Ansible and the dependencies on the Control Machine:$ cd /home/tidb/tidb-ansible $ sudo pip install -r ./requirements.txt Ansible and the related dependencies are in the tidb-ansible/requirements.txt file. View the version of Ansible:$ ansible --version ansible 2.5.0 Step 5: Configure the SSH mutual trust and sudo rules on the Control Machine Make sure you have logged in to the Control Machine using the tidb user account. Add the IPs of your target machines to the [servers] section of the hosts.ini file.$ cd /home/tidb/tidb-ansible $ vi hosts.ini [servers] 172.16.10.1 172.16.10.2 172.16.10.3 172.16.10.4 172.16.10.5 172.16.10.6 [all:vars] username = tidb ntp_server = pool.ntp.org Run the following command and input the root user account password of your target machines.$ ansible-playbook -i hosts.ini create_users.yml -u root -k This step creates the tidb user account on the target machines, configures the sudo rules and the SSH mutual trust between the Control Machine and the target machines. To configure the SSH mutual trust and sudo without password manually, see How to manually configure the SSH mutual trust and sudo without password Step 6: Install the NTP service on the target machines Note: If the time and time zone of all your target machines are same, the NTP service is on and is normally synchronizing time, you can ignore this step. See How to check whether the NTP service is normal. Make sure you have logged in to the Control Machine using the tidb user account, run the following command:$ cd /home/tidb/tidb-ansible $ ansible-playbook -i hosts.ini deploy_ntp.yml -u tidb -b The NTP service is installed and started using the software repository that comes with the system on the target machines. The default NTP server list in the installation package is used. The related server parameter is in the /etc/ntp.conf configuration file.To make the NTP service start synchronizing as soon as possible, the system executes the ntpdate command to set the local date and time by polling ntp_server in the hosts.ini file. The default server is pool.ntp.org, and you can also replace it with your NTP server.Step 7: Configure the CPUfreq governor mode on the target machine For details about CPUfreq, see the CPUfreq Governor documentation.Set the CPUfreq governor mode to performance to make full use of CPU performance.Check the governor modes supported by the system You can run the cpupower frequency-info --governors command to check the governor modes which the system supports:# cpupower frequency-info --governors analyzing CPU 0: available cpufreq governors: performance powersave Taking the above code for example, the system supports the performance and powersave modes. Note: As the following shows, if it returns “Not Available”, it means that the current system does not support CPUfreq configuration and you can skip this step. # cpupower frequency-info --governors analyzing CPU 0: available cpufreq governors: Not Available Check the current governor mode You can run the cpupower frequency-info --policy command to check the current CPUfreq governor mode:# cpupower frequency-info --policy analyzing CPU 0: current policy: …"}, {"url": "https://pingcap.com/docs/op-guide/docker-deployment/", "title": "Deploy TiDB Using Docker", "content": " Deploy TiDB Using Docker This page shows you how to manually deploy a multi-node TiDB cluster on multiple machines using Docker.To learn more, see TiDB architecture and Software and Hardware Requirements.Preparation Before you start, make sure that you have: Installed the latest version of Docker Pulled the latest images of TiDB, TiKV and PD from Docker Hub. If not, pull the images using the following commands:docker pull pingcap/tidb:latest docker pull pingcap/tikv:latest docker pull pingcap/pd:latest Multi nodes deployment Assume we have 6 machines with the following details: Host Name IP Services Data Path host1 192.168.1.101 PD1 & TiDB /data host2 192.168.1.102 PD2 /data host3 192.168.1.103 PD3 /data host4 192.168.1.104 TiKV1 /data host5 192.168.1.105 TiKV2 /data host6 192.168.1.106 TiKV3 /data 1. Start PD Start PD1 on the host1docker run -d --name pd1 -p 2379:2379 -p 2380:2380 -v /etc/localtime:/etc/localtime:ro -v /data:/data pingcap/pd:latest --name="pd1" --data-dir="/data/pd1" --client-urls="http://0.0.0.0:2379" --advertise-client-urls="http://192.168.1.101:2379" --peer-urls="http://0.0.0.0:2380" --advertise-peer-urls="http://192.168.1.101:2380" --initial-cluster="pd1=http://192.168.1.101:2380,pd2=http://192.168.1.102:2380,pd3=http://192.168.1.103:2380" Start PD2 on the host2docker run -d --name pd2 -p 2379:2379 -p 2380:2380 -v /etc/localtime:/etc/localtime:ro -v /data:/data pingcap/pd:latest --name="pd2" --data-dir="/data/pd2" --client-urls="http://0.0.0.0:2379" --advertise-client-urls="http://192.168.1.102:2379" --peer-urls="http://0.0.0.0:2380" --advertise-peer-urls="http://192.168.1.102:2380" --initial-cluster="pd1=http://192.168.1.101:2380,pd2=http://192.168.1.102:2380,pd3=http://192.168.1.103:2380" Start PD3 on the host3docker run -d --name pd3 -p 2379:2379 -p 2380:2380 -v /etc/localtime:/etc/localtime:ro -v /data:/data pingcap/pd:latest --name="pd3" --data-dir="/data/pd3" --client-urls="http://0.0.0.0:2379" --advertise-client-urls="http://192.168.1.103:2379" --peer-urls="http://0.0.0.0:2380" --advertise-peer-urls="http://192.168.1.103:2380" --initial-cluster="pd1=http://192.168.1.101:2380,pd2=http://192.168.1.102:2380,pd3=http://192.168.1.103:2380" 2. Start TiKV Start TiKV1 on the host4docker run -d --name tikv1 -p 20160:20160 -v /etc/localtime:/etc/localtime:ro -v /data:/data pingcap/tikv:latest --addr="0.0.0.0:20160" --advertise-addr="192.168.1.104:20160" --data-dir="/data/tikv1" --pd="192.168.1.101:2379,192.168.1.102:2379,192.168.1.103:2379" Start TiKV2 on the host5docker run -d --name tikv2 -p 20160:20160 -v /etc/localtime:/etc/localtime:ro -v /data:/data pingcap/tikv:latest --addr="0.0.0.0:20160" --advertise-addr="192.168.1.105:20160" --data-dir="/data/tikv2" --pd="192.168.1.101:2379,192.168.1.102:2379,192.168.1.103:2379" Start TiKV3 on the host6docker run -d --name tikv3 -p 20160:20160 -v /etc/localtime:/etc/localtime:ro -v /data:/data pingcap/tikv:latest --addr="0.0.0.0:20160" --advertise-addr="192.168.1.106:20160" --data-dir="/data/tikv3" --pd="192.168.1.101:2379,192.168.1.102:2379,192.168.1.103:2379" 3. Start TiDB Start TiDB on the host1docker run -d --name tidb -p 4000:4000 -p 10080:10080 -v /etc/localtime:/etc/localtime:ro pingcap/tidb:latest --store=tikv --path="192.168.1.101:2379,192.168.1.102:2379,192.168.1.103:2379" 4. Use the MySQL client to connect to TiDB Install the MySQL client on host1 and run:$ mysql -h 127.0.0.1 -P 4000 -u root -D test mysql> show databases; +--------------------+ | Database | +--------------------+ | INFORMATION_SCHEMA | | PERFORMANCE_SCHEMA | | mysql | | test | +--------------------+ 4 rows in set (0.00 sec) How to customize the configuration file The TiKV and PD can be started with a specified configuration file, which includes some advanced parameters, for the performance tuning.Assume that the path to configuration file of PD and TiKV on the host is /path/to/config/pd.toml and /path/to/config/tikv.tomlYou can start TiKV and PD as follows:docker run -d --name tikv1 -p 20160:20160 -v /etc/localtime:/etc/localtime:ro -v /data:/data -v /path/to/config/tikv.toml:/tikv.toml:ro pingcap/tikv:latest --addr="0.0.0.0:20160" --advertise-addr="192.168.1.104:20160" --data-dir="/data/tikv1" --pd="192.168.1.101:2379,192.168.1.102:2379,192.168.1.103:2379" --config="/tikv.toml"docker run -d --name pd1 -p 2379:2379 -p 2380:2380 -v /etc/localtime:/etc/localtime:ro -v /data:/data -v /path/to/config/pd.toml:/pd.toml:ro pingcap/pd:latest --name="pd1" --data-dir="/data/pd1" --client-urls="http://0.0.0.0:2379" --advertise-client-urls="http://192.168.1.101:2379" --peer-urls="http://0.0.0.0:2380" --advertise-peer-urls="http://192.168.1.101:2380" --initial-cluster="pd1=http://192.168.1.101:2380,pd2=http://192.168.1.102:2380,pd3=http://192.168.1.103:2380" --config="/pd.toml""}, {"url": "https://pingcap.com/docs/v2.0/op-guide/docker-deployment/", "title": "Deploy TiDB Using Docker", "content": " Deploy TiDB Using Docker This page shows you how to manually deploy a multi-node TiDB cluster on multiple machines using Docker.To learn more, see TiDB architecture and Software and Hardware Requirements.Preparation Before you start, make sure that you have: Installed the latest version of Docker Pulled the latest images of TiDB, TiKV and PD from Docker Hub. If not, pull the images using the following commands:docker pull pingcap/tidb:latest docker pull pingcap/tikv:latest docker pull pingcap/pd:latest Multi nodes deployment Assume we have 6 machines with the following details: Host Name IP Services Data Path host1 192.168.1.101 PD1 & TiDB /data host2 192.168.1.102 PD2 /data host3 192.168.1.103 PD3 /data host4 192.168.1.104 TiKV1 /data host5 192.168.1.105 TiKV2 /data host6 192.168.1.106 TiKV3 /data 1. Start PD Start PD1 on the host1docker run -d --name pd1 -p 2379:2379 -p 2380:2380 -v /etc/localtime:/etc/localtime:ro -v /data:/data pingcap/pd:latest --name="pd1" --data-dir="/data/pd1" --client-urls="http://0.0.0.0:2379" --advertise-client-urls="http://192.168.1.101:2379" --peer-urls="http://0.0.0.0:2380" --advertise-peer-urls="http://192.168.1.101:2380" --initial-cluster="pd1=http://192.168.1.101:2380,pd2=http://192.168.1.102:2380,pd3=http://192.168.1.103:2380" Start PD2 on the host2docker run -d --name pd2 -p 2379:2379 -p 2380:2380 -v /etc/localtime:/etc/localtime:ro -v /data:/data pingcap/pd:latest --name="pd2" --data-dir="/data/pd2" --client-urls="http://0.0.0.0:2379" --advertise-client-urls="http://192.168.1.102:2379" --peer-urls="http://0.0.0.0:2380" --advertise-peer-urls="http://192.168.1.102:2380" --initial-cluster="pd1=http://192.168.1.101:2380,pd2=http://192.168.1.102:2380,pd3=http://192.168.1.103:2380" Start PD3 on the host3docker run -d --name pd3 -p 2379:2379 -p 2380:2380 -v /etc/localtime:/etc/localtime:ro -v /data:/data pingcap/pd:latest --name="pd3" --data-dir="/data/pd3" --client-urls="http://0.0.0.0:2379" --advertise-client-urls="http://192.168.1.103:2379" --peer-urls="http://0.0.0.0:2380" --advertise-peer-urls="http://192.168.1.103:2380" --initial-cluster="pd1=http://192.168.1.101:2380,pd2=http://192.168.1.102:2380,pd3=http://192.168.1.103:2380" 2. Start TiKV Start TiKV1 on the host4docker run -d --name tikv1 -p 20160:20160 -v /etc/localtime:/etc/localtime:ro -v /data:/data pingcap/tikv:latest --addr="0.0.0.0:20160" --advertise-addr="192.168.1.104:20160" --data-dir="/data/tikv1" --pd="192.168.1.101:2379,192.168.1.102:2379,192.168.1.103:2379" Start TiKV2 on the host5docker run -d --name tikv2 -p 20160:20160 -v /etc/localtime:/etc/localtime:ro -v /data:/data pingcap/tikv:latest --addr="0.0.0.0:20160" --advertise-addr="192.168.1.105:20160" --data-dir="/data/tikv2" --pd="192.168.1.101:2379,192.168.1.102:2379,192.168.1.103:2379" Start TiKV3 on the host6docker run -d --name tikv3 -p 20160:20160 -v /etc/localtime:/etc/localtime:ro -v /data:/data pingcap/tikv:latest --addr="0.0.0.0:20160" --advertise-addr="192.168.1.106:20160" --data-dir="/data/tikv3" --pd="192.168.1.101:2379,192.168.1.102:2379,192.168.1.103:2379" 3. Start TiDB Start TiDB on the host1docker run -d --name tidb -p 4000:4000 -p 10080:10080 -v /etc/localtime:/etc/localtime:ro pingcap/tidb:latest --store=tikv --path="192.168.1.101:2379,192.168.1.102:2379,192.168.1.103:2379" 4. Use the MySQL client to connect to TiDB Install the MySQL client on host1 and run:$ mysql -h 127.0.0.1 -P 4000 -u root -D test mysql> show databases; +--------------------+ | Database | +--------------------+ | INFORMATION_SCHEMA | | PERFORMANCE_SCHEMA | | mysql | | test | +--------------------+ 4 rows in set (0.00 sec) How to customize the configuration file The TiKV and PD can be started with a specified configuration file, which includes some advanced parameters, for the performance tuning.Assume that the path to configuration file of PD and TiKV on the host is /path/to/config/pd.toml and /path/to/config/tikv.tomlYou can start TiKV and PD as follows:docker run -d --name tikv1 -p 20160:20160 -v /etc/localtime:/etc/localtime:ro -v /data:/data -v /path/to/config/tikv.toml:/tikv.toml:ro pingcap/tikv:latest --addr="0.0.0.0:20160" --advertise-addr="192.168.1.104:20160" --data-dir="/data/tikv1" --pd="192.168.1.101:2379,192.168.1.102:2379,192.168.1.103:2379" --config="/tikv.toml"docker run -d --name pd1 -p 2379:2379 -p 2380:2380 -v /etc/localtime:/etc/localtime:ro -v /data:/data -v /path/to/config/pd.toml:/pd.toml:ro pingcap/pd:latest --name="pd1" --data-dir="/data/pd1" --client-urls="http://0.0.0.0:2379" --advertise-client-urls="http://192.168.1.101:2379" --peer-urls="http://0.0.0.0:2380" --advertise-peer-urls="http://192.168.1.101:2380" --initial-cluster="pd1=http://192.168.1.101:2380,pd2=http://192.168.1.102:2380,pd3=http://192.168.1.103:2380" --config="/pd.toml""}, {"url": "https://pingcap.com/docs/v1.0/op-guide/binary-deployment/", "title": "Deploy TiDB Using the Binary", "content": " Deploy TiDB Using the Binary Overview A complete TiDB cluster contains PD, TiKV, and TiDB. To start the database service, follow the order of PD -> TiKV -> TiDB. To stop the database service, follow the order of stopping TiDB -> TiKV -> PD.Before you start, see TiDB architecture and Software and Hardware Requirements.This document describes the binary deployment of three scenarios: To quickly understand and try TiDB, see Single node cluster deployment. To try TiDB out and explore the features, see Multiple nodes cluster deployment for test. To deploy and use TiDB in production, see Multiple nodes cluster deployment. TiDB components and default ports TiDB database components (required) See the following table for the default ports for the TiDB components: Component Default Port Protocol Description ssh 22 TCP sshd service TiDB 4000 TCP the communication port for the application and DBA tools TiDB 10080 TCP the communication port to report TiDB status TiKV 20160 TCP the TiKV communication port PD 2379 TCP the communication port between TiDB and PD PD 2380 TCP the inter-node communication port within the PD cluster TiDB database components (optional) See the following table for the default ports for the optional TiDB components: Component Default Port Protocol Description Prometheus 9090 TCP the communication port for the Prometheus service Pushgateway 9091 TCP the aggregation and report port for TiDB, TiKV, and PD monitor Node_exporter 9100 TCP the communication port to report the system information of every TiDB cluster node Grafana 3000 TCP the port for the external Web monitoring service and client (Browser) access alertmanager 9093 TCP the port for the alert service Configure and check the system before installation Operating system Configuration Description Supported Platform See the Software and Hardware Requirements File System The ext4 file system is recommended in TiDB Deployment Swap Space The Swap Space is recommended to close in TiDB Deployment Disk Block Size Set the size of the system disk Block to 4096 Network and firewall Configuration Description Firewall / Port Check whether the ports required by TiDB are accessible between the nodes Operating system parameters Configuration Description Nice Limits For system users, set the default value of nice in TiDB to 0 min_free_kbytes The setting for vm.min_free_kbytes in sysctl.conf needs to be high enough User Open Files Limit For database administrators, set the number of TiDB open files to 1000000 System Open File Limits Set the number of system open files to 1000000 User Process Limits For TiDB users, set the nproc value to 4096 in limits.conf Address Space Limits For TiDB users, set the space to unlimited in limits.conf File Size Limits For TiDB users, set the fsize value to unlimited in limits.conf Disk Readahead Set the value of the readahead data disk to 4096 at a minimum NTP service Configure the NTP time synchronization service for each node SELinux Turn off the SELinux service for each node CPU Frequency Scaling It is recommended to turn on CPU overclocking Transparent Hugepages For Red Hat 7+ and CentOS 7+ systems, it is required to set the Transparent Hugepages to always I/O Scheduler Set the I/O Scheduler of data disks to the deadline mode vm.swappiness Set vm.swappiness = 0 Note: To adjust the operating system parameters, contact your system administrator. Database running user Configuration Description LANG environment Set LANG = en_US.UTF8 TZ time zone Set the TZ time zone of all nodes to the same value Create the database running user account In the Linux environment, create TiDB on each installation node as a database running user, and set up the SSH mutual trust between cluster nodes. To create a running user and open SSH mutual trust, contact the system administrator. Here is an example:# useradd tidb # usermod -a -G tidb tidb # su - tidb Last login: Tue Aug 22 12:06:23 CST 2017 on pts/2 -bash-4.2$ ssh-keygen -t rsa Generating public/private rsa key pair. Enter file in which to save the key (/home/tidb/.ssh/id_rsa): Created directory '/home/tidb/.ssh'. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/tidb/.ssh/id_rsa. Your public key has been saved in /home/tidb/.ssh/id_rsa.pub. The key fingerprint is: 5a:00:e6:df:9e:40:25:2c:2d:e2:6e:ee:74:c6:c3:c1 tidb@t001 The key's randomart image is: +--[ RSA 2048]----+ | oo. . | | .oo.oo | | . ..oo | | .. o o | | . E o S | | oo . = . | | o. * . o | | ..o . | | .. | +-----------------+ -bash-4.2$ cd .ssh -bash-4.2$ cat id_rsa.pub >> authorized_keys -bash-4.2$ chmod 644 authorized_keys -bash-4.2$ ssh-copy-id -i ~/.ssh/id_rsa.pub 192.168.1.100 Download the official binary package TiDB provides the official binary installation package that supports Linux. For the operating system, it is recommended to use Redhat 7.3+, CentOS 7.3+ and higher versions.Operating system: Linux (Redhat 7+, CentOS 7+) # Download the package. wget http://download.pingcap.org/tidb-latest-linux-amd64.tar.gz wget http://download.pingcap.org/tidb-latest-linux-amd64.sha256 # Check the file integrity. If the result is OK, the file is correct. sha256sum -c tidb-latest-linux-amd64.sha256 # Extract the package. tar -xzf tidb-latest-linux-amd64.tar.gz cd tidb-latest-linux-amd64 Single node cluster deployment After downloading the TiDB binary package, you can run and test the TiDB cluster on a standalone server. Follow the steps below to start PD, TiKV and TiDB: Start PD../bin/pd-server --data-dir=pd --log-file=pd.log Start TiKV../bin/tikv-server --pd="127.0.0.1:2379" --data-dir=tikv --log-file=tikv.log Start TiDB../bin/tidb-server --store=tikv --path="127.0.0.1:2379" --log-file=tidb.log Use the official MySQL client to connect to TiDB.mysql -h 127.0.0.1 -P 4000 -u root -D test Multiple nodes cluster deployment for test If you want to test TiDB but have a limited number of nodes, you can use one PD instance to test the entire cluster.Assuming that you have four nodes, you can deploy 1 PD instance, 3 TiKV instances, and 1 TiDB instance. See the following table for details: Name Host IP Services Node1 192.168.199.113 PD1, TiDB Node2 192.168.199.114 TiKV1 Node3 192.168.199.115 TiKV2 Node4 192.168.199.116 TiKV3 Follow the steps below to start PD, TiKV and TiDB: Start PD on Node1../bin/pd-server --name=pd1 --data-dir=pd1 --client-urls="http://192.168.199.113:2379" --peer-urls="http://192.168.199.113:2380" --initial-cluster="pd1=http://192.168.199.113:2380" --log-file=pd.log Start TiKV on Node2, Node3 and Node4../bin/tikv-server --pd="192.168.199.113:2379" --addr="192.168.199.114:20160" --data-dir=tikv1 --log-file=tikv.log ./bin/tikv-server --pd="192.168.199.113:2379" --addr="192.168.199.115:20160" --data-dir=tikv2 --log-file=tikv.log ./bin/tikv-server --pd="192.168.199.113:2379" --addr="192.168.199.116:20160" --data-dir=tikv3 --log-file=tikv.log Start TiDB on Node1../bin/tidb-server --store=tikv --path="192.168.199.113:2379" --log-file=tidb.log Use the official MySQL client to connect to TiDB.mysql -h 192.168.199.113 -P 4000 -u root -D test Multiple nodes cluster deployment For the production environment, multiple nodes cluster deployment is recommended. Before you begin, see Software and Hardware Requirements.Assuming that you have six nodes, you can deploy 3 PD instances, 3 TiKV instances, and 1 TiDB instance. See the following table for details: Name Host IP Services Node1 192.168.199.113 PD1, TiDB Node2 192.168.199.114 PD2 Node3 192.168.199.115 PD3 Node4 192.168.199.116 TiKV1 Node5 192.168.199.117 TiKV2 Node6 192.168.199.118 TiKV3 Follow the steps below to start PD, TiKV, and TiDB: Start PD on …"}, {"url": "https://pingcap.com/docs/", "title": "Docs", "content": ""}, {"url": "https://pingcap.com/docs-cn/", "title": "Docs-cns", "content": ""}, {"url": "https://pingcap.com/tidb-academy/mysql_dbas/query-optimization/explain/", "title": "EXPLAIN", "content": " EXPLAIN Resources Using EXPLAIN manual page Transcript Welcome back. In the previous video, I compared query optimization to GPS navigation and an address to being the same as an SQL query. To extend that analogy just a little bit further: a GPS navigation system may have multiple routes to navigate you to the same address. In query optimization parlance, we would say that there are multiple possible execution plans for a query. The database system chooses what it determines to be the most efficient, or lowest cost plan. And we can see what that is with the EXPLAIN command.TiDB and MySQL both have query optimizers, so coming from a MySQL background this may not be new. But both the format of EXPLAIN, and the types of optimizations (or routes possible) in TiDB do differ from MySQL. TiDB is also a distributed system, so in determining the lowest cost plan it needs to estimate the CPU cost, memory cost and network transfer cost.So let’s look at the current best plan for this query. To do that, we just add the word EXPLAIN, so EXPLAIN SELECT count(*) FROM trips WHERE start_date BETWEEN '2017-07-01 00:00:00' AND '2017-07-01 23:59:59'.MySQL [bikeshare]> EXPLAIN SELECT count(*) FROM trips WHERE start_date BETWEEN '2017-07-01 00:00:00' AND '2017-07-01 23:59:59'; +--------------------------+------------+------+------------------------------------------------------------------------------------------------------------------------+ | id | count | task | operator info | +--------------------------+------------+------+------------------------------------------------------------------------------------------------------------------------+ | StreamAgg_20 | 1.00 | root | funcs:count(col_0) | | └─TableReader_21 | 1.00 | root | data:StreamAgg_9 | | └─StreamAgg_9 | 1.00 | cop | funcs:count(1) | | └─Selection_19 | 40444.43 | cop | ge(bikeshare.trips.start_date, 2017-07-01 00:00:00.000000), le(bikeshare.trips.start_date, 2017-07-01 23:59:59.000000) | | └─TableScan_18 | 1617777.00 | cop | table:trips, range:[-inf,+inf], keep order:false | +--------------------------+------------+------+------------------------------------------------------------------------------------------------------------------------+ 5 rows in set (0.00 sec) Here we can see that the coprocessor (cop) needs to scan the table trips to find rows that match the criteria of start_date. Coprocessor is just a way of saying “tasks that happen in TiKV, not TiDB”. We will cover what that means soon, but for performance the TiDB Platform pushes parts of query execution into TiKV. This helps reduce the amount of data that needs to be copied around.Rows that meet this criteria are determined in Selection_19 and passed to StreamAgg_9, all still within the coprocessor (i.e. all still inside of TiKV). The count column shows an approximate number of rows that will be processed, which is estimated with the help of table statistics. In this query, it is estimated that each of the TiKV nodes will return 1.00 row to TiDB (as TableReader_21), which are then aggregated as StreamAgg_20 to return an estimated 1.00 row to the client.The good news with this query is that most of the work is pushed down to the coprocessor. This means that minimal data transfer way required for query execution. However, what reading EXPLAIN has told me is that there is no index to speed up filtering the predicate start_date. We can see in TableScan_18 that all the rows in the table are being scanned. Ouch!So let’s fix that with an index, which takes about 7 minutes. So I’ll fast forward:MySQL [bikeshare]> ALTER TABLE trips ADD INDEX (start_date); Query OK, 0 rows affected (6 min 51.40 sec) MySQL [bikeshare]> EXPLAIN SELECT count(*) FROM trips WHERE start_date BETWEEN '2017-07-01 00:00:00' AND '2017-07-01 23:59:59'; +------------------------+----------+------+--------------------------------------------------------------------------------------------------+ | id | count | task | operator info | +------------------------+----------+------+--------------------------------------------------------------------------------------------------+ | StreamAgg_25 | 1.00 | root | funcs:count(col_0) | | └─IndexReader_26 | 1.00 | root | index:StreamAgg_9 | | └─StreamAgg_9 | 1.00 | cop | funcs:count(1) | | └─IndexScan_24 | 40444.43 | cop | table:trips, index:start_date, range:[2017-07-01 00:00:00,2017-07-01 23:59:59], keep order:false | +------------------------+----------+------+--------------------------------------------------------------------------------------------------+ 4 rows in set (0.71 sec) In the revisited EXPLAIN, we can see the count of rows scanned has reduced via the use of an index. On my Kubernetes cluster, this reduced query execution time reduced from 3.38 seconds to 0.02 seconds!So a quick rundown of what’s in EXPLAIN: It shows the plan that the query optimization determined to be the cheapest. Each of the rows is a set of steps that need to be completed, represented in a tree. Each of the counts are estimates; they are built by keeping statistics on the data distribution such as histograms. Running EXPLAIN doesn’t run the actual query. Like with GPS, it’s possible that statistics are incorrect and there might be cases where they need updating. Since you can’t sight check a query (it’s declarative), your job in running EXPLAIN is to make sure that indexes are being used to match various predicates (in this case an index on start_date makes sense!) Try and think WHERE work can be eliminated or filtered out - this is the first place to start. It’s time to try optimizing a few queries for yourself in our next exercise."}, {"url": "https://pingcap.com/docs/op-guide/security/", "title": "Enable TLS Authentication", "content": " Enable TLS Authentication Overview This document describes how to enable TLS authentication in the TiDB cluster. The TLS authentication includes the following two conditions: The mutual authentication between TiDB components, including the authentication among TiDB, TiKV and PD, between TiKV Control and TiKV, between PD Control and PD, between TiKV peers, and between PD peers. Once enabled, the mutual authentication applies to all components, and it does not support applying to only part of the components. The one-way and mutual authentication between the TiDB server and the MySQL Client. Note: The authentication between the MySQL Client and the TiDB server uses one set of certificates, while the authentication among TiDB components uses another set of certificates. Enable mutual TLS authentication among TiDB components Prepare certificates It is recommended to prepare a separate server certificate for TiDB, TiKV and PD, and make sure that they can authenticate each other. The clients of TiDB, TiKV and PD share one client certificate.You can use multiple tools to generate self-signed certificates, such as openssl, easy-rsa and cfssl.See an example of generating self-signed certificates using cfssl.Configure certificates To enable mutual authentication among TiDB components, configure the certificates of TiDB, TiKV and PD as follows.TiDB Configure in the configuration file or command line arguments:[security] # Path of file that contains list of trusted SSL CAs for connection with cluster components. cluster-ssl-ca = "/path/to/ca.pem" # Path of file that contains X509 certificate in PEM format for connection with cluster components. cluster-ssl-cert = "/path/to/tidb-server.pem" # Path of file that contains X509 key in PEM format for connection with cluster components. cluster-ssl-key = "/path/to/tidb-server-key.pem" TiKV Configure in the configuration file or command line arguments, and set the corresponding URL to https:[security] # set the path for certificates. Empty string means disabling secure connections. ca-path = "/path/to/ca.pem" cert-path = "/path/to/client.pem" key-path = "/path/to/client-key.pem" PD Configure in the configuration file or command line arguments, and set the corresponding URL to https:[security] # Path of file that contains list of trusted SSL CAs. If set, following four settings shouldn't be empty cacert-path = "/path/to/ca.pem" # Path of file that contains X509 certificate in PEM format. cert-path = "/path/to/server.pem" # Path of file that contains X509 key in PEM format. key-path = "/path/to/server-key.pem" Now mutual authentication among TiDB components is enabled.When you connect the server using the client, it is required to specify the client certificate. For example:./pd-ctl -u https://127.0.0.1:2379 --cacert /path/to/ca.pem --cert /path/to/pd-client.pem --key /path/to/pd-client-key.pem ./tikv-ctl --host="127.0.0.1:20160" --ca-path="/path/to/ca.pem" --cert-path="/path/to/client.pem" --key-path="/path/to/clinet-key.pem" Enable TLS authentication between the MySQL client and TiDB server Prepare certificates mysql_ssl_rsa_setup --datadir=certs Configure one-way authentication Configure in the configuration file or command line arguments of TiDB:[security] # Path of file that contains list of trusted SSL CAs. ssl-ca = "" # Path of file that contains X509 certificate in PEM format. ssl-cert = "/path/to/certs/server.pem" # Path of file that contains X509 key in PEM format. ssl-key = "/path/to/certs/server-key.pem" Configure in the MySQL client:mysql -u root --host 127.0.0.1 --port 4000 --ssl-mode=REQUIRED Configure mutual authentication Configure in the configuration file or command line arguments of TiDB:[security] # Path of file that contains list of trusted SSL CAs for connection with mysql client. ssl-ca = "/path/to/certs/ca.pem" # Path of file that contains X509 certificate in PEM format for connection with mysql client. ssl-cert = "/path/to/certs/server.pem" # Path of file that contains X509 key in PEM format for connection with mysql client. ssl-key = "/path/to/certs/server-key.pem" Specify the client certificate in the client:mysql -u root --host 127.0.0.1 --port 4000 --ssl-cert=/path/to/certs/client-cert.pem --ssl-key=/path/to/certs/client-key.pem --ssl-ca=/path/to/certs/ca.pem --ssl-mode=VERIFY_IDENTITY"}, {"url": "https://pingcap.com/docs/v1.0/op-guide/security/", "title": "Enable TLS Authentication", "content": " Enable TLS Authentication Overview This document describes how to enable TLS authentication in the TiDB cluster. The TLS authentication includes the following two conditions: The mutual authentication between TiDB components, including the authentication among TiDB, TiKV and PD, between TiKV Control and TiKV, between PD Control and PD, between TiKV peers, and between PD peers. Once enabled, the mutual authentication applies to all components, and it does not support applying to only part of the components. The one-way and mutual authentication between the TiDB server and the MySQL Client. Note: The authentication between the MySQL Client and the TiDB server uses one set of certificates, while the authentication among TiDB components uses another set of certificates. Enable mutual TLS authentication among TiDB components Prepare certificates It is recommended to prepare a separate server certificate for TiDB, TiKV and PD, and make sure that they can authenticate each other. The clients of TiDB, TiKV and PD share one client certificate.You can use multiple tools to generate self-signed certificates, such as openssl, easy-rsa and cfssl.See an example of generating self-signed certificates using cfssl.Configure certificates To enable mutual authentication among TiDB components, configure the certificates of TiDB, TiKV and PD as follows.TiDB Configure in the configuration file or command line arguments:[security] # Path of file that contains list of trusted SSL CAs for connection with cluster components. cluster-ssl-ca = "/path/to/ca.pem" # Path of file that contains X509 certificate in PEM format for connection with cluster components. cluster-ssl-cert = "/path/to/tidb-server.pem" # Path of file that contains X509 key in PEM format for connection with cluster components. cluster-ssl-key = "/path/to/tidb-server-key.pem" TiKV Configure in the configuration file or command line arguments, and set the corresponding URL to https:[security] # set the path for certificates. Empty string means disabling secure connections. ca-path = "/path/to/ca.pem" cert-path = "/path/to/client.pem" key-path = "/path/to/client-key.pem" PD Configure in the configuration file or command line arguments, and set the corresponding URL to https:[security] # Path of file that contains list of trusted SSL CAs. If set, following four settings shouldn't be empty cacert-path = "/path/to/ca.pem" # Path of file that contains X509 certificate in PEM format. cert-path = "/path/to/server.pem" # Path of file that contains X509 key in PEM format. key-path = "/path/to/server-key.pem" Now mutual authentication among TiDB components is enabled.When you connect the server using the client, it is required to specify the client certificate. For example:./pd-ctl -u https://127.0.0.1:2379 --cacert /path/to/ca.pem --cert /path/to/pd-client.pem --key /path/to/pd-client-key.pem ./tikv-ctl --host="127.0.0.1:20160" --ca-path="/path/to/ca.pem" --cert-path="/path/to/client.pem" --key-path="/path/to/clinet-key.pem" Enable TLS authentication between the MySQL client and TiDB server Prepare certificates mysql_ssl_rsa_setup --datadir=certs Configure one-way authentication Configure in the configuration file or command line arguments of TiDB:[security] # Path of file that contains list of trusted SSL CAs. ssl-ca = "" # Path of file that contains X509 certificate in PEM format. ssl-cert = "/path/to/certs/server.pem" # Path of file that contains X509 key in PEM format. ssl-key = "/path/to/certs/server-key.pem" Configure in the MySQL client:mysql -u root --host 127.0.0.1 --port 4000 --ssl-mode=REQUIRED Configure mutual authentication Configure in the configuration file or command line arguments of TiDB:[security] # Path of file that contains list of trusted SSL CAs for connection with mysql client. ssl-ca = "/path/to/certs/ca.pem" # Path of file that contains X509 certificate in PEM format for connection with mysql client. ssl-cert = "/path/to/certs/server.pem" # Path of file that contains X509 key in PEM format for connection with mysql client. ssl-key = "/path/to/certs/server-key.pem" Specify the client certificate in the client:mysql -u root --host 127.0.0.1 --port 4000 --ssl-cert=/path/to/certs/client-cert.pem --ssl-key=/path/to/certs/client-key.pem --ssl-ca=/path/to/certs/ca.pem --ssl-mode=VERIFY_IDENTITY"}, {"url": "https://pingcap.com/docs/v2.0/op-guide/security/", "title": "Enable TLS Authentication", "content": " Enable TLS Authentication Overview This document describes how to enable TLS authentication in the TiDB cluster. The TLS authentication includes the following two conditions: The mutual authentication between TiDB components, including the authentication among TiDB, TiKV and PD, between TiKV Control and TiKV, between PD Control and PD, between TiKV peers, and between PD peers. Once enabled, the mutual authentication applies to all components, and it does not support applying to only part of the components. The one-way and mutual authentication between the TiDB server and the MySQL Client. Note: The authentication between the MySQL Client and the TiDB server uses one set of certificates, while the authentication among TiDB components uses another set of certificates. Enable mutual TLS authentication among TiDB components Prepare certificates It is recommended to prepare a separate server certificate for TiDB, TiKV and PD, and make sure that they can authenticate each other. The clients of TiDB, TiKV and PD share one client certificate.You can use multiple tools to generate self-signed certificates, such as openssl, easy-rsa and cfssl.See an example of generating self-signed certificates using cfssl.Configure certificates To enable mutual authentication among TiDB components, configure the certificates of TiDB, TiKV and PD as follows.TiDB Configure in the configuration file or command line arguments:[security] # Path of file that contains list of trusted SSL CAs for connection with cluster components. cluster-ssl-ca = "/path/to/ca.pem" # Path of file that contains X509 certificate in PEM format for connection with cluster components. cluster-ssl-cert = "/path/to/tidb-server.pem" # Path of file that contains X509 key in PEM format for connection with cluster components. cluster-ssl-key = "/path/to/tidb-server-key.pem" TiKV Configure in the configuration file or command line arguments, and set the corresponding URL to https:[security] # set the path for certificates. Empty string means disabling secure connections. ca-path = "/path/to/ca.pem" cert-path = "/path/to/client.pem" key-path = "/path/to/client-key.pem" PD Configure in the configuration file or command line arguments, and set the corresponding URL to https:[security] # Path of file that contains list of trusted SSL CAs. If set, following four settings shouldn't be empty cacert-path = "/path/to/ca.pem" # Path of file that contains X509 certificate in PEM format. cert-path = "/path/to/server.pem" # Path of file that contains X509 key in PEM format. key-path = "/path/to/server-key.pem" Now mutual authentication among TiDB components is enabled.When you connect the server using the client, it is required to specify the client certificate. For example:./pd-ctl -u https://127.0.0.1:2379 --cacert /path/to/ca.pem --cert /path/to/pd-client.pem --key /path/to/pd-client-key.pem ./tikv-ctl --host="127.0.0.1:20160" --ca-path="/path/to/ca.pem" --cert-path="/path/to/client.pem" --key-path="/path/to/clinet-key.pem" Enable TLS authentication between the MySQL client and TiDB server Prepare certificates mysql_ssl_rsa_setup --datadir=certs Configure one-way authentication Configure in the configuration file or command line arguments of TiDB:[security] # Path of file that contains list of trusted SSL CAs. ssl-ca = "" # Path of file that contains X509 certificate in PEM format. ssl-cert = "/path/to/certs/server.pem" # Path of file that contains X509 key in PEM format. ssl-key = "/path/to/certs/server-key.pem" Configure in the MySQL client:mysql -u root --host 127.0.0.1 --port 4000 --ssl-mode=REQUIRED Configure mutual authentication Configure in the configuration file or command line arguments of TiDB:[security] # Path of file that contains list of trusted SSL CAs for connection with mysql client. ssl-ca = "/path/to/certs/ca.pem" # Path of file that contains X509 certificate in PEM format for connection with mysql client. ssl-cert = "/path/to/certs/server.pem" # Path of file that contains X509 key in PEM format for connection with mysql client. ssl-key = "/path/to/certs/server-key.pem" Specify the client certificate in the client:mysql -u root --host 127.0.0.1 --port 4000 --ssl-cert=/path/to/certs/client-cert.pem --ssl-key=/path/to/certs/client-key.pem --ssl-ca=/path/to/certs/ca.pem --ssl-mode=VERIFY_IDENTITY"}, {"url": "https://pingcap.com/docs/sql/encryption-and-compression-functions/", "title": "Encryption and Compression Functions", "content": " Encryption and Compression Functions Name Description MD5() Calculate MD5 checksum PASSWORD() Calculate and return a password string RANDOM_BYTES() Return a random byte vector SHA1(), SHA() Calculate an SHA-1 160-bit checksum SHA2() Calculate an SHA-2 checksum AES_DECRYPT() Decrypt using AES AES_ENCRYPT() Encrypt using AES COMPRESS() Return result as a binary string UNCOMPRESS() Uncompress a string compressed UNCOMPRESSED_LENGTH() Return the length of a string before compression CREATE_ASYMMETRIC_PRIV_KEY() Create private key CREATE_ASYMMETRIC_PUB_KEY() Create public key CREATE_DH_PARAMETERS() Generate shared DH secret CREATE_DIGEST() Generate digest from string ASYMMETRIC_DECRYPT() Decrypt ciphertext using private or public key ASYMMETRIC_DERIVE() Derive symmetric key from asymmetric keys ASYMMETRIC_ENCRYPT() Encrypt cleartext using private or public key ASYMMETRIC_SIGN() Generate signature from digest ASYMMETRIC_VERIFY() Verify that signature matches digest "}, {"url": "https://pingcap.com/docs/v1.0/sql/encryption-and-compression-functions/", "title": "Encryption and Compression Functions", "content": " Encryption and Compression Functions Name Description MD5() Calculate MD5 checksum PASSWORD() (deprecated 5.7.6) Calculate and return a password string RANDOM_BYTES() Return a random byte vector SHA1(), SHA() Calculate an SHA-1 160-bit checksum SHA2() Calculate an SHA-2 checksum AES_DECRYPT() Decrypt using AES AES_ENCRYPT() Encrypt using AES COMPRESS() Return result as a binary string UNCOMPRESS() Uncompress a string compressed UNCOMPRESSED_LENGTH() Return the length of a string before compression CREATE_ASYMMETRIC_PRIV_KEY() Create private key CREATE_ASYMMETRIC_PUB_KEY() Create public key CREATE_DH_PARAMETERS() Generate shared DH secret CREATE_DIGEST() Generate digest from string ASYMMETRIC_DECRYPT() Decrypt ciphertext using private or public key ASYMMETRIC_DERIVE() Derive symmetric key from asymmetric keys ASYMMETRIC_ENCRYPT() Encrypt cleartext using private or public key ASYMMETRIC_SIGN() Generate signature from digest ASYMMETRIC_VERIFY() Verify that signature matches digest "}, {"url": "https://pingcap.com/docs/v2.0/sql/encryption-and-compression-functions/", "title": "Encryption and Compression Functions", "content": " Encryption and Compression Functions Name Description MD5() Calculate MD5 checksum PASSWORD() (deprecated 5.7.6) Calculate and return a password string RANDOM_BYTES() Return a random byte vector SHA1(), SHA() Calculate an SHA-1 160-bit checksum SHA2() Calculate an SHA-2 checksum AES_DECRYPT() Decrypt using AES AES_ENCRYPT() Encrypt using AES COMPRESS() Return result as a binary string UNCOMPRESS() Uncompress a string compressed UNCOMPRESSED_LENGTH() Return the length of a string before compression CREATE_ASYMMETRIC_PRIV_KEY() Create private key CREATE_ASYMMETRIC_PUB_KEY() Create public key CREATE_DH_PARAMETERS() Generate shared DH secret CREATE_DIGEST() Generate digest from string ASYMMETRIC_DECRYPT() Decrypt ciphertext using private or public key ASYMMETRIC_DERIVE() Derive symmetric key from asymmetric keys ASYMMETRIC_ENCRYPT() Encrypt cleartext using private or public key ASYMMETRIC_SIGN() Generate signature from digest ASYMMETRIC_VERIFY() Verify that signature matches digest "}, {"url": "https://pingcap.com/agreements/eula-gcp-marketplace/", "title": "End User Agreement for GCP", "content": " PingCAP Click-Through End User License Agreement Last Updated: October 22, 2018PLEASE READ THIS PINGCAP END USER LICENSE AGREEMENT (“AGREEMENT”) CAREFULLY BEFORE USING THE TiDB OPERATOR ENTERPRISE SOFTWARE PRODUCT (TOGETHER WITH ANY, UPGRADES OR NEW VERSIONS THEREOF, THE “LICENSED SOFTWARE”) AND ANY OTHER SERVICES OFFERED BY PINGCAP (US) INC. (“PINGCAP”).By accessing, installing, copying, or otherwise using the Licensed Software and/or by purchasing any services from PingCAP, you or the entity you represent (“You”, “Your” or “Licensee”) agree to be bound by the terms of this Agreement, the PingCAP privacy policy, the PingCAP Terms of Service, and the Google Cloud Platform Marketplace Agreement. You represent and warrant that You have the authority to enter into this Agreement, or if Licensee is an entity, to enter into this Agreement on behalf of Licensee and to bind Licensee to the terms of this Agreement. If You do not have the legal authority to enter into this Agreement, do not understand this Agreement, or do not agree to any of its terms, please do not click to accept, and do not install or use the Licensed Software. Grant of License. Subject to the terms hereof, payment of the Fees and any applicable user/use limitations, PingCAP grants Licensee a personal, non-exclusive, non-transferable, non-sublicensable, revocable, limited license to access and use the Licensed Software in object code form solely for Your internal business purposes and in accordance with PingCAP’s user documentation. Restrictions. Licensee will not and will not allow any third party to: (i) remove or modify any notice of copyright or other proprietary rights that appear on or in the Licensed Software; (ii) reverse engineer or attempt to discover by any means the source code, underlying ideas or algorithms of all or any portion of the Licensed Software; (iii) provide, distribute, lease, lend, disclose, use for timesharing or service bureau purposes, or otherwise use or allow others to use for the benefit of any third party the Licensed Software; (iv) possess or use the Licensed Software, or allow the transfer, transmission, export, or re-export of the Licensed Software or portion thereof in violation of any export control laws or regulations administered by the U.S. Commerce Department, U.S. Treasury Department’s Office of Foreign Assets Control, or any other government agency; (v) disclose to any third party any benchmarking or comparative study involving the Licensed Software; or (vi) modify or create derivative works based on all or a portion of the Licensed Software. Ownership. PingCAP retains all title, ownership and interest in and to the Licensed Software, Proprietary Information and all intellectual property rights therein. To the extent the Licensed Software contains any materials licensed from third parties, third party suppliers may own such licensed materials. PingCAP retains all rights not expressly granted to Licensee in this Agreement. Licensee agrees: (i) to protect and maintain the confidentiality of the Licensed Software any other proprietary or confidential information (collectively, “Proprietary Information”) that may be provided to Licensee by or on behalf of PingCAP and (ii) not to disclose or provide access to the Licensed Software and/or Proprietary Information to any third parties except as expressly permitted in this Agreement. Support. PingCAP may, but is not required to provide technical support for the Licensed Software. If PingCAP elects to provide technical support to Licensee, it may charge Licensee fees for such technical support and will use commercially reasonable efforts to respond to Licensee’s questions or inquiries according to the terms specified in the “Maintenance and Support” section of the product listing for the Licensed Software on Google Cloud Platform Marketplace. Fees and Payment. Licensee will pay any fee specified in the product listing for the Licensed Software on Google Cloud Platform Marketplace (the “Fees”). Google will invoice Licensee on the basis specified in the Google Cloud Platform Marketplace Agreement. Licensee agrees to comply entirely with Licensee’s payment obligations in the Google Cloud Platform Marketplace Agreement. Additional Services. PingCAP may agree to perform certain additional services for Licensee (“Additional Services”). Such Additional Services are outside the scope of this Agreement and will be governed by a separate written agreement to be negotiated between PingCAP and Licensee. Termination; Breach. The license granted under this Agreement will terminate: (i) thirty (30) days after PingCAP notifies Licensee of any breach of this Agreement if such breach is not cured at the end of the thirty (30) day period; (ii) immediately, if the other party ceases its business operations or becomes subject to insolvency proceedings and the proceedings are not dismissed within ninety (90) days; (iii) immediately, if for any reason PingCAP ceases to be featured in the Google Cloud Marketplace; or (iv) effective upon notice to Licensee, at any time for any reason or no reason at all, without liability to Licensee. Upon termination of this Agreement, Licensee shall immediately cease all use of the Licensed Software and return or destroy any Proprietary Information in its possession or control. Indemnification.(a) PingCAP Indemnity. PingCAP will defend, indemnify and hold Licensee harmless from any third party claims alleging that the use of the Licensed Software infringes a valid United States patent or copyright or misappropriates any trade secret right; provided that Licensee promptly notifies PingCAP of such claim or allegation in writing, gives PingCAP sole control of the defense and settlement of such claim or allegation and provides PingCAP reasonable cooperation and assistance thereof.(b) Exclusions. The foregoing obligations in Section 8(a) shall not apply to with respect to the Licensed Software or portions thereof to the extent: (i) not created by PingCAP; (ii) modified by any party other than PingCAP; (ii) combined or bundled with any products, processes or materials not provided by PingCAP; (iii) continued use of the Licensed Software after notification of an alleged infringement or the provision of a non-infringing modification or alternative.(c) Licensee Indemnity. Licensee will defend, indemnify and hold PingCAP and its affiliates and its and their officers, agents and employees harmless against any losses, liabilities, expenses (including reasonable attorneys’ fees), damages, claims, demands, proceedings and causes of actions arising from any breach by Licensee of the terms of this Agreement or unauthorized use of the Licensed Software by Licensee. Feedback. Licensee agrees that PingCAP may freely exploit and make available any and all feedback, suggestions, ideas, enhancement requests, recommendations or other information provided by Licensee or any other party relating to the Licensed Software. No Warranty. PINGCAP OFFERS NO WARRANTY WHATSOEVER UNDER THIS AGREEMENT. YOU ACKNOWLEDGE THAT THE LICENSED SOFTWARE IS PROVIDED “AS IS” AND “AS AVAILABLE” WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER. TO THE MAXIMUM EXTENT PERMITTED UNDER APPLICABLE LAW, PINGCAP, ON ITS OWN BEHALF AND ON BEHALF OF ITS AFFILIATES AND ITS AND THEIR RESPECTIVE LICENSORS AND SERVICE PROVIDERS, EXPRESSLY DISCLAIMS ALL WARRANTIES, WHETHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO THE LICENSED SOFTWARE AND DOCUMENTATION, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND NON-INFRINGEMENT, AND WARRANTIES THAT MAY ARISE OUT OF COURSE OF DEALING, COURSE OF PERFORMANCE, USAGE, OR TRADE PRACTICE. WITHOUT LIMITATION TO THE FOREGOING, PINGCAP PROVIDES NO WARRANTY OR UNDERTAKING, AND MAKES NO REPRESENTATION OF ANY KIND THAT THE LICENSED SOFTWARE WILL MEET THE LICENSEE’S REQUIREMENTS, ACHIEVE ANY INTENDED RESULTS, BE COMPATIBLE, OR WORK WITH ANY OTHER SOFTWARE, …"}, {"url": "https://pingcap.com/docs/sql/error/", "title": "Error Codes and Troubleshooting", "content": " Error Codes and Troubleshooting This document describes the problems encountered during the use of TiDB and provides the solutions.Error codes TiDB is compatible with the error codes in MySQL, and in most cases returns the same error code as MySQL. In addition, TiDB has the following unique error codes: Error code Description Solution 8001 The memory used by the request exceeds the threshold limit for the TiDB memory usage. Increase the value of the system variable with the tidb_mem_quota prefix. 8002 To guarantee consistency, a transaction with the SELECT FOR UPDATE statement cannot be retried when it encounters a commit conflict. TiDB rolls back the transaction and returns this error. Retry the failed transaction. 8003 If the data in a row is not consistent with the index when executing the ADMIN CHECK TABLE command, TiDB returns this error. 9001 The PD request timed out. Check the state/monitor/log of the PD server and the network between the TiDB server and the PD server. 9002 The TiKV request timed out. Check the state/monitor/log of the TiKV server and the network between the TiDB server and the TiKV server. 9003 The TiKV server is busy and this usually occurs when the workload is too high. Check the state/monitor/log of the TiKV server. 9004 This error occurs when a large number of transactional conflicts exist in the database. Check the code of application. 9005 A certain Raft Group is not available, such as the number of replicas is not enough. This error usually occurs when the TiKV server is busy or the TiKV node is down. Check the state/monitor/log of the TiKV server. 9006 The interval of GC Life Time is too short and the data that should be read by the long transactions might be cleared. Extend the interval of GC Life Time. 9500 A single transaction is too large. See here for the solution. Troubleshooting See the troubleshooting and FAQ documents."}, {"url": "https://pingcap.com/docs/v1.0/sql/error/", "title": "Error Codes and Troubleshooting", "content": " Error Codes and Troubleshooting This document describes the problems encountered during the use of TiDB and provides the solutions.Error codes TiDB is compatible with the error codes in MySQL, and in most cases returns the same error code as MySQL. In addition, TiDB has the following unique error codes: Error code Description Solution 9001 The PD request timed out. Check the state/monitor/log of the PD server and the network between the TiDB server and the PD server. 9002 The TiKV request timed out. Check the state/monitor/log of the TiKV server and the network between the TiDB server and the TiKV server. 9003 The TiKV server is busy and this usually occurs when the workload is too high. Check the state/monitor/log of the TiKV server. 9004 This error occurs when a large number of transactional conflicts exist in the database. Check the code of application. 9005 A certain Raft Group is not available, such as the number of replicas is not enough. This error usually occurs when the TiKV server is busy or the TiKV node is down. Check the state/monitor/log of the TiKV server. 9006 The interval of GC Life Time is too short and the data that should be read by the long transactions might be cleared. Extend the interval of GC Life Time. 9500 A single transaction is too large. See here for the solution. Troubleshooting See the troubleshooting and FAQ documents."}, {"url": "https://pingcap.com/docs/v2.0/sql/error/", "title": "Error Codes and Troubleshooting", "content": " Error Codes and Troubleshooting This document describes the problems encountered during the use of TiDB and provides the solutions.Error codes TiDB is compatible with the error codes in MySQL, and in most cases returns the same error code as MySQL. In addition, TiDB has the following unique error codes: Error code Description Solution 8001 The memory used by the request exceeds the threshold limit for the TiDB memory usage. Increase the value of the system variable with the tidb_mem_quota prefix. 8002 To guarantee consistency, a transaction with the SELECT FOR UPDATE statement cannot be retried when it encounters a commit conflict. TiDB rolls back the transaction and returns this error. Retry the failed transaction. 8003 If the data in a row is not consistent with the index when executing the ADMIN CHECK TABLE command, TiDB returns this error. 9001 The PD request timed out. Check the state/monitor/log of the PD server and the network between the TiDB server and the PD server. 9002 The TiKV request timed out. Check the state/monitor/log of the TiKV server and the network between the TiDB server and the TiKV server. 9003 The TiKV server is busy and this usually occurs when the workload is too high. Check the state/monitor/log of the TiKV server. 9004 This error occurs when a large number of transactional conflicts exist in the database. Check the code of application. 9005 A certain Raft Group is not available, such as the number of replicas is not enough. This error usually occurs when the TiKV server is busy or the TiKV node is down. Check the state/monitor/log of the TiKV server. 9006 The interval of GC Life Time is too short and the data that should be read by the long transactions might be cleared. Extend the interval of GC Life Time. 9500 A single transaction is too large. See here for the solution. Troubleshooting See the troubleshooting and FAQ documents."}, {"url": "https://pingcap.com/docs/sql/expression-syntax/", "title": "Expression Syntax", "content": " Expression Syntax The following rules define the expression syntax in TiDB. You can find the definition in parser/parser.y. The syntax parsing in TiDB is based on Yacc.Expression: singleAtIdentifier assignmentEq Expression | Expression logOr Expression | Expression "XOR" Expression | Expression logAnd Expression | "NOT" Expression | Factor IsOrNotOp trueKwd | Factor IsOrNotOp falseKwd | Factor IsOrNotOp "UNKNOWN" | Factor Factor: Factor IsOrNotOp "NULL" | Factor CompareOp PredicateExpr | Factor CompareOp singleAtIdentifier assignmentEq PredicateExpr | Factor CompareOp AnyOrAll SubSelect | PredicateExpr PredicateExpr: PrimaryFactor InOrNotOp '(' ExpressionList ')' | PrimaryFactor InOrNotOp SubSelect | PrimaryFactor BetweenOrNotOp PrimaryFactor "AND" PredicateExpr | PrimaryFactor LikeOrNotOp PrimaryExpression LikeEscapeOpt | PrimaryFactor RegexpOrNotOp PrimaryExpression | PrimaryFactor PrimaryFactor: PrimaryFactor '|' PrimaryFactor | PrimaryFactor '&' PrimaryFactor | PrimaryFactor "<<" PrimaryFactor | PrimaryFactor ">>" PrimaryFactor | PrimaryFactor '+' PrimaryFactor | PrimaryFactor '-' PrimaryFactor | PrimaryFactor '*' PrimaryFactor | PrimaryFactor '/' PrimaryFactor | PrimaryFactor '%' PrimaryFactor | PrimaryFactor "DIV" PrimaryFactor | PrimaryFactor "MOD" PrimaryFactor | PrimaryFactor '^' PrimaryFactor | PrimaryExpression PrimaryExpression: Operand | FunctionCallKeyword | FunctionCallNonKeyword | FunctionCallAgg | FunctionCallGeneric | Identifier jss stringLit | Identifier juss stringLit | SubSelect | '!' PrimaryExpression | '~' PrimaryExpression | '-' PrimaryExpression | '+' PrimaryExpression | "BINARY" PrimaryExpression | PrimaryExpression "COLLATE" StringName "}, {"url": "https://pingcap.com/docs/v1.0/sql/expression-syntax/", "title": "Expression Syntax", "content": " Expression Syntax The following rules define the expression syntax in TiDB. You can find the definition in parser/parser.y. The syntax parsing in TiDB is based on Yacc.Expression: singleAtIdentifier assignmentEq Expression | Expression logOr Expression | Expression "XOR" Expression | Expression logAnd Expression | "NOT" Expression | Factor IsOrNotOp trueKwd | Factor IsOrNotOp falseKwd | Factor IsOrNotOp "UNKNOWN" | Factor Factor: Factor IsOrNotOp "NULL" | Factor CompareOp PredicateExpr | Factor CompareOp singleAtIdentifier assignmentEq PredicateExpr | Factor CompareOp AnyOrAll SubSelect | PredicateExpr PredicateExpr: PrimaryFactor InOrNotOp '(' ExpressionList ')' | PrimaryFactor InOrNotOp SubSelect | PrimaryFactor BetweenOrNotOp PrimaryFactor "AND" PredicateExpr | PrimaryFactor LikeOrNotOp PrimaryExpression LikeEscapeOpt | PrimaryFactor RegexpOrNotOp PrimaryExpression | PrimaryFactor PrimaryFactor: PrimaryFactor '|' PrimaryFactor | PrimaryFactor '&' PrimaryFactor | PrimaryFactor "<<" PrimaryFactor | PrimaryFactor ">>" PrimaryFactor | PrimaryFactor '+' PrimaryFactor | PrimaryFactor '-' PrimaryFactor | PrimaryFactor '*' PrimaryFactor | PrimaryFactor '/' PrimaryFactor | PrimaryFactor '%' PrimaryFactor | PrimaryFactor "DIV" PrimaryFactor | PrimaryFactor "MOD" PrimaryFactor | PrimaryFactor '^' PrimaryFactor | PrimaryExpression PrimaryExpression: Operand | FunctionCallKeyword | FunctionCallNonKeyword | FunctionCallAgg | FunctionCallGeneric | Identifier jss stringLit | Identifier juss stringLit | SubSelect | '!' PrimaryExpression | '~' PrimaryExpression | '-' PrimaryExpression | '+' PrimaryExpression | "BINARY" PrimaryExpression | PrimaryExpression "COLLATE" StringName "}, {"url": "https://pingcap.com/docs/v2.0/sql/expression-syntax/", "title": "Expression Syntax", "content": " Expression Syntax The following rules define the expression syntax in TiDB. You can find the definition in parser/parser.y. The syntax parsing in TiDB is based on Yacc.Expression: singleAtIdentifier assignmentEq Expression | Expression logOr Expression | Expression "XOR" Expression | Expression logAnd Expression | "NOT" Expression | Factor IsOrNotOp trueKwd | Factor IsOrNotOp falseKwd | Factor IsOrNotOp "UNKNOWN" | Factor Factor: Factor IsOrNotOp "NULL" | Factor CompareOp PredicateExpr | Factor CompareOp singleAtIdentifier assignmentEq PredicateExpr | Factor CompareOp AnyOrAll SubSelect | PredicateExpr PredicateExpr: PrimaryFactor InOrNotOp '(' ExpressionList ')' | PrimaryFactor InOrNotOp SubSelect | PrimaryFactor BetweenOrNotOp PrimaryFactor "AND" PredicateExpr | PrimaryFactor LikeOrNotOp PrimaryExpression LikeEscapeOpt | PrimaryFactor RegexpOrNotOp PrimaryExpression | PrimaryFactor PrimaryFactor: PrimaryFactor '|' PrimaryFactor | PrimaryFactor '&' PrimaryFactor | PrimaryFactor "<<" PrimaryFactor | PrimaryFactor ">>" PrimaryFactor | PrimaryFactor '+' PrimaryFactor | PrimaryFactor '-' PrimaryFactor | PrimaryFactor '*' PrimaryFactor | PrimaryFactor '/' PrimaryFactor | PrimaryFactor '%' PrimaryFactor | PrimaryFactor "DIV" PrimaryFactor | PrimaryFactor "MOD" PrimaryFactor | PrimaryFactor '^' PrimaryFactor | PrimaryExpression PrimaryExpression: Operand | FunctionCallKeyword | FunctionCallNonKeyword | FunctionCallAgg | FunctionCallGeneric | Identifier jss stringLit | Identifier juss stringLit | SubSelect | '!' PrimaryExpression | '~' PrimaryExpression | '-' PrimaryExpression | '+' PrimaryExpression | "BINARY" PrimaryExpression | PrimaryExpression "COLLATE" StringName "}, {"url": "https://pingcap.com/tidb-academy/mysql_dbas/htap/TODO/", "title": "Finding the Busiest Day of the Year", "content": " Finding the Busiest Day of the Year In this query, we are finding the day of the year that had the highest number of bike trips:MySQL [bikeshare]> SELECT COUNT(*) c, DATE(start_date) as day_of_year FROM trips GROUP BY day_of_year ORDER BY c DESC LIMIT 10; +-------+-------------+ | c | day_of_year | +-------+-------------+ | 16896 | 2017-04-15 | | 16346 | 2017-08-05 | | 16191 | 2017-03-25 | | 16038 | 2017-04-14 | | 15767 | 2017-07-30 | | 15549 | 2017-07-26 | | 15517 | 2017-07-08 | | 15477 | 2017-10-07 | | 15434 | 2017-04-13 | | 15403 | 2017-07-04 | +-------+-------------+ 10 rows in set (4.73 sec) In EXPLAIN:MySQL [bikeshare]> EXPLAIN SELECT COUNT(*) c, DATE(start_date) as day_of_year FROM trips GROUP BY day_of_year ORDER BY c DESC LIMIT 10; +--------------------------+------------+------+-------------------------------------------------------------------------------------------------+ | id | count | task | operator info | +--------------------------+------------+------+-------------------------------------------------------------------------------------------------+ | Projection_7 | 10.00 | root | 2_col_0, date(bikeshare.trips.start_date) | | └─TopN_10 | 10.00 | root | 2_col_0:desc, offset:0, count:10 | | └─HashAgg_14 | 3390469.43 | root | group by:date(bikeshare.trips.start_date), funcs:count(1), firstrow(bikeshare.trips.start_date) | | └─TableReader_18 | 3757777.00 | root | data:TableScan_17 | | └─TableScan_17 | 3757777.00 | cop | table:trips, range:[-inf,+inf], keep order:false | +--------------------------+------------+------+-------------------------------------------------------------------------------------------------+ 5 rows in set (0.00 sec) So lets start by describing what’s happening: We have a tablescan again, because there is no WHERE clause or ability to filter rows. The tablescan operation feeds into TiDB (TableReader), where rows are in parallel inserted into a hash table to produce the grouping (summing the number of rows per date). This is a bit different to the previous query, because the coprocessor is not able to be used. While the date function is supported by the coprocessor, because each region is organized by a key range….. A top-N is then performed to retrieve the Top 10 rows. This query is already quite optimized, the only commentary I have is that in the version of TiKV I am using, the coprocessor is unable to handle the DATE function.Add index on start_date:ALTER TABLE trips ADD INDEX s (start_date); EXPLAIN SELECT COUNT(*) c, DATE(start_date) as day_of_year FROM trips GROUP BY day_of_year ORDER BY c DESC LIMIT 10; Here we can see X. The advantage of the index is two fold: - Coprocessor - Smaller scan area.Other info Our first example analytics query is to find out what are the busiest days of the year to rent a bike:If you are coming from a MySQL background, there are some features here which you will not be familiar with. Lets explain what’s happening here: A tablescan operation is reading each TiKV node to find rows that match. There is no where clause, so every row matches: it’s expected that the range be -inf to +inf. The tablescan operation feeds into TiDB (TableReader), where rows are in parallel inserted into a hash table to produce the grouping (summing the number of rows per date). A top-N is then performed to retrieve the Top 10 rows. This query is already quite optimized, the only commentary I have is that in the version of TiKV I am using, the coprocessor is unable to handle the DATE function. Which day of the week is the busiest for trips Which month is the busiest. What is the average number of trips per bike each day. "}, {"url": "https://pingcap.com/tidb-academy/mysql_dbas/introduction/format-and-housekeeping/", "title": "Format and Housekeeping", "content": " Format and Housekeeping Transcript Before we get deep in the weeds, I want to cover some housekeeping items.Starting off, let’s talk about the format. TiDB for MySQL DBAs uses a combination of videos and hands-on exercises. You will need a Google Cloud Platform, or GCP, account in order to complete the tutorials, and a Google Kubernetes Engine cluster of 3x n1-standard instances. GCP comes with a $300 credit for the first year of usage, which is more than enough to complete this course.If you have trouble with any of the exercises, you can reach out to academy@pingcap.com. Myself and the team at PingCAP are ready and eager to help you and aim to get back to you within a 24 hour timeframe.We have built this course to work within the performance limitations of n1-standard instances with network attached storage. But in order to give you a touch of production experience, some commands (such as adding an index on a large table) may take up to 10 minutes to run. We will do our best to give you a heads up when a step in an exercise will take some time so that you can use this opportunity to take a break and stretch your legs. But for the most part know that this is intentional on our part. We want to simulate a touch of real-world experience.OK. I think that’s it. Continue on and let’s get started!"}, {"url": "https://pingcap.com/docs/sql/functions-and-operators-reference/", "title": "Function and Operator Reference", "content": " Function and Operator Reference The usage of the functions and operators in TiDB is similar to MySQL. See Functions and Operators in MySQL.In SQL statements, expressions can be used on the ORDER BY and HAVING clauses of the SELECT statement, the WHERE clause of SELECT/DELETE/UPDATE statements, and SET statements.You can write expressions using literals, column names, NULL, built-in functions, operators and so on."}, {"url": "https://pingcap.com/docs/v1.0/sql/functions-and-operators-reference/", "title": "Function and Operator Reference", "content": " Function and Operator Reference The usage of the functions and operators in TiDB is similar to MySQL. See Functions and Operators in MySQL.In SQL statements, expressions can be used on the ORDER BY and HAVING clauses of the SELECT statement, the WHERE clause of SELECT/DELETE/UPDATE statements, and SET statements.You can write expressions using literals, column names, NULL, built-in functions, operators and so on."}, {"url": "https://pingcap.com/docs/v2.0/sql/functions-and-operators-reference/", "title": "Function and Operator Reference", "content": " Function and Operator Reference The usage of the functions and operators in TiDB is similar to MySQL. See Functions and Operators in MySQL.In SQL statements, expressions can be used on the ORDER BY and HAVING clauses of the SELECT statement, the WHERE clause of SELECT/DELETE/UPDATE statements, and SET statements.You can write expressions using literals, column names, NULL, built-in functions, operators and so on."}, {"url": "https://pingcap.com/docs-cn/sql/aggregate-group-by-functions/", "title": "GROUP BY 聚合函数", "content": " GROUP BY 聚合函数 本文将详细介绍 TiDB 支持的聚合函数。TiDB 支持的聚合函数 TiDB 支持的 MySQL GROUP BY 聚合函数如下所示: 函数名 功能描述 COUNT() 返回检索到的行的数目 COUNT(DISTINCT) 返回不同值的数目 SUM() 返回和 AVG() 返回平均值 MAX() 返回最大值 MIN() 返回最小值 GROUP_CONCAT() 返回连接的字符串 注意: 除非另有说明,否则组函数默认忽略 NULL 值。 如果在不包含 GROUP BY 子句的语句中使用组函数,则相当于对所有行进行分组。 GROUP BY 修饰符 TiDB 目前不支持 GROUP BY 修饰符,例如 WITH ROLLUP,将来会提供支持。详情参阅 #4250。对 SQL 模式的支持 TiDB 支持 SQL 模式 ONLY_FULL_GROUP_BY,当启用该模式时,TiDB 拒绝不明确的非聚合列的查询。例如,以下查询在启用 ONLY_FULL_GROUP_BY 时是不合规的,因为 SELECT 列表中的非聚合列 “b” 在 GROUP BY 语句中不显示:drop table if exists t; create table t(a bigint, b bigint, c bigint); insert into t values(1, 2, 3), (2, 2, 3), (3, 2, 3); mysql> select a, b, sum(c) from t group by a; +------+------+--------+ | a | b | sum(c) | +------+------+--------+ | 1 | 2 | 3 | | 2 | 2 | 3 | | 3 | 2 | 3 | +------+------+--------+ 3 rows in set (0.01 sec) mysql> set sql_mode = 'ONLY_FULL_GROUP_BY'; Query OK, 0 rows affected (0.00 sec) mysql> select a, b, sum(c) from t group by a; ERROR 1055 (42000): Expression #2 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'b' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by 目前,TiDB 默认不开启 SQL 模式 ONLY_FULL_GROUP_BY。与 MySQL 的区别 TiDB 目前实现的 ONLY_FULL_GROUP_BY 没有 MySQL 5.7 严格。例如,假设我们执行以下查询,希望结果按 “c” 排序:drop table if exists t; create table t(a bigint, b bigint, c bigint); insert into t values(1, 2, 1), (1, 2, 2), (1, 3, 1), (1, 3, 2); select distinct a, b from t order by c; 要对结果进行排序,必须先清除重复。但选择保留哪一行会影响 c 的保留值,也会影响排序,并使其具有任意性。在 MySQL 中,ORDER BY 表达式需至少满足以下条件之一,否则 DISTINCT 和 ORDER BY 查询将因不合规而被拒绝: 表达式等同于 SELECT 列表中的一个。 表达式引用并属于查询选择表的所有列都是 SELECT 列表的元素。 但是在 TiDB 中,上述查询是合规的,详情参阅 #4254。TiDB 中另一个标准 SQL 的扩展允许 HAVING 子句中的引用使用 SELECT 列表中的别名表达式。例如:以下查询返回在 orders 中只出现一次的 name 值:select name, count(name) from orders group by name having count(name) = 1; 这个 TiDB 扩展允许在聚合列的 HAVING 子句中使用别名:select name, count(name) as c from orders group by name having c = 1; 标准 SQL 只支持 GROUP BY 子句中的列表达式,以下语句不合规,因为 FLOOR(value/100) 是一个非列表达式:select id, floor(value/100) from tbl_name group by id, floor(value/100); TiDB 对标准 SQL 的扩展支持 GROUP BY 子句中非列表达式,认为上述语句合规。标准 SQL 也不支持 GROUP BY 子句中使用别名。TiDB 对标准 SQL 的扩展支持使用别名,查询的另一种写法如下:select id, floor(value/100) as val from tbl_name group by id, val; TiDB 不支持的聚合函数 TiDB 目前不支持的聚合函数如下所示,相关进展参阅 TiDB #7623。 STD, STDDEV, STDDEV_POP STDDEV_SAMP VARIANCE, VAR_POP VAR_SAMP JSON_ARRAYAGG JSON_OBJECTAGG "}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/aggregate-group-by-functions/", "title": "GROUP BY 聚合函数", "content": " GROUP BY 聚合函数 GROUP BY 聚合函数功能描述 本节介绍 TiDB 中支持的 MySQL GROUP BY 聚合函数。 函数名 功能描述 COUNT() 返回检索到的行的数目 COUNT(DISTINCT) 返回不同值的数目 SUM() 返回和 AVG() 返回平均值 MAX() 返回最大值 MIN() 返回最小值 GROUP_CONCAT() 返回连接的字符串 Note: 除非另有说明,否则组函数默认忽略 NULL 值。 如果在不包含 GROUP BY 子句的语句中使用组函数,则相当于对所有行进行分组。详情参阅 TiDB 中的 GROUP BY。 GROUP BY 修饰符 TiDB 目前不支持任何 GROUP BY 修饰符,将来会提供支持,详情参阅 #4250。TiDB 中的 GROUP BY 当 SQL 模式 ONLY_FULL_GROUP_BY 被禁用时,TiDB 与 MySQL 等效:允许 SELECT 列表、HAVING 条件或 ORDER BY 列表引用非聚合列,即使这些列在功能上不依赖于 GROUP BY 列。例如,在 MySQL 5.7.5 中使用 ONLY_FULL_GROUP_BY 的查询是不合规的,因为 SELECT 列表中的非聚合列 “b” 在 GROUP BY 中不显示:drop table if exists t; create table t(a bigint, b bigint, c bigint); insert into t values(1, 2, 3), (2, 2, 3), (3, 2, 3); select a, b, sum(c) from t group by a; 上述查询在 TiDB 中是合规的。TiDB 目前不支持 SQL 模式 ONLY_FULL_GROUP_BY,将来会提供支持,详情参阅 #4248。假设我们执行以下查询,希望结果按 c 排序:drop table if exists t; create table t(a bigint, b bigint, c bigint); insert into t values(1, 2, 1), (1, 2, 2), (1, 3, 1), (1, 3, 2); select distinct a, b from t order by c; 要对结果进行排序,必须先清除重复。但选择保留哪一行会影响 c 的保留值,也会影响排序,并使其具有任意性。在 MySQL 中,ORDER BY 表达式需至少满足以下条件之一,否则 DISTINCT 和 ORDER BY 查询将因不合规而被拒绝: 表达式等同于 SELECT 列表中的一个。 表达式引用并属于查询选择表的所有列都是 SELECT 列表的元素。 但是在 TiDB 中,上述查询是合规的,详情参阅 #4254。TiDB 中另一个标准 SQL 的扩展允许 HAVING 子句中的引用使用 SELECT 列表中的别名表达式。例如:以下查询返回在 orders 中只出现一次的 name 值:select name, count(name) from orders group by name having count(name) = 1; 这个 TiDB 扩展允许在聚合列的 HAVING 子句中使用别名:select name, count(name) as c from orders group by name having c = 1; 标准 SQL 只支持 GROUP BY 子句中的列表达式,以下语句不合规,因为 FLOOR(value/100) 是一个非列表达式:select id, floor(value/100) from tbl_name group by id, floor(value/100); TiDB 对标准 SQL 的扩展支持 GROUP BY 子句中非列表达式,认为上述语句合规。标准 SQL 也不支持 GROUP BY 子句中使用别名。TiDB 对标准 SQL 的扩展支持使用别名,查询的另一种写法如下:select id, floor(value/100) as val from tbl_name group by id, val; 函数依赖检测 TiDB 不支持 SQL 模式 ONLY_FULL_GROUP_BY 和函数依赖检测,将来会提供支持,详情参阅 #4248。"}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/aggregate-group-by-functions/", "title": "GROUP BY 聚合函数", "content": " GROUP BY 聚合函数 GROUP BY 聚合函数功能描述 本节介绍 TiDB 中支持的 MySQL GROUP BY 聚合函数。 函数名 功能描述 COUNT() 返回检索到的行的数目 COUNT(DISTINCT) 返回不同值的数目 SUM() 返回和 AVG() 返回平均值 MAX() 返回最大值 MIN() 返回最小值 GROUP_CONCAT() 返回连接的字符串 Note: 除非另有说明,否则组函数默认忽略 NULL 值。 如果在不包含 GROUP BY 子句的语句中使用组函数,则相当于对所有行进行分组。详情参阅 TiDB 中的 GROUP BY。 GROUP BY 修饰符 TiDB 目前不支持任何 GROUP BY 修饰符,将来会提供支持,详情参阅 #4250。TiDB 中的 GROUP BY 当 SQL 模式 ONLY_FULL_GROUP_BY 被禁用时,TiDB 与 MySQL 等效:允许 SELECT 列表、HAVING 条件或 ORDER BY 列表引用非聚合列,即使这些列在功能上不依赖于 GROUP BY 列。例如,在 MySQL 5.7.5 中使用 ONLY_FULL_GROUP_BY 的查询是不合规的,因为 SELECT 列表中的非聚合列 “b” 在 GROUP BY 中不显示:drop table if exists t; create table t(a bigint, b bigint, c bigint); insert into t values(1, 2, 3), (2, 2, 3), (3, 2, 3); select a, b, sum(c) from t group by a; 上述查询在 TiDB 中是合规的。TiDB 目前不支持 SQL 模式 ONLY_FULL_GROUP_BY,将来会提供支持,详情参阅 #4248。假设我们执行以下查询,希望结果按 c 排序:drop table if exists t; create table t(a bigint, b bigint, c bigint); insert into t values(1, 2, 1), (1, 2, 2), (1, 3, 1), (1, 3, 2); select distinct a, b from t order by c; 要对结果进行排序,必须先清除重复。但选择保留哪一行会影响 c 的保留值,也会影响排序,并使其具有任意性。在 MySQL 中,ORDER BY 表达式需至少满足以下条件之一,否则 DISTINCT 和 ORDER BY 查询将因不合规而被拒绝: 表达式等同于 SELECT 列表中的一个。 表达式引用并属于查询选择表的所有列都是 SELECT 列表的元素。 但是在 TiDB 中,上述查询是合规的,详情参阅 #4254。TiDB 中另一个标准 SQL 的扩展允许 HAVING 子句中的引用使用 SELECT 列表中的别名表达式。例如:以下查询返回在 orders 中只出现一次的 name 值:select name, count(name) from orders group by name having count(name) = 1; 这个 TiDB 扩展允许在聚合列的 HAVING 子句中使用别名:select name, count(name) as c from orders group by name having c = 1; 标准 SQL 只支持 GROUP BY 子句中的列表达式,以下语句不合规,因为 FLOOR(value/100) 是一个非列表达式:select id, floor(value/100) from tbl_name group by id, floor(value/100); TiDB 对标准 SQL 的扩展支持 GROUP BY 子句中非列表达式,认为上述语句合规。标准 SQL 也不支持 GROUP BY 子句中使用别名。TiDB 对标准 SQL 的扩展支持使用别名,查询的另一种写法如下:select id, floor(value/100) as val from tbl_name group by id, val; 函数依赖检测 TiDB 不支持 SQL 模式 ONLY_FULL_GROUP_BY 和函数依赖检测,将来会提供支持,详情参阅 #4248。"}, {"url": "https://pingcap.com/docs/op-guide/generate-self-signed-certificates/", "title": "Generate Self-signed Certificates", "content": " Generate Self-signed Certificates Overview This document describes how to generate self-signed certificates using cfssl.Assume that the topology of the instance cluster is as follows: Name Host IP Services node1 172.16.10.1 PD1, TiDB1 node2 172.16.10.2 PD2, TiDB2 node3 172.16.10.3 PD3 node4 172.16.10.4 TiKV1 node5 172.16.10.5 TiKV2 node6 172.16.10.6 TiKV3 Download cfssl Assume that the host is x86_64 Linux:mkdir ~/bin curl -s -L -o ~/bin/cfssl https://pkg.cfssl.org/R1.2/cfssl_linux-amd64 curl -s -L -o ~/bin/cfssljson https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64 chmod +x ~/bin/{cfssl,cfssljson} export PATH=$PATH:~/bin Initialize the certificate authority To make it easy for modification later, generate the default configuration of cfssl:mkdir ~/cfssl cd ~/cfssl cfssl print-defaults config > ca-config.json cfssl print-defaults csr > ca-csr.json Generate certificates Certificates description tidb-server certificate: used by TiDB to authenticate TiDB for other components and clients tikv-server certificate: used by TiKV to authenticate TiKV for other components and clients pd-server certificate: used by PD to authenticate PD for other components and clients client certificate: used to authenticate the clients from PD, TiKV and TiDB, such as pd-ctl, tikv-ctl and pd-recover Configure the CA option Edit ca-config.json according to your need:{ "signing": { "default": { "expiry": "43800h" }, "profiles": { "server": { "expiry": "43800h", "usages": [ "signing", "key encipherment", "server auth", "client auth" ] }, "client": { "expiry": "43800h", "usages": [ "signing", "key encipherment", "client auth" ] } } } } Edit ca-csr.json according to your need:{ "CN": "My own CA", "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "CN", "L": "Beijing", "O": "PingCAP", "ST": "Beijing" } ] } Generate the CA certificate cfssl gencert -initca ca-csr.json | cfssljson -bare ca - The command above generates the following files:ca-key.pem ca.csr ca.pem Generate the server certificate The IP address of all components and 127.0.0.1 are included in hostname.echo '{"CN":"tidb-server","hosts":[""],"key":{"algo":"rsa","size":2048}}' | cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=server -hostname="172.16.10.1,172.16.10.2,127.0.0.1" - | cfssljson -bare tidb-server echo '{"CN":"tikv-server","hosts":[""],"key":{"algo":"rsa","size":2048}}' | cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=server -hostname="172.16.10.4,172.16.10.5,172.16.10.6,127.0.0.1" - | cfssljson -bare tikv-server echo '{"CN":"pd-server","hosts":[""],"key":{"algo":"rsa","size":2048}}' | cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=server -hostname="172.16.10.1,172.16.10.2,172.16.10.3,127.0.0.1" - | cfssljson -bare pd-server The command above generates the following files:tidb-server-key.pem tikv-server-key.pem pd-server-key.pem tidb-server.csr tikv-server.csr pd-server.csr tidb-server.pem tikv-server.pem pd-server.pem Generate the client certificate echo '{"CN":"client","hosts":[""],"key":{"algo":"rsa","size":2048}}' | cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=client -hostname="" - | cfssljson -bare client The command above generates the following files:client-key.pem client.csr client.pem"}, {"url": "https://pingcap.com/docs/v1.0/op-guide/generate-self-signed-certificates/", "title": "Generate Self-signed Certificates", "content": " Generate Self-signed Certificates Overview This document describes how to generate self-signed certificates using cfssl.Assume that the topology of the instance cluster is as follows: Name Host IP Services node1 172.16.10.1 PD1, TiDB1 node2 172.16.10.2 PD2, TiDB2 node3 172.16.10.3 PD3 node4 172.16.10.4 TiKV1 node5 172.16.10.5 TiKV2 node6 172.16.10.6 TiKV3 Download cfssl Assume that the host is x86_64 Linux:mkdir ~/bin curl -s -L -o ~/bin/cfssl https://pkg.cfssl.org/R1.2/cfssl_linux-amd64 curl -s -L -o ~/bin/cfssljson https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64 chmod +x ~/bin/{cfssl,cfssljson} export PATH=$PATH:~/bin Initialize the certificate authority To make it easy for modification later, generate the default configuration of cfssl:mkdir ~/cfssl cd ~/cfssl cfssl print-defaults config > ca-config.json cfssl print-defaults csr > ca-csr.json Generate certificates Certificates description tidb-server certificate: used by TiDB to authenticate TiDB for other components and clients tikv-server certificate: used by TiKV to authenticate TiKV for other components and clients pd-server certificate: used by PD to authenticate PD for other components and clients client certificate: used to authenticate the clients from PD, TiKV and TiDB, such as pd-ctl, tikv-ctl and pd-recover Configure the CA option Edit ca-config.json according to your need:{ "signing": { "default": { "expiry": "43800h" }, "profiles": { "server": { "expiry": "43800h", "usages": [ "signing", "key encipherment", "server auth", "client auth" ] }, "client": { "expiry": "43800h", "usages": [ "signing", "key encipherment", "client auth" ] } } } } Edit ca-csr.json according to your need:{ "CN": "My own CA", "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "CN", "L": "Beijing", "O": "PingCAP", "ST": "Beijing" } ] } Generate the CA certificate cfssl gencert -initca ca-csr.json | cfssljson -bare ca - The command above generates the following files:ca-key.pem ca.csr ca.pem Generate the server certificate The IP address of all components and 127.0.0.1 are included in hostname.echo '{"CN":"tidb-server","hosts":[""],"key":{"algo":"rsa","size":2048}}' | cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=server -hostname="172.16.10.1,172.16.10.2,127.0.0.1" - | cfssljson -bare tidb-server echo '{"CN":"tikv-server","hosts":[""],"key":{"algo":"rsa","size":2048}}' | cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=server -hostname="172.16.10.4,172.16.10.5,172.16.10.6,127.0.0.1" - | cfssljson -bare tikv-server echo '{"CN":"pd-server","hosts":[""],"key":{"algo":"rsa","size":2048}}' | cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=server -hostname="172.16.10.1,172.16.10.2,172.16.10.3,127.0.0.1" - | cfssljson -bare pd-server The command above generates the following files:tidb-server-key.pem tikv-server-key.pem pd-server-key.pem tidb-server.csr tikv-server.csr pd-server.csr tidb-server.pem tikv-server.pem pd-server.pem Generate the client certificate echo '{"CN":"client","hosts":[""],"key":{"algo":"rsa","size":2048}}' | cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=client -hostname="" - | cfssljson -bare client The command above generates the following files:client-key.pem client.csr client.pem"}, {"url": "https://pingcap.com/docs/v2.0/op-guide/generate-self-signed-certificates/", "title": "Generate Self-signed Certificates", "content": " Generate Self-signed Certificates Overview This document describes how to generate self-signed certificates using cfssl.Assume that the topology of the instance cluster is as follows: Name Host IP Services node1 172.16.10.1 PD1, TiDB1 node2 172.16.10.2 PD2, TiDB2 node3 172.16.10.3 PD3 node4 172.16.10.4 TiKV1 node5 172.16.10.5 TiKV2 node6 172.16.10.6 TiKV3 Download cfssl Assume that the host is x86_64 Linux:mkdir ~/bin curl -s -L -o ~/bin/cfssl https://pkg.cfssl.org/R1.2/cfssl_linux-amd64 curl -s -L -o ~/bin/cfssljson https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64 chmod +x ~/bin/{cfssl,cfssljson} export PATH=$PATH:~/bin Initialize the certificate authority To make it easy for modification later, generate the default configuration of cfssl:mkdir ~/cfssl cd ~/cfssl cfssl print-defaults config > ca-config.json cfssl print-defaults csr > ca-csr.json Generate certificates Certificates description tidb-server certificate: used by TiDB to authenticate TiDB for other components and clients tikv-server certificate: used by TiKV to authenticate TiKV for other components and clients pd-server certificate: used by PD to authenticate PD for other components and clients client certificate: used to authenticate the clients from PD, TiKV and TiDB, such as pd-ctl, tikv-ctl and pd-recover Configure the CA option Edit ca-config.json according to your need:{ "signing": { "default": { "expiry": "43800h" }, "profiles": { "server": { "expiry": "43800h", "usages": [ "signing", "key encipherment", "server auth", "client auth" ] }, "client": { "expiry": "43800h", "usages": [ "signing", "key encipherment", "client auth" ] } } } } Edit ca-csr.json according to your need:{ "CN": "My own CA", "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "CN", "L": "Beijing", "O": "PingCAP", "ST": "Beijing" } ] } Generate the CA certificate cfssl gencert -initca ca-csr.json | cfssljson -bare ca - The command above generates the following files:ca-key.pem ca.csr ca.pem Generate the server certificate The IP address of all components and 127.0.0.1 are included in hostname.echo '{"CN":"tidb-server","hosts":[""],"key":{"algo":"rsa","size":2048}}' | cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=server -hostname="172.16.10.1,172.16.10.2,127.0.0.1" - | cfssljson -bare tidb-server echo '{"CN":"tikv-server","hosts":[""],"key":{"algo":"rsa","size":2048}}' | cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=server -hostname="172.16.10.4,172.16.10.5,172.16.10.6,127.0.0.1" - | cfssljson -bare tikv-server echo '{"CN":"pd-server","hosts":[""],"key":{"algo":"rsa","size":2048}}' | cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=server -hostname="172.16.10.1,172.16.10.2,172.16.10.3,127.0.0.1" - | cfssljson -bare pd-server The command above generates the following files:tidb-server-key.pem tikv-server-key.pem pd-server-key.pem tidb-server.csr tikv-server.csr pd-server.csr tidb-server.pem tikv-server.pem pd-server.pem Generate the client certificate echo '{"CN":"client","hosts":[""],"key":{"algo":"rsa","size":2048}}' | cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=client -hostname="" - | cfssljson -bare client The command above generates the following files:client-key.pem client.csr client.pem"}, {"url": "https://pingcap.com/docs-cn/sql/generated-columns/", "title": "Generated Column", "content": " Generated Column 为了在功能上兼容 MySQL 5.7,TiDB 支持 generated column。Generated column 的主要的作用之一:从 JSON 数据类型中解出数据,并为该数据建立索引。使用 generated column 对 JSON 建索引 MySQL 5.7 及 TiDB 都不能直接为 JSON 类型的列添加索引,即不支持如下表结构:CREATE TABLE person ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255) NOT NULL, address_info JSON, KEY (address_info) ); 为 JSON 列添加索引之前,首先必须抽取该列为 generated column。以 city generated column 为例,你可以添加索引:CREATE TABLE person ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255) NOT NULL, address_info JSON, city VARCHAR(64) AS (JSON_UNQUOTE(JSON_EXTRACT(address_info, '$.city'))) VIRTUAL, KEY (city) ); 该表中,city 列是一个 generated column。顾名思义,此列由该表的其他列生成,对此列进行插入或更新操作时,并不能对之赋值。此列按需生成,并不存储在数据库中,也不占用内存空间,因而是虚拟的。city 列的索引存储在数据库中,并使用和 varchar(64) 类的其他索引相同的结构。可使用 generated column 的索引,以提高如下语句的执行速度:SELECT name, id FROM person WHERE city = 'Beijing'; 如果 $.city 路径中无数据,则 JSON_EXTRACT 返回 NULL。如果你想增加约束:city 列必须是NOT NULL,则可按照以下方式定义 virtual column:CREATE TABLE person ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255) NOT NULL, address_info JSON, city VARCHAR(64) AS (JSON_UNQUOTE(JSON_EXTRACT(address_info, '$.city'))) VIRTUAL NOT NULL, KEY (city) ); INSERT 和 UPDATE 语句都会检查 virtual column 的定义。未通过有效性检测的行会返回错误:mysql> INSERT INTO person (name, address_info) VALUES ('Morgan', JSON_OBJECT('Country', 'Canada')); ERROR 1048 (23000): Column 'city' cannot be null 局限性 目前 JSON and generated column 有以下局限性: 不能通过 ALTER TABLE 增加 STORED 存储方式的 generated column; 不能通过 ALTER TABLE 在 generated column 上增加索引; 并未支持所有的 JSON 函数。 "}, {"url": "https://pingcap.com/docs/sql/generated-columns/", "title": "Generated Columns", "content": " Generated Columns TiDB supports generated columns as part of MySQL 5.7 compatibility. One of the primary use cases for generated columns is to extract data out of a JSON data type and enable it to be indexed.Index JSON using generated column In both MySQL 5.7 and TiDB, columns of type JSON can not be indexed directly. i.e. The following table structure is not supported:CREATE TABLE person ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255) NOT NULL, address_info JSON, KEY (address_info) ); In order to index a JSON column, you must first extract it as a generated column. Using the city generated column as an example, you are then able to add an index:CREATE TABLE person ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255) NOT NULL, address_info JSON, city VARCHAR(64) AS (JSON_UNQUOTE(JSON_EXTRACT(address_info, '$.city'))) VIRTUAL, KEY (city) ); In this table, the city column is a generated column. As the name implies, the column is generated from other columns in the table, and cannot be assigned a value when inserted or updated. The column is also virtual in that it does not require any storage or memory, and is generated on demand. The index on city however is stored and uses the same structure as other indexes of the type varchar(64).You can use the index on the generated column in order to speed up the following statement:SELECT name, id FROM person WHERE city = 'Beijing'; If no data exists at path $.city, JSON_EXTRACT returns NULL. If you want to enforce a constraint that city must be NOT NULL, you can define the virtual column as follows:CREATE TABLE person ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255) NOT NULL, address_info JSON, city VARCHAR(64) AS (JSON_UNQUOTE(JSON_EXTRACT(address_info, '$.city'))) VIRTUAL NOT NULL, KEY (city) ); Both INSERT and UPDATE statements check virtual column definitions. Rows that do not pass validation return errors:mysql> INSERT INTO person (name, address_info) VALUES ('Morgan', JSON_OBJECT('Country', 'Canada')); ERROR 1048 (23000): Column 'city' cannot be null Limitations The current limitations of JSON and generated columns are as follows: You cannot add the generated column in the storage type of STORED through ALTER TABLE. You cannot create an index on the generated column through ALTER TABLE. Not all JSON functions are supported. "}, {"url": "https://pingcap.com/tidb-academy/mysql_dbas/introduction/google-cloud-platform/", "title": "Google Cloud Platform", "content": " Google Cloud Platform Sign up for a $300 free trial for Google Cloud Platform.A valid credit card is required. Provided you complete the course in a short enough time frame, your credit card will not be charged. PingCAP is not responsible for any usage fees incurred."}, {"url": "https://pingcap.com/tidb-academy/mysql_dbas/ddl/f1-ddl-algorithm/", "title": "Google's F1 DDL Algorithm", "content": " Google’s F1 DDL Algorithm Resources F1 Paper Transcript So in our previous video, I asserted that DDL in TiDB is both online, and despite being a distributed system, is able to externalize schema changes everywhere at the same time. So how does it work?The short version is that TiDB uses the methodology described in Google’s Online, Asynchronous Schema Change in F1 paper. Let me try and summarize the methodology using an analogy: You work for an international company with employees distributed across the world. Your main communication channel with other employees is email. The company has decided that it wants to switch all communication channels to Slack. They want to both make the switch, and ensure that everyone makes the change at the same time. So what is the best way to achieve this with everyone distributed?Well, an easy way to do this is to announce the change well in advance. This way, everyone knows that at Noon UTC, it’s time to switch to Slack and stop using email. And that is a part-solution to solving the DDL synchronization problem.Let’s complicate the scenario a little: Your company uses Email. It decided to switch to HipChat (posting notice in email). It then decided to switch to Slack (posting notice in HipChat). Let’s also assume that as soon as it switched to Slack, it also shut down HipChat. In our naive scenario, we could have users on email that did not check-in quickly enough and now are not able to receive instruction in HipChat that they should now be using Slack.So an improvement on our algorithm of “posting advance notice of schema changes” is to agree to check back in for schema changes at defined intervals. This is getting close to how DDL works in TiDB, where there will be a lease for a version of schema, with a set time to check back in for updates.The other lesson that we can learn from this analogy is that when the company switched to HipChat, it should have forced all employees to be on it before switching to Slack. By agreeing to a lease time, there should only be a very brief window when both technologies are deployed which is the result of clock skew. Tolerating a small window allows the system to be online and not have a freeze where communication is not sent to email or HipChat.The last lesson we can learn is that an individual change (such as adding an index) can be broken down into smaller incremental operations that are safe to transit from one step to the next. An example of this might be, if I add an index to a column, the first step should be to have a version of the schema that all TiDB servers upgrade to which starts maintaining the index. When it is ensured that all TiDB servers are maintaining the indexes, the next step is to sweep through and reading rows one-by-one to create the index. If we were not able to ensure all servers had a minimum version of the schema, there could be a rogue TiDB server which updated a row but didn’t update the index. Thus our index would be corrupt. This staged deployment also helps introduce schema changes to existing queries that are in-flight, such as a long running update.So that is the gist of the F1 paper, in my own words. What is also key to enforce here, is that the TiDB servers are both stateless, but also without a concept of membership. Having membership would make the scaling process more complicated, so schema change works on a concept of a lease instead. Our analogy of a distributed set of employees using email is useful here, in that in an alternative universe, employees might all be in the same office and you can just broadcast a schema change over the intercom system. To add a little more system detail: The meta data itself is stored in TiKV, but it is the PD server which is responsible for notifying TiDB instances that the schema version has changed.If you would like to read in more detail, I recommend reading the F1 paper directly. It is included in the resources for this video. In the next step, we’ll be performing DDL on our example database and verifying that it is indeed online."}, {"url": "https://pingcap.com/recruit-cn/campus/campus-2019-hr-management-trainee/", "title": "HR Management Trainee", "content": " 人力资源管培生 岗位职责: 与 Team 小伙伴一起制定公司招聘计划并实施落地,搭建人才地图; 与 Team 小伙伴一起搭建组织发展、绩效评估体系,进行员工关系管理及入、离、调、转等; 与 Team 小伙伴一起搭建与完善公司培训体系,进行人才梯队建设及重点人才培养,企业文化宣传、落地等; 与 Team 小伙伴一起为业务体系提供专业的人力资源支持与服务。 任职要求: 对人力资源及 High Tech 有强烈的好奇心; 积极主动,具备较好的逻辑思维能力及强烈的求知欲,乐于不断接受新的挑战; 英语好,善于与人交流和收集信息,有计算机相关知识或互联网公司实习经验的优先。 待遇:8K - 15K,13薪 + 奖金,优秀者可面议联系方式:hire@pingcap.com工作地点:北京"}, {"url": "https://pingcap.com/tidb-academy/mysql_dbas/htap/lab/", "title": "HTAP", "content": " HTAP "}, {"url": "https://pingcap.com/tidb-academy/mysql_dbas/htap/overview/", "title": "HTAP", "content": " HTAP Transcript Welcome back.A few sections back we talked about query optimization, and the examples used mostly fit into the category of what we call OLTP or online transaction processing.In this section we, are going to talk about a different type of query, which is used as part of a business’ reporting needs or decision support systems. These queries tend to be more expensive to execute as they often read a lot of data and aggregate it. We are of course talking about the category of queries called OLAP.Traditionally, these two categories of queries have been better served by using different database systems. i.e. the transactions are processed in one technology, and then extracted and loaded into a data warehouse in batch for later processing.And when we think about a traditional business - this workflow fits in nicely. Overnight, after the business day finishes, a job kicks off to perform the ETL (extract, transform and load) operation.If we look at businesses today though, they are global and transact 24x7. If we look at retail, one of the hot trends, it is same day or instant local delivery. This makes ETL more burdensome because now you can’t instantly report and make decisions on your transactional data.This is where HTAP enters the picture. It means that you can execute both types of queries on the same database system."}, {"url": "https://pingcap.com/en/", "title": "Home", "content": ""}, {"url": "https://pingcap.com/tidb-academy/mysql_dbas/scaling/overview/", "title": "Horizontal Scaling", "content": " Horizontal Scaling Transcript Welcome back. In this video, we are going to talk about scaling, which for the TiDB platform you can independently perform across two different dimensions.First, you can scale the SQL processing by changing the number of TiDB Servers. Since TiDB servers are stateless, this is a very quick operation, both in terms of scaling out by increasing the count of TiDB instances and in terms of scaling in by decreasing the count.The second type of scaling is with regard to storage and the number of TiKV Servers. With TiKV, it is relatively simple to increase or scale up the number of instances, but with decreasing there is a little bit of added complexity. Because TiKV maintains state (it stores your data), scale in activity has to be performed in such a fashion that it doesn’t degrade the health of the cluster.That is to say, scaling TiKV involves an act of rebalancing the Regions (which is TiDB Platform terminology for units of approximately 100MB each). A graceful scale in leaves sufficient time for servers to be drained of their Regions with the remaining TiKV servers having sufficient free capacity to take over.This problem is not unique to TiKV. The good news is: Kubernetes understands that there are these additional steps to scale stateful services. With Kubernetes and operator, scaling both SQL and storage is not only possible but actually very easy to achieve."}, {"url": "https://pingcap.com/tidb-planet/become-a-contributor/", "title": "How to become a contributor", "content": ""}, {"url": "https://pingcap.com/docs/sql/information-functions/", "title": "Information Functions", "content": " Information Functions In TiDB, the usage of information functions is similar to MySQL. For more information, see Information Functions.Information function descriptions Name Description CONNECTION_ID() Return the connection ID (thread ID) for the connection CURRENT_USER(), CURRENT_USER Return the authenticated user name and host name DATABASE() Return the default (current) database name FOUND_ROWS() For a SELECT with a LIMIT clause, the number of the rows that are returned if there is no LIMIT clause LAST_INSERT_ID() Return the value of the AUTOINCREMENT column for the last INSERT SCHEMA() Synonym for DATABASE() SESSION_USER() Synonym for USER() SYSTEM_USER() Synonym for USER() USER() Return the user name and host name provided by the client VERSION() Return a string that indicates the MySQL server version TIDB_VERSION() Return a string that indicates the TiDB server version "}, {"url": "https://pingcap.com/docs/v1.0/sql/information-functions/", "title": "Information Functions", "content": " Information Functions In TiDB, the usage of information functions is similar to MySQL. For more information, see Information Functions.Information function descriptions Name Description CONNECTION_ID() Return the connection ID (thread ID) for the connection CURRENT_USER(), CURRENT_USER Return the authenticated user name and host name DATABASE() Return the default (current) database name FOUND_ROWS() For a SELECT with a LIMIT clause, the number of the rows that are returned if there is no LIMIT clause LAST_INSERT_ID() Return the value of the AUTOINCREMENT column for the last INSERT SCHEMA() Synonym for DATABASE() SESSION_USER() Synonym for USER() SYSTEM_USER() Synonym for USER() USER() Return the user name and host name provided by the client VERSION() Return a string that indicates the MySQL server version TIDB_VERSION Return a string that indicates the TiDB server version "}, {"url": "https://pingcap.com/docs/v2.0/sql/information-functions/", "title": "Information Functions", "content": " Information Functions In TiDB, the usage of information functions is similar to MySQL. For more information, see Information Functions.Information function descriptions Name Description CONNECTION_ID() Return the connection ID (thread ID) for the connection CURRENT_USER(), CURRENT_USER Return the authenticated user name and host name DATABASE() Return the default (current) database name FOUND_ROWS() For a SELECT with a LIMIT clause, the number of the rows that are returned if there is no LIMIT clause LAST_INSERT_ID() Return the value of the AUTOINCREMENT column for the last INSERT SCHEMA() Synonym for DATABASE() SESSION_USER() Synonym for USER() SYSTEM_USER() Synonym for USER() USER() Return the user name and host name provided by the client VERSION() Return a string that indicates the MySQL server version TIDB_VERSION Return a string that indicates the TiDB server version "}, {"url": "https://pingcap.com/recruit-cn/campus/campus-2019-infrastructure-engineer/", "title": "Infrastructure Engineer", "content": " Infrastructure Engineer 职位描述:如果你: 内心不安,喜欢挑战和创新; 熟悉分布式系统,大数据或者数据库领域; 想和简单有爱的 PingCAP 的工程师们一起做世界级的开源项目。 那么你就是我们要找的人。在分布式数据库领域有很多迷人的问题需要去解决,如果你对任何一个问题感到无比的好奇,想要深挖究竟,都可以来和我们聊聊。 想深入理解业界最前沿的分布式数据库 Spanner 的设计和思考,如何从 0 到 1 落地实现; 如何设计和实现世界前沿的分布式 SQL 优化器,让一个复杂的 SQL 查询变的无比轻快智能; 如何在成千上万台集群规模的情况下,实现无阻塞的表结构变更操作,而不影响任何在线的业务; 如何实现一个高效的分布式事务管理器,让 ACID 事务在大规模并发的分布式存场景下依然可以高效可靠; 如何基于一致性的 Raft 协议实现快速稳定的数据复制和自动故障恢复,确保数据安全; 如何在一个 PR 提交之后,快速验证千万级别的 tests 是否全部通过,性能有没有显著提升; …… 待遇:15K - 20K + 期权, 13薪 + 奖金,优秀者可面议联系方式:hire@pingcap.com工作地点:北京,上海,广州,杭州,深圳,成都"}, {"url": "https://pingcap.com/docs/tikv/deploy-tikv-using-ansible/", "title": "Install and Deploy TiKV Using Ansible", "content": " Install and Deploy TiKV Using Ansible This guide describes how to install and deploy TiKV using Ansible. Ansible is an IT automation tool that can configure systems, deploy software, and orchestrate more advanced IT tasks such as continuous deployments or zero downtime rolling updates.TiDB-Ansible is a TiDB cluster deployment tool developed by PingCAP, based on Ansible playbook. TiDB-Ansible enables you to quickly deploy a new TiKV cluster which includes PD, TiKV, and the cluster monitoring modules. Note: For the production environment, it is recommended to use TiDB-Ansible to deploy your TiDB cluster. If you only want to try TiKV out and explore the features, see Install and Deploy TiKV using Docker Compose on a single machine. Prepare Before you start, make sure you have: Several target machines that meet the following requirements: 4 or more machinesA standard TiKV cluster contains 6 machines. You can use 4 machines for testing. CentOS 7.3 (64 bit) or later with Python 2.7 installed, x86_64 architecture (AMD64) Network between machines Note: When you deploy TiKV using Ansible, use SSD disks for the data directory of TiKV and PD nodes. Otherwise, it cannot pass the check. For more details, see Software and Hardware Requirements. A Control Machine that meets the following requirements: Note: The Control Machine can be one of the target machines. CentOS 7.3 (64 bit) or later with Python 2.7 installed Access to the Internet Git installed Step 1: Install system dependencies on the Control Machine Log in to the Control Machine using the root user account, and run the corresponding command according to your operating system. If you use a Control Machine installed with CentOS 7, run the following command:# yum -y install epel-release git curl sshpass # yum -y install python-pip If you use a Control Machine installed with Ubuntu, run the following command:# apt-get -y install git curl sshpass python-pip Step 2: Create the tidb user on the Control Machine and generate the SSH key Make sure you have logged in to the Control Machine using the root user account, and then run the following command. Create the tidb user.# useradd -m -d /home/tidb tidb Set a password for the tidb user account.# passwd tidb Configure sudo without password for the tidb user account by adding tidb ALL=(ALL) NOPASSWD: ALL to the end of the sudo file:# visudo tidb ALL=(ALL) NOPASSWD: ALL Generate the SSH key.Execute the su command to switch the user from root to tidb. Create the SSH key for the tidb user account and hit the Enter key when Enter passphrase is prompted. After successful execution, the SSH private key file is /home/tidb/.ssh/id_rsa, and the SSH public key file is /home/tidb/.ssh/id_rsa.pub.# su - tidb $ ssh-keygen -t rsa Generating public/private rsa key pair. Enter file in which to save the key (/home/tidb/.ssh/id_rsa): Created directory '/home/tidb/.ssh'. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/tidb/.ssh/id_rsa. Your public key has been saved in /home/tidb/.ssh/id_rsa.pub. The key fingerprint is: SHA256:eIBykszR1KyECA/h0d7PRKz4fhAeli7IrVphhte7/So tidb@172.16.10.49 The key's randomart image is: +---[RSA 2048]----+ |=+o+.o. | |o=o+o.oo | | .O.=.= | | . B.B + | |o B * B S | | * + * + | | o + . | | o E+ . | |o ..+o. | +----[SHA256]-----+ Step 3: Download TiDB-Ansible to the Control Machine Log in to the Control Machine using the tidb user account and enter the /home/tidb directory. Download the corresponding TiDB-Ansible version from the TiDB-Ansible project. The default folder name is tidb-ansible. Download the 2.0 GA version:$ git clone -b release-2.0 https://github.com/pingcap/tidb-ansible.git Download the master version:$ git clone https://github.com/pingcap/tidb-ansible.git Note: It is required to download tidb-ansible to the /home/tidb directory using the tidb user account. If you download it to the /root directory, a privilege issue occurs. If you have questions regarding which version to use, email to info@pingcap.com for more information or file an issue. Step 4: Install Ansible and its dependencies on the Control Machine Make sure you have logged in to the Control Machine using the tidb user account.It is required to use pip to install Ansible and its dependencies, otherwise a compatibility issue occurs. Currently, the TiDB 2.0 GA version and the master version are compatible with Ansible 2.4 and Ansible 2.5. Install Ansible and the dependencies on the Control Machine:$ cd /home/tidb/tidb-ansible $ sudo pip install -r ./requirements.txt Ansible and the related dependencies are in the tidb-ansible/requirements.txt file. View the version of Ansible:$ ansible --version ansible 2.5.0 Step 5: Configure the SSH mutual trust and sudo rules on the Control Machine Make sure you have logged in to the Control Machine using the tidb user account. Add the IPs of your target machines to the [servers] section of the hosts.ini file.$ cd /home/tidb/tidb-ansible $ vi hosts.ini [servers] 172.16.10.1 172.16.10.2 172.16.10.3 172.16.10.4 172.16.10.5 172.16.10.6 [all:vars] username = tidb ntp_server = pool.ntp.org Run the following command and input the root user account password of your target machines.$ ansible-playbook -i hosts.ini create_users.yml -u root -k This step creates the tidb user account on the target machines, and configures the sudo rules and the SSH mutual trust between the Control Machine and the target machines. Note: To configure the SSH mutual trust and sudo without password manually, see How to manually configure the SSH mutual trust and sudo without password. Step 6: Install the NTP service on the target machines Note: If the time and time zone of all your target machines are same, the NTP service is on and is normally synchronizing time, you can ignore this step. See How to check whether the NTP service is normal. Make sure you have logged in to the Control Machine using the tidb user account, run the following command:$ cd /home/tidb/tidb-ansible $ ansible-playbook -i hosts.ini deploy_ntp.yml -u tidb -b The NTP service is installed and started using the software repository that comes with the system on the target machines. The default NTP server list in the installation package is used. The related server parameter is in the /etc/ntp.conf configuration file.To make the NTP service start synchronizing as soon as possible, the system executes the ntpdate command to set the local date and time by polling ntp_server in the hosts.ini file. The default server is pool.ntp.org, and you can also replace it with your NTP server.Step 7: Configure the CPUfreq governor mode on the target machine For details about CPUfreq, see the CPUfreq Governor documentation.Set the CPUfreq governor mode to performance to make full use of CPU performance.Check the governor modes supported by the system You can run the cpupower frequency-info --governors command to check the governor modes which the system supports:# cpupower frequency-info --governors analyzing CPU 0: available cpufreq governors: performance powersave Taking the above code for example, the system supports the performance and powersave modes. Note: As the following shows, if it returns “Not Available”, it means that the current system does not support CPUfreq configuration and you can skip this step. # cpupower frequency-info --governors analyzing CPU 0: available cpufreq governors: Not Available Check the current governor mode You can run the cpupower frequency-info --policy command to check the current CPUfreq governor mode:# cpupower frequency-info --policy analyzing CPU 0: current policy: frequency should be within 1.20 GHz and 3.20 GHz. The governor "powersave" may decide which speed to use within this range. As the above code shows, the current mode is powersave in this example.Change the governor mode You can run the following command to change the current mode to performance:# cpupower …"}, {"url": "https://pingcap.com/docs/v2.0/tikv/deploy-tikv-using-ansible/", "title": "Install and Deploy TiKV Using Ansible", "content": " Install and Deploy TiKV Using Ansible This guide describes how to install and deploy TiKV using Ansible. Ansible is an IT automation tool that can configure systems, deploy software, and orchestrate more advanced IT tasks such as continuous deployments or zero downtime rolling updates.TiDB-Ansible is a TiDB cluster deployment tool developed by PingCAP, based on Ansible playbook. TiDB-Ansible enables you to quickly deploy a new TiKV cluster which includes PD, TiKV, and the cluster monitoring modules. Note: For the production environment, it is recommended to use TiDB-Ansible to deploy your TiDB cluster. If you only want to try TiKV out and explore the features, see Install and Deploy TiKV using Docker Compose on a single machine. Prepare Before you start, make sure you have: Several target machines that meet the following requirements: 4 or more machinesA standard TiKV cluster contains 6 machines. You can use 4 machines for testing. CentOS 7.3 (64 bit) or later with Python 2.7 installed, x86_64 architecture (AMD64) Network between machines Note: When you deploy TiKV using Ansible, use SSD disks for the data directory of TiKV and PD nodes. Otherwise, it cannot pass the check. For more details, see Software and Hardware Requirements. A Control Machine that meets the following requirements: Note: The Control Machine can be one of the target machines. CentOS 7.3 (64 bit) or later with Python 2.7 installed Access to the Internet Git installed Step 1: Install system dependencies on the Control Machine Log in to the Control Machine using the root user account, and run the corresponding command according to your operating system. If you use a Control Machine installed with CentOS 7, run the following command:# yum -y install epel-release git curl sshpass # yum -y install python-pip If you use a Control Machine installed with Ubuntu, run the following command:# apt-get -y install git curl sshpass python-pip Step 2: Create the tidb user on the Control Machine and generate the SSH key Make sure you have logged in to the Control Machine using the root user account, and then run the following command. Create the tidb user.# useradd -m -d /home/tidb tidb Set a password for the tidb user account.# passwd tidb Configure sudo without password for the tidb user account by adding tidb ALL=(ALL) NOPASSWD: ALL to the end of the sudo file:# visudo tidb ALL=(ALL) NOPASSWD: ALL Generate the SSH key.Execute the su command to switch the user from root to tidb. Create the SSH key for the tidb user account and hit the Enter key when Enter passphrase is prompted. After successful execution, the SSH private key file is /home/tidb/.ssh/id_rsa, and the SSH public key file is /home/tidb/.ssh/id_rsa.pub.# su - tidb $ ssh-keygen -t rsa Generating public/private rsa key pair. Enter file in which to save the key (/home/tidb/.ssh/id_rsa): Created directory '/home/tidb/.ssh'. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/tidb/.ssh/id_rsa. Your public key has been saved in /home/tidb/.ssh/id_rsa.pub. The key fingerprint is: SHA256:eIBykszR1KyECA/h0d7PRKz4fhAeli7IrVphhte7/So tidb@172.16.10.49 The key's randomart image is: +---[RSA 2048]----+ |=+o+.o. | |o=o+o.oo | | .O.=.= | | . B.B + | |o B * B S | | * + * + | | o + . | | o E+ . | |o ..+o. | +----[SHA256]-----+ Step 3: Download TiDB-Ansible to the Control Machine Log in to the Control Machine using the tidb user account and enter the /home/tidb directory. Download the corresponding TiDB-Ansible version from the TiDB-Ansible project. The default folder name is tidb-ansible. Download the 2.0 GA version:$ git clone -b release-2.0 https://github.com/pingcap/tidb-ansible.git Download the master version:$ git clone https://github.com/pingcap/tidb-ansible.git Note: It is required to download tidb-ansible to the /home/tidb directory using the tidb user account. If you download it to the /root directory, a privilege issue occurs. If you have questions regarding which version to use, email to info@pingcap.com for more information or file an issue. Step 4: Install Ansible and its dependencies on the Control Machine Make sure you have logged in to the Control Machine using the tidb user account.It is required to use pip to install Ansible and its dependencies, otherwise a compatibility issue occurs. Currently, the TiDB 2.0 GA version and the master version are compatible with Ansible 2.4 and Ansible 2.5. Install Ansible and the dependencies on the Control Machine:$ cd /home/tidb/tidb-ansible $ sudo pip install -r ./requirements.txt Ansible and the related dependencies are in the tidb-ansible/requirements.txt file. View the version of Ansible:$ ansible --version ansible 2.5.0 Step 5: Configure the SSH mutual trust and sudo rules on the Control Machine Make sure you have logged in to the Control Machine using the tidb user account. Add the IPs of your target machines to the [servers] section of the hosts.ini file.$ cd /home/tidb/tidb-ansible $ vi hosts.ini [servers] 172.16.10.1 172.16.10.2 172.16.10.3 172.16.10.4 172.16.10.5 172.16.10.6 [all:vars] username = tidb ntp_server = pool.ntp.org Run the following command and input the root user account password of your target machines.$ ansible-playbook -i hosts.ini create_users.yml -u root -k This step creates the tidb user account on the target machines, and configures the sudo rules and the SSH mutual trust between the Control Machine and the target machines. Note: To configure the SSH mutual trust and sudo without password manually, see How to manually configure the SSH mutual trust and sudo without password. Step 6: Install the NTP service on the target machines Note: If the time and time zone of all your target machines are same, the NTP service is on and is normally synchronizing time, you can ignore this step. See How to check whether the NTP service is normal. Make sure you have logged in to the Control Machine using the tidb user account, run the following command:$ cd /home/tidb/tidb-ansible $ ansible-playbook -i hosts.ini deploy_ntp.yml -u tidb -b The NTP service is installed and started using the software repository that comes with the system on the target machines. The default NTP server list in the installation package is used. The related server parameter is in the /etc/ntp.conf configuration file.To make the NTP service start synchronizing as soon as possible, the system executes the ntpdate command to set the local date and time by polling ntp_server in the hosts.ini file. The default server is pool.ntp.org, and you can also replace it with your NTP server.Step 7: Configure the CPUfreq governor mode on the target machine For details about CPUfreq, see the CPUfreq Governor documentation.Set the CPUfreq governor mode to performance to make full use of CPU performance.Check the governor modes supported by the system You can run the cpupower frequency-info --governors command to check the governor modes which the system supports:# cpupower frequency-info --governors analyzing CPU 0: available cpufreq governors: performance powersave Taking the above code for example, the system supports the performance and powersave modes. Note: As the following shows, if it returns “Not Available”, it means that the current system does not support CPUfreq configuration and you can skip this step. # cpupower frequency-info --governors analyzing CPU 0: available cpufreq governors: Not Available Check the current governor mode You can run the cpupower frequency-info --policy command to check the current CPUfreq governor mode:# cpupower frequency-info --policy analyzing CPU 0: current policy: frequency should be within 1.20 GHz and 3.20 GHz. The governor "powersave" may decide which speed to use within this range. As the above code shows, the current mode is powersave in this example.Change the governor mode You can run the following command to change the current mode to performance:# cpupower …"}, {"url": "https://pingcap.com/docs/tikv/deploy-tikv-using-binary/", "title": "Install and Deploy TiKV Using Binary Files", "content": " Install and Deploy TiKV Using Binary Files This guide describes how to deploy a TiKV cluster using binary files. To quickly understand and try TiKV, see Deploy the TiKV cluster on a single machine. To try TiKV out and explore the features, see Deploy the TiKV cluster on multiple nodes for testing. Deploy the TiKV cluster on a single machine This section describes how to deploy TiKV on a single machine installed with the Linux system. Take the following steps: Download the official binary package.# Download the package. wget https://download.pingcap.org/tidb-latest-linux-amd64.tar.gz wget http://download.pingcap.org/tidb-latest-linux-amd64.sha256 # Check the file integrity. If the result is OK, the file is correct. sha256sum -c tidb-latest-linux-amd64.sha256 # Extract the package. tar -xzf tidb-latest-linux-amd64.tar.gz cd tidb-latest-linux-amd64 Start PD../bin/pd-server --name=pd1 --data-dir=pd1 --client-urls="http://127.0.0.1:2379" --peer-urls="http://127.0.0.1:2380" --initial-cluster="pd1=http://127.0.0.1:2380" --log-file=pd1.log Start TiKV.To start the 3 TiKV instances, open a new terminal tab or window, come to the tidb-latest-linux-amd64 directory, and start the instances using the following command:./bin/tikv-server --pd-endpoints="127.0.0.1:2379" --addr="127.0.0.1:20160" --data-dir=tikv1 --log-file=tikv1.log ./bin/tikv-server --pd-endpoints="127.0.0.1:2379" --addr="127.0.0.1:20161" --data-dir=tikv2 --log-file=tikv2.log ./bin/tikv-server --pd-endpoints="127.0.0.1:2379" --addr="127.0.0.1:20162" --data-dir=tikv3 --log-file=tikv3.log You can use the pd-ctl tool to verify whether PD and TiKV are successfully deployed:./bin/pd-ctl store -d -u http://127.0.0.1:2379 If the state of all the TiKV instances is “Up”, you have successfully deployed a TiKV cluster.Deploy the TiKV cluster on multiple nodes for testing This section describes how to deploy TiKV on multiple nodes. If you want to test TiKV with a limited number of nodes, you can use one PD instance to test the entire cluster.Assume that you have four nodes, you can deploy 1 PD instance and 3 TiKV instances. For details, see the following table: Name Host IP Services Node1 192.168.199.113 PD1 Node2 192.168.199.114 TiKV1 Node3 192.168.199.115 TiKV2 Node4 192.168.199.116 TiKV3 To deploy a TiKV cluster with multiple nodes for test, take the following steps: Download the official binary package on each node.# Download the package. wget https://download.pingcap.org/tidb-latest-linux-amd64.tar.gz wget http://download.pingcap.org/tidb-latest-linux-amd64.sha256 # Check the file integrity. If the result is OK, the file is correct. sha256sum -c tidb-latest-linux-amd64.sha256 # Extract the package. tar -xzf tidb-latest-linux-amd64.tar.gz cd tidb-latest-linux-amd64 Start PD on Node1../bin/pd-server --name=pd1 --data-dir=pd1 --client-urls="http://192.168.199.113:2379" --peer-urls="http://192.168.199.113:2380" --initial-cluster="pd1=http://192.168.199.113:2380" --log-file=pd1.log Log in and start TiKV on other nodes: Node2, Node3 and Node4.Node2:./bin/tikv-server --pd-endpoints="192.168.199.113:2379" --addr="192.168.199.114:20160" --data-dir=tikv1 --log-file=tikv1.log Node3:./bin/tikv-server --pd-endpoints="192.168.199.113:2379" --addr="192.168.199.115:20160" --data-dir=tikv2 --log-file=tikv2.log Node4:./bin/tikv-server --pd-endpoints="192.168.199.113:2379" --addr="192.168.199.116:20160" --data-dir=tikv3 --log-file=tikv3.log You can use the pd-ctl tool to verify whether PD and TiKV are successfully deployed:./pd-ctl store -d -u http://192.168.199.113:2379 The result displays the store count and detailed information regarding each store. If the state of all the TiKV instances is “Up”, you have successfully deployed a TiKV cluster."}, {"url": "https://pingcap.com/docs/v2.0/tikv/deploy-tikv-using-binary/", "title": "Install and Deploy TiKV Using Binary Files", "content": " Install and Deploy TiKV Using Binary Files This guide describes how to deploy a TiKV cluster using binary files. To quickly understand and try TiKV, see Deploy the TiKV cluster on a single machine. To try TiKV out and explore the features, see Deploy the TiKV cluster on multiple nodes for testing. Deploy the TiKV cluster on a single machine This section describes how to deploy TiKV on a single machine installed with the Linux system. Take the following steps: Download the official binary package.# Download the package. wget https://download.pingcap.org/tidb-latest-linux-amd64.tar.gz wget http://download.pingcap.org/tidb-latest-linux-amd64.sha256 # Check the file integrity. If the result is OK, the file is correct. sha256sum -c tidb-latest-linux-amd64.sha256 # Extract the package. tar -xzf tidb-latest-linux-amd64.tar.gz cd tidb-latest-linux-amd64 Start PD../bin/pd-server --name=pd1 --data-dir=pd1 --client-urls="http://127.0.0.1:2379" --peer-urls="http://127.0.0.1:2380" --initial-cluster="pd1=http://127.0.0.1:2380" --log-file=pd1.log Start TiKV.To start the 3 TiKV instances, open a new terminal tab or window, come to the tidb-latest-linux-amd64 directory, and start the instances using the following command:./bin/tikv-server --pd-endpoints="127.0.0.1:2379" --addr="127.0.0.1:20160" --data-dir=tikv1 --log-file=tikv1.log ./bin/tikv-server --pd-endpoints="127.0.0.1:2379" --addr="127.0.0.1:20161" --data-dir=tikv2 --log-file=tikv2.log ./bin/tikv-server --pd-endpoints="127.0.0.1:2379" --addr="127.0.0.1:20162" --data-dir=tikv3 --log-file=tikv3.log You can use the pd-ctl tool to verify whether PD and TiKV are successfully deployed:./bin/pd-ctl store -d -u http://127.0.0.1:2379 If the state of all the TiKV instances is “Up”, you have successfully deployed a TiKV cluster.Deploy the TiKV cluster on multiple nodes for testing This section describes how to deploy TiKV on multiple nodes. If you want to test TiKV with a limited number of nodes, you can use one PD instance to test the entire cluster.Assume that you have four nodes, you can deploy 1 PD instance and 3 TiKV instances. For details, see the following table: Name Host IP Services Node1 192.168.199.113 PD1 Node2 192.168.199.114 TiKV1 Node3 192.168.199.115 TiKV2 Node4 192.168.199.116 TiKV3 To deploy a TiKV cluster with multiple nodes for test, take the following steps: Download the official binary package on each node.# Download the package. wget https://download.pingcap.org/tidb-latest-linux-amd64.tar.gz wget http://download.pingcap.org/tidb-latest-linux-amd64.sha256 # Check the file integrity. If the result is OK, the file is correct. sha256sum -c tidb-latest-linux-amd64.sha256 # Extract the package. tar -xzf tidb-latest-linux-amd64.tar.gz cd tidb-latest-linux-amd64 Start PD on Node1../bin/pd-server --name=pd1 --data-dir=pd1 --client-urls="http://192.168.199.113:2379" --peer-urls="http://192.168.199.113:2380" --initial-cluster="pd1=http://192.168.199.113:2380" --log-file=pd1.log Log in and start TiKV on other nodes: Node2, Node3 and Node4.Node2:./bin/tikv-server --pd-endpoints="192.168.199.113:2379" --addr="192.168.199.114:20160" --data-dir=tikv1 --log-file=tikv1.log Node3:./bin/tikv-server --pd-endpoints="192.168.199.113:2379" --addr="192.168.199.115:20160" --data-dir=tikv2 --log-file=tikv2.log Node4:./bin/tikv-server --pd-endpoints="192.168.199.113:2379" --addr="192.168.199.116:20160" --data-dir=tikv3 --log-file=tikv3.log You can use the pd-ctl tool to verify whether PD and TiKV are successfully deployed:./pd-ctl store -d -u http://192.168.199.113:2379 The result displays the store count and detailed information regarding each store. If the state of all the TiKV instances is “Up”, you have successfully deployed a TiKV cluster."}, {"url": "https://pingcap.com/docs/tikv/deploy-tikv-using-docker/", "title": "Install and Deploy TiKV Using Docker", "content": " Install and Deploy TiKV Using Docker This guide describes how to deploy a multi-node TiKV cluster using Docker.Prerequisites Make sure that Docker is installed on each machine.For more details about prerequisites, see Hardware and Software Requirements.Deploy the TiKV cluster on multiple nodes Assume that you have 6 machines with the following details: Name Host IP Services Data Path Node1 192.168.1.101 PD1 /data Node2 192.168.1.102 PD2 /data Node3 192.168.1.103 PD3 /data Node4 192.168.1.104 TiKV1 /data Node5 192.168.1.105 TiKV2 /data Node6 192.168.1.106 TiKV3 /data If you want to test TiKV with a limited number of nodes, you can also use one PD instance to test the entire cluster.Step 1: Pull the latest images of TiKV and PD from Docker Hub Start Docker and pull the latest images of TiKV and PD from Docker Hub using the following command:docker pull pingcap/tikv:latest docker pull pingcap/pd:latest Step 2: Log in and start PD Log in to the three PD machines and start PD respectively: Start PD1 on Node1:docker run -d --name pd1 -p 2379:2379 -p 2380:2380 -v /etc/localtime:/etc/localtime:ro -v /data:/data pingcap/pd:latest --name="pd1" --data-dir="/data/pd1" --client-urls="http://0.0.0.0:2379" --advertise-client-urls="http://192.168.1.101:2379" --peer-urls="http://0.0.0.0:2380" --advertise-peer-urls="http://192.168.1.101:2380" --initial-cluster="pd1=http://192.168.1.101:2380,pd2=http://192.168.1.102:2380,pd3=http://192.168.1.103:2380" Start PD2 on Node2:docker run -d --name pd2 -p 2379:2379 -p 2380:2380 -v /etc/localtime:/etc/localtime:ro -v /data:/data pingcap/pd:latest --name="pd2" --data-dir="/data/pd2" --client-urls="http://0.0.0.0:2379" --advertise-client-urls="http://192.168.1.102:2379" --peer-urls="http://0.0.0.0:2380" --advertise-peer-urls="http://192.168.1.102:2380" --initial-cluster="pd1=http://192.168.1.101:2380,pd2=http://192.168.1.102:2380,pd3=http://192.168.1.103:2380" Start PD3 on Node3:docker run -d --name pd3 -p 2379:2379 -p 2380:2380 -v /etc/localtime:/etc/localtime:ro -v /data:/data pingcap/pd:latest --name="pd3" --data-dir="/data/pd3" --client-urls="http://0.0.0.0:2379" --advertise-client-urls="http://192.168.1.103:2379" --peer-urls="http://0.0.0.0:2380" --advertise-peer-urls="http://192.168.1.103:2380" --initial-cluster="pd1=http://192.168.1.101:2380,pd2=http://192.168.1.102:2380,pd3=http://192.168.1.103:2380" Step 3: Log in and start TiKV Log in to the three TiKV machines and start TiKV respectively: Start TiKV1 on Node4:docker run -d --name tikv1 -p 20160:20160 -v /etc/localtime:/etc/localtime:ro -v /data:/data pingcap/tikv:latest --addr="0.0.0.0:20160" --advertise-addr="192.168.1.104:20160" --data-dir="/data/tikv1" --pd="192.168.1.101:2379,192.168.1.102:2379,192.168.1.103:2379" Start TiKV2 on Node5:docker run -d --name tikv2 -p 20160:20160 -v /etc/localtime:/etc/localtime:ro -v /data:/data pingcap/tikv:latest --addr="0.0.0.0:20160" --advertise-addr="192.168.1.105:20160" --data-dir="/data/tikv2" --pd="192.168.1.101:2379,192.168.1.102:2379,192.168.1.103:2379" Start TiKV3 on Node6:docker run -d --name tikv3 -p 20160:20160 -v /etc/localtime:/etc/localtime:ro -v /data:/data pingcap/tikv:latest --addr="0.0.0.0:20160" --advertise-addr="192.168.1.106:20160" --data-dir="/data/tikv3" --pd="192.168.1.101:2379,192.168.1.102:2379,192.168.1.103:2379" You can check whether the TiKV cluster has been successfully deployed using the following command:curl 192.168.1.101:2379/pd/api/v1/stores If the state of all the TiKV instances is “Up”, you have successfully deployed a TiKV cluster.What’s next? If you want to try the Go client, see Try Two Types of APIs."}, {"url": "https://pingcap.com/docs/v2.0/tikv/deploy-tikv-using-docker/", "title": "Install and Deploy TiKV Using Docker", "content": " Install and Deploy TiKV Using Docker This guide describes how to deploy a multi-node TiKV cluster using Docker.Prerequisites Make sure that Docker is installed on each machine.For more details about prerequisites, see Hardware and Software Requirements.Deploy the TiKV cluster on multiple nodes Assume that you have 6 machines with the following details: Name Host IP Services Data Path Node1 192.168.1.101 PD1 /data Node2 192.168.1.102 PD2 /data Node3 192.168.1.103 PD3 /data Node4 192.168.1.104 TiKV1 /data Node5 192.168.1.105 TiKV2 /data Node6 192.168.1.106 TiKV3 /data If you want to test TiKV with a limited number of nodes, you can also use one PD instance to test the entire cluster.Step 1: Pull the latest images of TiKV and PD from Docker Hub Start Docker and pull the latest images of TiKV and PD from Docker Hub using the following command:docker pull pingcap/tikv:latest docker pull pingcap/pd:latest Step 2: Log in and start PD Log in to the three PD machines and start PD respectively: Start PD1 on Node1:docker run -d --name pd1 -p 2379:2379 -p 2380:2380 -v /etc/localtime:/etc/localtime:ro -v /data:/data pingcap/pd:latest --name="pd1" --data-dir="/data/pd1" --client-urls="http://0.0.0.0:2379" --advertise-client-urls="http://192.168.1.101:2379" --peer-urls="http://0.0.0.0:2380" --advertise-peer-urls="http://192.168.1.101:2380" --initial-cluster="pd1=http://192.168.1.101:2380,pd2=http://192.168.1.102:2380,pd3=http://192.168.1.103:2380" Start PD2 on Node2:docker run -d --name pd2 -p 2379:2379 -p 2380:2380 -v /etc/localtime:/etc/localtime:ro -v /data:/data pingcap/pd:latest --name="pd2" --data-dir="/data/pd2" --client-urls="http://0.0.0.0:2379" --advertise-client-urls="http://192.168.1.102:2379" --peer-urls="http://0.0.0.0:2380" --advertise-peer-urls="http://192.168.1.102:2380" --initial-cluster="pd1=http://192.168.1.101:2380,pd2=http://192.168.1.102:2380,pd3=http://192.168.1.103:2380" Start PD3 on Node3:docker run -d --name pd3 -p 2379:2379 -p 2380:2380 -v /etc/localtime:/etc/localtime:ro -v /data:/data pingcap/pd:latest --name="pd3" --data-dir="/data/pd3" --client-urls="http://0.0.0.0:2379" --advertise-client-urls="http://192.168.1.103:2379" --peer-urls="http://0.0.0.0:2380" --advertise-peer-urls="http://192.168.1.103:2380" --initial-cluster="pd1=http://192.168.1.101:2380,pd2=http://192.168.1.102:2380,pd3=http://192.168.1.103:2380" Step 3: Log in and start TiKV Log in to the three TiKV machines and start TiKV respectively: Start TiKV1 on Node4:docker run -d --name tikv1 -p 20160:20160 -v /etc/localtime:/etc/localtime:ro -v /data:/data pingcap/tikv:latest --addr="0.0.0.0:20160" --advertise-addr="192.168.1.104:20160" --data-dir="/data/tikv1" --pd="192.168.1.101:2379,192.168.1.102:2379,192.168.1.103:2379" Start TiKV2 on Node5:docker run -d --name tikv2 -p 20160:20160 -v /etc/localtime:/etc/localtime:ro -v /data:/data pingcap/tikv:latest --addr="0.0.0.0:20160" --advertise-addr="192.168.1.105:20160" --data-dir="/data/tikv2" --pd="192.168.1.101:2379,192.168.1.102:2379,192.168.1.103:2379" Start TiKV3 on Node6:docker run -d --name tikv3 -p 20160:20160 -v /etc/localtime:/etc/localtime:ro -v /data:/data pingcap/tikv:latest --addr="0.0.0.0:20160" --advertise-addr="192.168.1.106:20160" --data-dir="/data/tikv3" --pd="192.168.1.101:2379,192.168.1.102:2379,192.168.1.103:2379" You can check whether the TiKV cluster has been successfully deployed using the following command:curl 192.168.1.101:2379/pd/api/v1/stores If the state of all the TiKV instances is “Up”, you have successfully deployed a TiKV cluster.What’s next? If you want to try the Go client, see Try Two Types of APIs."}, {"url": "https://pingcap.com/docs/tikv/deploy-tikv-docker-compose/", "title": "Install and Deploy TiKV Using Docker Compose", "content": " Install and Deploy TiKV Using Docker Compose This guide describes how to quickly deploy a TiKV testing cluster using Docker Compose on a single machine. Note: Currently, this installation method only supports the Linux system. Prerequisites Make sure you have installed the following items on your machine: Docker (17.06.0 or later) and Docker Composesudo yum install docker docker-compose Helmcurl https://raw.githubusercontent.com/kubernetes/helm/master/scripts/get | bash Gitsudo yum install git Install and deploy Download tidb-docker-compose.git clone https://github.com/pingcap/tidb-docker-compose.git Edit the compose/values.yaml file to configure networkMode to host.cd tidb-docker-compose vim compose/values.yaml Edit the compose/values.yaml file to comment the TiDB section out. Change the Prometheus and Pushgateway addresses for the host network mode.sed -i 's/pushgateway:9091/127.0.0.1:9091/g' config/* sed -i 's/prometheus:9090/127.0.0.1:9090/g' config/* Generate the generated-docker-compose.yml file.helm template compose > generated-docker-compose.yml Create and start the cluster using the generated-docker-compose.yml file.docker-compose -f generated-docker-compose.yml pull # Get the latest Docker images docker-compose -f generated-docker-compose.yml up -d You can check whether the TiKV cluster has been successfully deployed using the following command:curl localhost:2379/pd/api/v1/stores If the state of all the TiKV instances is “Up”, you have successfully deployed a TiKV cluster.What’s next? If you want to try the Go client, see Try Two Types of APIs."}, {"url": "https://pingcap.com/docs/v2.0/tikv/deploy-tikv-docker-compose/", "title": "Install and Deploy TiKV Using Docker Compose", "content": " Install and Deploy TiKV Using Docker Compose This guide describes how to quickly deploy a TiKV testing cluster using Docker Compose on a single machine. Note: Currently, this installation method only supports the Linux system. Prerequisites Make sure you have installed the following items on your machine: Docker (17.06.0 or later) and Docker Composesudo yum install docker docker-compose Helmcurl https://raw.githubusercontent.com/kubernetes/helm/master/scripts/get | bash Gitsudo yum install git Install and deploy Download tidb-docker-compose.git clone https://github.com/pingcap/tidb-docker-compose.git Edit the compose/values.yaml file to configure networkMode to host and comment the TiDB section out.cd tidb-docker-compose/compose networkMode: host Generate the generated-docker-compose.yml file.helm template compose > generated-docker-compose.yml Create and start the cluster using the generated-docker-compose.yml file.docker-compose -f generated-docker-compose.yml pull # Get the latest Docker images docker-compose -f generated-docker-compose.yml up -d You can check whether the TiKV cluster has been successfully deployed using the following command:curl localhost:2379/pd/api/v1/stores If the state of all the TiKV instances is “Up”, you have successfully deployed a TiKV cluster.What’s next? If you want to try the Go client, see Try Two Types of APIs."}, {"url": "https://pingcap.com/tidb-academy/mysql_dbas/introduction/distributed-databases/", "title": "Introduction to Distributed Databases", "content": " Introduction to Distributed Databases Transcript In introducing TiDB, I want to start by taking a quick tour of databases and answer what TiDB is, and why it exists.Our story begins in the 1960s with the first generation of databases. They were not yet relational, and the query language that was used to access records was closely tied to the storage format. So this meant that there was very little in the way of vendor independence, and changing the storage format (perhaps to add an optimization) necessitated changing how you accessed the data.In the early 1970s, we saw the invention of the relational model and SQL. This invention addressed many of the issues of the earlier systems, and presented an abstraction that was more friendly to developers. Queries were now possible in independent higher level language, and not tied to the physical implementation. While it is important to mention that SQL is a living language and has had many updates to the standard, the origin of many of the relational databases we use today can be traced back to this point.From the 1970s to the early 2000s, SQL-based relational databases dominated. While SQL was “standard”, many of the vendors also offered proprietary stored procedure languages that were highly optimized, but reduced the portability between platforms. While I would be hesitant to call any of these systems slow, many of them were inherently designed to be run on a single server. And since they trace back to the 1970s, this should not be surprising. At the time it was uncommon for a company to have very many computers, let alone dedicated servers just for databases.But the single server design really started to become problematic with the rise of the Internet. The canonical answer to it, at least in the early 2000s was to use sharding + read replicas, often with MySQL as the database. And while I have fond memories of these times personally, I think it is important to clarify that this was not really a feature of the database, but a feature of the application code that knew which was the correct database server to connect to for a particular query. It also relied on the developer carefully planning their table design because cross-shard queries were either extremely difficult or not possible. So in some respects the limits of the 1960s had unfortunately returned. Often a cache was also used such as memcached, which helped alleviate load on the database. But the cache itself was a lookaside cache, and pushed more logic into the application.Around the mid 2000s we saw the introduction of NoSQL databases. And while I want to clarify that NoSQL as a term really covers a broad family of technologies, a common thread between them was addressing the scalability issues of traditional relational databases. By (in many cases) changing the data model slightly, and reducing some of the data consistency guarantees of the system, they were able to scale horizontally by just adding nodes.NoSQL is typically now used to refer to “not only SQL”, since some of these systems do offer query languages that closely resemble SQL anyway. But what I think is important to mention here, is much like sharding where there is complexity that needs to be managed in application code, some of the guarantees that NoSQL databases took away also led to additional application code.I think as an industry we often use banks or money incorrectly as the only system that requires transactions and durability. But consider a hypothetical application that has either user permissions or privacy settings;If I, as a user make a change to my settings and then see a web page come back and say that the changes have been applied, I do not expect that this database activity will be lost because the database crashed 2 seconds later. In ecommerce, a user might place an order and then receive an email confirmation saying that the order was successful. But because the system crashed, the order was lost.So in both cases the scalability needs pushed back responsibility to those that developed and managed the system. Developers now had a choice of which set of trade-offs they were more willing to accept.The next generation of systems that we are now seeing emerge are commonly referred to as NewSQL, in essence SQL-based relational databases with the scalability characteristics of NoSQL. Many of these systems draw inspiration from Google Spanner, which was really amongst the first of the horizontally scalable systems with strong consistency guarantees - a departure from NoSQL.This is the family of systems that TiDB belongs to. TiDB uses a Spanner-inspired architecture and speaks the MySQL network protocol, so applications can connect to it using an existing MySQL connector. While there are some semantics differences in TiDB to make it distributed, for application developers using it, it is much closer to the traditional relational databases spanning back to the 1970s than it is to NoSQL databases.One such change, is that TiDB uses optimistic locking rather than the more traditional pessimistic locking used by InnoDB. Let me show you a quick example of a behavior difference that might surprise you:create table t1 (c1 int); create table t2 (c2 int); create table t3 (c3 int); insert into t1 values(50); insert into t2 values(0); insert into t3 values(0); set autocommit=0; ‘’' transaction 1 ‘’' begin; update t1 set c1 = c1 - 50 where c1 >= 50; ‘’' Success, affected rows is 1 ‘’' update t2 set c2=c2 + 50; commit; // transaction 2 begin; update t1 set c1 = c1 - 10 where c1 >= 10; ' Success, affected rows is 1 !!!!, but notice here, the real affected rows is 0, if client uses affected rows as the successful signature of this transaction, but it’s wrong because tidb will retry this transaction. update t3 set c3 = c3 + 10; commit; This difference is documented in the TiDB manual, but is a good lesson in distributed databases. Due to optimistic locking, the affected rows may differ from MySQL to TiDB and your application should also expect that COMMIT may result in an error.We will have a dedicated section that looks at the compatibility between TiDB and MySQL, but for now let’s continue the introduction to the TiDB Platform."}, {"url": "https://pingcap.com/docs/sql/statistics/", "title": "Introduction to Statistics", "content": " Introduction to Statistics Based on the statistics, the TiDB optimizer chooses the most efficient query execution plan. The statistics collect table-level and column-level information. The statistics of a table include the total number of rows and the number of updated rows. The statistics of a column include the number of different values, the number of NULL, the histogram, and the Count-Min Sketch of the column. Collect statistics Manual collection You can run the ANALYZE statement to collect statistics.Syntax:ANALYZE TABLE TableNameList [WITH NUM BUCKETS] > The statement collects statistics of all the tables in `TableNameList`. > `WITH NUM BUCKETS` specifies the maximum number of buckets in the generated histogram. ANALYZE TABLE TableName INDEX [IndexNameList] [WITH NUM BUCKETS] > The statement collects statistics of the index columns on all `IndexNameList`s in `TableName`. > The statement collects statistics of all index columns when `IndexNameList` is empty. ANALYZE TABLE TableName PARTITION PartitionNameList [WITH NUM BUCKETS] > The statement collects partition statistics of all `PartitionNameList`s in `TableName`. ANALYZE TABLE TableName PARTITION PartitionNameList [IndexNameList] [WITH NUM BUCKETS] > The statement collects index column statistics of the partitions in all `PartitionNameList`s in `TableName`. Automatic update For the INSERT, DELETE, or UPDATE statements, TiDB automatically updates the number of rows and updated rows. TiDB persists this information regularly and the update cycle is 5 * stats-lease. The default value of stats-lease is 3s. If you specify the value as 0, it does not update automatically.Three system variables related to automatic update of statistics are as follows: System Variable Default Value Description tidb_auto_analyze_ratio 0.5 the threshold value of automatic update tidb_auto_analyze_start_time 00:00 +0000 the start time in a day when TiDB can perform automatic update tidb_auto_analyze_end_time 23:59 +0000 the end time in a day when TiDB can perform automatic update When the ratio of the number of modified rows to the total number of rows of tbl in a table is greater than tidb_auto_analyze_ratio, and the current time is between tidb_auto_analyze_start_time and tidb_auto_analyze_end_time, TiDB executes the ANALYZE TABLE tbl statement in the background to automatically update the statistics of this table.When the query is executed, TiDB collects feedback with the probability of feedback-probability and uses it to update the histogram and Count-Min Sketch. You can modify the value of feedback-probability in the configuration file. The default value is 0.Control ANALYZE concurrency When you run the ANALYZE statement, you can adjust the concurrency using the following parameters, to control its effect on the system.tidb_build_stats_concurrency Currently, when you run the ANALYZE statement, the task is divided into multiple small tasks. Each task only works on one column or index. You can use the tidb_build_stats_concurrency parameter to control the number of simultaneous tasks. The default value is 4.tidb_distsql_scan_concurrency When you analyze regular columns, you can use the tidb_distsql_scan_concurrency parameter to control the number of Region to be read at one time. The default value is 10.tidb_index_serial_scan_concurrency When you analyze index columns, you can use the tidb_index_serial_scan_concurrency parameter to control the number of Region to be read at one time. The default value is 1.View statistics You can view the statistics status using the following statements.Metadata of tables You can use the SHOW STATS_META statement to view the total number of rows and the number of updated rows.Syntax:SHOW STATS_META [ShowLikeOrWhere] > The statement returns the total number of rows and the number of updated rows. You can use `ShowLikeOrWhere` to filter the information you need. Currently, the SHOW STATS_META statement returns the following 6 columns: Syntax Element Description db_name database name table_name table name partition_name partition name update_time the time of the update modify_count the number of modified rows row_count the total number of rows Metadata of columns You can use the SHOW STATS_HISTOGRAMS statement to view the number of different values and the number of NULL in all the columns.Syntax:SHOW STATS_HISTOGRAMS [ShowLikeOrWhere] > The statement returns the number of different values and the number of `NULL` in all the columns. You can use `ShowLikeOrWhere` to filter the information you need. Currently, the SHOW STATS_HISTOGRAMS statement returns the following 8 columns: Syntax Element Description db_name database name table_name table name partition_name partition name column_name column name is_index whether it is an index column or not update_time the time of the update distinct_count the number of different values null_count the number of NULL avg_col_size the average length of columns Buckets of histogram You can use the SHOW STATS_BUCKETS statement to view each bucket of the histogram.Syntax:SHOW STATS_BUCKETS [ShowLikeOrWhere] > The statement returns information about all the buckets. You can use `ShowLikeOrWhere` to filter the information you need. Currently, the SHOW STATS_BUCKETS statement returns the following 10 columns: Syntax Element Description db_name database name table_name table name partition_name partition name column_name column name is_index whether it is an index column or not bucket_id the ID of a bucket count the number of all the values that falls on the bucket and the previous buckets repeats the occurrence number of the maximum value lower_bound the minimum value upper_bound the maximum value Delete statistics You can run the DROP STATS statement to delete statistics.Syntax:DROP STATS TableName > The statement deletes statistics of all the tables in `TableName`. Import and export statistics Export statistics The interface to export statistics:http://${tidb-server-ip}:${tidb-server-status-port}/stats/dump/${db_name}/${table_name} > Use this interface to obtain the JSON format statistics of the `${table_name}` table in the `${db_name}` database. Import statistics Generally, the imported statistics refer to the JSON file obtained using the export interface.Syntax:LOAD STATS 'file_name' > `file_name` is the file name of the statistics to be imported."}, {"url": "https://pingcap.com/docs/v1.0/sql/statistics/", "title": "Introduction to Statistics", "content": " Introduction to Statistics Based on the statistics, the TiDB optimizer chooses the most efficient query execution plan. The statistics collect table-level and column-level information. The statistics of a table include the total number of rows and the number of updated rows. The statistics of a column include the number of different values, the number of NULL, and the histogram of the column.Collect statistics Manual collection You can run the ANALYZE statement to collect statistics.Syntax:ANALYZE TABLE TableNameList > The statement collects statistics of all the tables in `TableNameList`. ANALYZE TABLE TableName INDEX IndexNameList > The statement collects statistics of the index columns on all `IndexNameList` in `TableName`. Automatic update For the INSERT, DELETE, or UPDATE statements, TiDB automatically updates the number of rows and updated rows. TiDB persists this information regularly and the update cycle is 5 * stats-lease. The default value of stats-lease is 3s. If you specify the value as 0, it does not update automatically.Control ANALYZE concurrency When you run the ANALYZE statement, you can adjust the concurrency using the following parameters, to control its effect on the system.tidb_build_stats_concurrency Currently, when you run the ANALYZE statement, the task is divided into multiple small tasks. Each task only works on one column or index. You can use the tidb_build_stats_concurrency parameter to control the number of simultaneous tasks. The default value is 4.tidb_distsql_scan_concurrency When you analyze regular columns, you can use the tidb_distsql_scan_concurrency parameter to control the number of Region to be read at one time. The default value is 10.tidb_index_serial_scan_concurrency When you analyze index columns, you can use the tidb_index_serial_scan_concurrency parameter to control the number of Region to be read at one time. The default value is 1.View statistics You can view the statistics status using the following statements.Metadata of tables You can use the SHOW STATS_META statement to view the total number of rows and the number of updated rows.Syntax:SHOW STATS_META [ShowLikeOrWhere] > The statement returns the total number of rows and the number of updated rows. You can use `ShowLikeOrWhere` to filter the information you need. Currently, the SHOW STATS_META statement returns the following 5 columns: Syntax Element Description db_name database name table_name table name update_time the time of the update modify_count the number of modified rows row_count the total number of rows Metadata of columns You can use the SHOW STATS_HISTOGRAMS statement to view the number of different values and the number of NULL in all the columns.Syntax:SHOW STATS_HISTOGRAMS [ShowLikeOrWhere] > The statement returns the number of different values and the number of `NULL` in all the columns. You can use `ShowLikeOrWhere` to filter the information you need. Currently, the SHOW STATS_HISTOGRAMS statement returns the following 7 columns: Syntax Element Description db_name database name table_name table name column_name column name is_index whether it is an index column or not update_time the time of the update distinct_count the number of different values null_count the number of NULL Buckets of histogram You can use the SHOW STATS_BUCKETS statement to view each bucket of the histogram.Syntax:SHOW STATS_BUCKETS [ShowLikeOrWhere] > The statement returns information about all the buckets. You can use `ShowLikeOrWhere` to filter the information you need. Currently, the SHOW STATS_BUCKETS statement returns the following 9 columns: Syntax Element Description db_name database name table_name table name column_name column name is_index whether it is an index column or not bucket_id the ID of a bucket count the number of all the values that falls on the bucket and the previous buckets repeats the occurrence number of the maximum value lower_bound the minimum value upper_bound the maximum value Delete statistics You can run the DROP STATS statement to delete statistics.Syntax:DROP STATS TableName > The statement deletes statistics of all the tables in `TableName`。"}, {"url": "https://pingcap.com/docs/v2.0/sql/statistics/", "title": "Introduction to Statistics", "content": " Introduction to Statistics Based on the statistics, the TiDB optimizer chooses the most efficient query execution plan. The statistics collect table-level and column-level information. The statistics of a table include the total number of rows and the number of updated rows. The statistics of a column include the number of different values, the number of NULL, the histogram, and the Count-Min Sketch of the column. Collect statistics Manual collection You can run the ANALYZE statement to collect statistics.Syntax:ANALYZE TABLE TableNameList > The statement collects statistics of all the tables in `TableNameList`. ANALYZE TABLE TableName INDEX [IndexNameList] > The statement collects statistics of the index columns on all `IndexNameList` in `TableName`. > The statement collects statistics of all index columns when `IndexNameList` is empty. Automatic update For the INSERT, DELETE, or UPDATE statements, TiDB automatically updates the number of rows and updated rows. TiDB persists this information regularly and the update cycle is 5 * stats-lease. The default value of stats-lease is 3s. If you specify the value as 0, it does not update automatically.When the ratio of the number of modified rows to the total number of rows is greater than auto-analyze-ratio, TiDB automatically starts the Analyze statement. You can modify the value of auto-analyze-ratio in the configuration file. The default value is 0, which means that this function is not enabled.When the query is executed, TiDB collects feedback with the probability of feedback-probability and uses it to update the histogram and Count-Min Sketch. You can modify the value of feedback-probability in the configuration file. The default value is 0.Control ANALYZE concurrency When you run the ANALYZE statement, you can adjust the concurrency using the following parameters, to control its effect on the system.tidb_build_stats_concurrency Currently, when you run the ANALYZE statement, the task is divided into multiple small tasks. Each task only works on one column or index. You can use the tidb_build_stats_concurrency parameter to control the number of simultaneous tasks. The default value is 4.tidb_distsql_scan_concurrency When you analyze regular columns, you can use the tidb_distsql_scan_concurrency parameter to control the number of Region to be read at one time. The default value is 10.tidb_index_serial_scan_concurrency When you analyze index columns, you can use the tidb_index_serial_scan_concurrency parameter to control the number of Region to be read at one time. The default value is 1.View statistics You can view the statistics status using the following statements.Metadata of tables You can use the SHOW STATS_META statement to view the total number of rows and the number of updated rows.Syntax:SHOW STATS_META [ShowLikeOrWhere] > The statement returns the total number of rows and the number of updated rows. You can use `ShowLikeOrWhere` to filter the information you need. Currently, the SHOW STATS_META statement returns the following 5 columns: Syntax Element Description db_name database name table_name table name update_time the time of the update modify_count the number of modified rows row_count the total number of rows Metadata of columns You can use the SHOW STATS_HISTOGRAMS statement to view the number of different values and the number of NULL in all the columns.Syntax:SHOW STATS_HISTOGRAMS [ShowLikeOrWhere] > The statement returns the number of different values and the number of `NULL` in all the columns. You can use `ShowLikeOrWhere` to filter the information you need. Currently, the SHOW STATS_HISTOGRAMS statement returns the following 7 columns: Syntax Element Description db_name database name table_name table name column_name column name is_index whether it is an index column or not update_time the time of the update distinct_count the number of different values null_count the number of NULL avg_col_size the average length of columns Buckets of histogram You can use the SHOW STATS_BUCKETS statement to view each bucket of the histogram.Syntax:SHOW STATS_BUCKETS [ShowLikeOrWhere] > The statement returns information about all the buckets. You can use `ShowLikeOrWhere` to filter the information you need. Currently, the SHOW STATS_BUCKETS statement returns the following 9 columns: Syntax Element Description db_name database name table_name table name column_name column name is_index whether it is an index column or not bucket_id the ID of a bucket count the number of all the values that falls on the bucket and the previous buckets repeats the occurrence number of the maximum value lower_bound the minimum value upper_bound the maximum value Delete statistics You can run the DROP STATS statement to delete statistics.Syntax:DROP STATS TableName > The statement deletes statistics of all the tables in `TableName`. Import and export statistics Export statistics The interface to export statistics:http://${tidb-server-ip}:${tidb-server-status-port}/stats/dump/${db_name}/${table_name} > Use this interface to obtain the JSON format statistics of the `${table_name}` table in the `${db_name}` database. Import statistics Generally, the imported statistics refer to the JSON file obtained using the export interface.Syntax:LOAD STATS 'file_name' > `file_name` is the file name of the statistics to be imported."}, {"url": "https://pingcap.com/docs/sql/json-functions/", "title": "JSON Functions", "content": " JSON Functions TiDB supports most of the JSON functions that shipped with the GA release of MySQL 5.7. Additional JSON functions were added to MySQL 5.7 after its release, and not all are available in TiDB (see unsupported functions).Functions that create JSON values Function Name and Syntactic Sugar Description JSON_ARRAY([val[, val] …]) Evaluates a (possibly empty) list of values and returns a JSON array containing those values JSON_OBJECT(key, val[, key, val] …) Evaluates a (possibly empty) list of key-value pairs and returns a JSON object containing those pairs Functions that search JSON values Function Name and Syntactic Sugar Description JSON_CONTAINS(target, candidate[, path]) Indicates by returning 1 or 0 whether a given candidate JSON document is contained within a target JSON document JSON_CONTAINS_PATH(json_doc, one_or_all, path[, path] …) Returns 0 or 1 to indicate whether a JSON document contains data at a given path or paths JSON_EXTRACT(json_doc, path[, path] …) Returns data from a JSON document, selected from the parts of the document matched by the path arguments -> Returns the value from a JSON column after the evaluating path; the syntactic sugar of JSON_EXTRACT(doc, path_literal) ->> Returns the value from a JSON column after the evaluating path and unquoting the result; the syntactic sugar of JSON_UNQUOTE(JSON_EXTRACT(doc, path_literal)) JSON_KEYS(json_doc[, path]) Returns the keys from the top-level value of a JSON object as a JSON array, or, if a path argument is given, the top-level keys from the selected path Functions that modify JSON values Function Name and Syntactic Sugar Description JSON_INSERT(json_doc, path, val[, path, val] …) Inserts data into a JSON document and returns the result JSON_MERGE(json_doc, json_doc[, json_doc] …) Merges two or more JSON documents and returns the merged result JSON_REMOVE(json_doc, path[, path] …) Removes data from a JSON document and returns the result JSON_REPLACE(json_doc, path, val[, path, val] …) Replaces existing values in a JSON document and returns the result JSON_SET(json_doc, path, val[, path, val] …) Inserts or updates data in a JSON document and returns the result JSON_UNQUOTE(json_val) Unquotes a JSON value and returns the result as a string Functions that return JSON value attributes Function Name and Syntactic Sugar Description JSON_DEPTH(json_doc) Returns the maximum depth of a JSON document JSON_LENGTH(json_doc[, path]) Returns the length of a JSON document, or, if a path argument is given, the length of the value within the path JSON_TYPE(json_val) Returns a string indicating the type of a JSON value Unsupported functions The following JSON functions are unsupported in TiDB. You can track the progress in adding them in TiDB #7546: JSON_APPEND and its alias JSON_ARRAY_APPEND JSON_ARRAY_INSERT JSON_MERGE_PATCH JSON_MERGE_PRESERVE, use the alias JSON_MERGE instead JSON_PRETTY JSON_QUOTE JSON_SEARCH JSON_STORAGE_SIZE JSON_VALID JSON_ARRAYAGG JSON_OBJECTAGG "}, {"url": "https://pingcap.com/docs/v1.0/sql/json-functions/", "title": "JSON Functions", "content": " JSON Functions Function Name and Syntactic Sugar Description JSON_EXTRACT(json_doc, path[, path] …) Return data from a JSON document, selected from the parts of the document matched by the path arguments JSON_UNQUOTE(json_val) Unquote JSON value and return the result as a utf8mb4 string JSON_TYPE(json_val) Return a utf8mb4 string indicating the type of a JSON value JSON_SET(json_doc, path, val[, path, val] …) Insert or update data in a JSON document and return the result JSON_INSERT(json_doc, path, val[, path, val] …) Insert data into a JSON document and return the result JSON_REPLACE(json_doc, path, val[, path, val] …) Replace existing values in a JSON document and return the result JSON_REMOVE(json_doc, path[, path] …) Remove data from a JSON document and return the result JSON_MERGE(json_doc, json_doc[, json_doc] …) Merge two or more JSON documents and return the merged result JSON_OBJECT(key, val[, key, val] …) Evaluate a (possibly empty) list of key-value pairs and return a JSON object containing those pairs JSON_ARRAY([val[, val] …]) Evaluate a (possibly empty) list of values and return a JSON array containing those values -> Return value from JSON column after evaluating path; the syntactic sugar of JSON_EXTRACT(doc, path_literal) ->> Return value from JSON column after evaluating path and unquoting the result; the syntactic sugar of JSON_UNQUOTE(JSONJSON_EXTRACT(doc, path_literal)) "}, {"url": "https://pingcap.com/docs/v2.0/sql/json-functions/", "title": "JSON Functions", "content": " JSON Functions Function Name and Syntactic Sugar Description JSON_EXTRACT(json_doc, path[, path] …) Return data from a JSON document, selected from the parts of the document matched by the path arguments JSON_UNQUOTE(json_val) Unquote JSON value and return the result as a utf8mb4 string JSON_TYPE(json_val) Return a utf8mb4 string indicating the type of a JSON value JSON_SET(json_doc, path, val[, path, val] …) Insert or update data in a JSON document and return the result JSON_INSERT(json_doc, path, val[, path, val] …) Insert data into a JSON document and return the result JSON_REPLACE(json_doc, path, val[, path, val] …) Replace existing values in a JSON document and return the result JSON_REMOVE(json_doc, path[, path] …) Remove data from a JSON document and return the result JSON_MERGE(json_doc, json_doc[, json_doc] …) Merge two or more JSON documents and return the merged result JSON_OBJECT(key, val[, key, val] …) Evaluate a (possibly empty) list of key-value pairs and return a JSON object containing those pairs JSON_ARRAY([val[, val] …]) Evaluate a (possibly empty) list of values and return a JSON array containing those values -> Return value from JSON column after evaluating path; the syntactic sugar of JSON_EXTRACT(doc, path_literal) ->> Return value from JSON column after evaluating path and unquoting the result; the syntactic sugar of JSON_UNQUOTE(JSONJSON_EXTRACT(doc, path_literal)) "}, {"url": "https://pingcap.com/docs/v1.0/sql/json-functions-generated-column/", "title": "JSON Functions and Generated Column", "content": " JSON Functions and Generated Column About To be compatible with MySQL 5.7 or later and better support the document store, TiDB supports JSON in the latest version. In TiDB, a document is a set of Key-Value pairs, encoded as a JSON object. You can use the JSON datatype in a TiDB table and create indexes for the JSON document fields using generated columns. In this way, you can flexibly deal with the business scenarios with uncertain schema and are no longer limited by the read performance and the lack of support for transactions in traditional document databases.JSON functions The support for JSON in TiDB mainly refers to the user interface of MySQL 5.7. For example, you can create a table that includes a JSON field to store complex information:CREATE TABLE person ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255) NOT NULL, address_info JSON ); When you insert data into a table, you can deal with those data with uncertain schema like this:INSERT INTO person (name, address_info) VALUES ("John", '{"city": "Beijing"}'); You can insert JSON data into the table by inserting a legal JSON string into the column corresponding to the JSON field. TiDB will then parse the text and save it in a more compact and easy-to-access binary form.You can also convert other data type into JSON using CAST:INSERT INTO person (name, address_info) VALUES ("John", CAST('{"city": "Beijing"}' AS JSON)); INSERT INTO person (name, address_info) VALUES ("John", CAST('123' AS JSON)); INSERT INTO person (name, address_info) VALUES ("John", CAST(123 AS JSON)); Now, if you want to query all the users living in Beijing from the table, you can simply use the following SQL statement:SELECT id, name FROM person WHERE JSON_EXTRACT(address_info, '$.city') = 'Beijing'; TiDB supports the JSON_EXTRACT function which is exactly the same as in MySQL. The function is to extract the city field from the address_info document. The second argument is a “path expression” and is used to specify which field to extract. See the following few examples to help you understand the “path expression”:SET @person = '{"name":"John","friends":[{"name":"Forest","age":16},{"name":"Zhang San","gender":"male"}]}'; SELECT JSON_EXTRACT(@person, '$.name'); -- gets "John" SELECT JSON_EXTRACT(@person, '$.friends[0].age'); -- gets 16 SELECT JSON_EXTRACT(@person, '$.friends[1].gender'); -- gets "male" SELECT JSON_EXTRACT(@person, '$.friends[2].name'); -- gets NULL In addition to inserting and querying data, TiDB also supports editing JSON. In general, TiDB currently supports the following JSON functions in MySQL 5.7: JSON_EXTRACT JSON_ARRAY JSON_OBJECT JSON_SET JSON_REPLACE JSON_INSERT JSON_REMOVE JSON_TYPE JSON_UNQUOTE You can get the general use of these functions directly from the function name. These functions in TiDB behave the same as in MySQL 5.7. For more information, see the JSON Functions document of MySQL 5.7. If you are a user of MySQL 5.7, you can migrate to TiDB seamlessly.Currently TiDB does not support all the JSON functions in MySQL 5.7. This is because our preliminary goal is to provide complete support for MySQL X Plugin, which covers the majority of JSON functions used to insert, select, update and delete data. More functions will be supported if necessary.Index JSON using generated column The full table scan is executed when you query a JSON field. When you run the EXPLAIN statement in TiDB, the results show that it is full table scan. Then, can you index the JSON field?First, this type of index is wrong:CREATE TABLE person ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255) NOT NULL, address_info JSON, KEY (address_info) ); This is not because of technical impossibility but because the direct comparison of JSON itself is meaningless. Although we can agree on some comparison rules, such as ARRAY is bigger than all OBJECT, it is useless. Therefore, as what is done in MySQL 5.7, TiDB prohibits the direct creation of index on JSON field, but you can index the fields in the JSON document in the form of generated column:CREATE TABLE person ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255) NOT NULL, address_info JSON, city VARCHAR(64) AS (JSON_EXTRACT(address_info, '$.city')) VIRTUAL, KEY (city) ); In this table, the city column is a generated column. As the name implies, the column is generated by other columns in the table, and cannot be assigned a value when inserted or updated. For generating a column, you can specify it as VIRTUAL to prevent it from being explicitly saved in the record, but by other columns when needed. This is particularly useful when the column is wide and you need to save storage space. With this generated column, you can create an index on it, and it looks the same with other regular columns. In query, you can run the following statements:SELECT name, id FROM person WHERE city = 'Beijing'; In this way, you can create an index. Note: In the JSON document, if the field in the specified path does not exist, the result of JSON_EXTRACT will be NULL. The value of the generated column with index is also NULL. If this is not what you want to see, you can add a NOT NULL constraint on the generated column. In this way, when the value of the city field is NULL after you insert data, it can be detected. Limitations The current limitations of JSON and generated column are as follows: You cannot add the generated column in the storage type of STORED through ALTER TABLE. You cannot create an index on the generated column through ALTER TABLE. The above functions and some other JSON functions are under development."}, {"url": "https://pingcap.com/docs/v2.0/sql/json-functions-generated-column/", "title": "JSON Functions and Generated Column", "content": " JSON Functions and Generated Column About To be compatible with MySQL 5.7 or later and better support the document store, TiDB supports JSON in the latest version. In TiDB, a document is a set of Key-Value pairs, encoded as a JSON object. You can use the JSON datatype in a TiDB table and create indexes for the JSON document fields using generated columns. In this way, you can flexibly deal with the business scenarios with uncertain schema and are no longer limited by the read performance and the lack of support for transactions in traditional document databases.JSON functions The support for JSON in TiDB mainly refers to the user interface of MySQL 5.7. For example, you can create a table that includes a JSON field to store complex information:CREATE TABLE person ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255) NOT NULL, address_info JSON ); When you insert data into a table, you can deal with those data with uncertain schema like this:INSERT INTO person (name, address_info) VALUES ("John", '{"city": "Beijing"}'); You can insert JSON data into the table by inserting a legal JSON string into the column corresponding to the JSON field. TiDB will then parse the text and save it in a more compact and easy-to-access binary form.You can also convert other data type into JSON using CAST:INSERT INTO person (name, address_info) VALUES ("John", CAST('{"city": "Beijing"}' AS JSON)); INSERT INTO person (name, address_info) VALUES ("John", CAST('123' AS JSON)); INSERT INTO person (name, address_info) VALUES ("John", CAST(123 AS JSON)); Now, if you want to query all the users living in Beijing from the table, you can simply use the following SQL statement:SELECT id, name FROM person WHERE JSON_EXTRACT(address_info, '$.city') = 'Beijing'; TiDB supports the JSON_EXTRACT function which is exactly the same as in MySQL. The function is to extract the city field from the address_info document. The second argument is a “path expression” and is used to specify which field to extract. See the following few examples to help you understand the “path expression”:SET @person = '{"name":"John","friends":[{"name":"Forest","age":16},{"name":"Zhang San","gender":"male"}]}'; SELECT JSON_EXTRACT(@person, '$.name'); -- gets "John" SELECT JSON_EXTRACT(@person, '$.friends[0].age'); -- gets 16 SELECT JSON_EXTRACT(@person, '$.friends[1].gender'); -- gets "male" SELECT JSON_EXTRACT(@person, '$.friends[2].name'); -- gets NULL In addition to inserting and querying data, TiDB also supports editing JSON. In general, TiDB currently supports the following JSON functions in MySQL 5.7: JSON_EXTRACT JSON_ARRAY JSON_OBJECT JSON_SET JSON_REPLACE JSON_INSERT JSON_REMOVE JSON_TYPE JSON_UNQUOTE You can get the general use of these functions directly from the function name. These functions in TiDB behave the same as in MySQL 5.7. For more information, see the JSON Functions document of MySQL 5.7. If you are a user of MySQL 5.7, you can migrate to TiDB seamlessly.Currently TiDB does not support all the JSON functions in MySQL 5.7. This is because our preliminary goal is to provide complete support for MySQL X Plugin, which covers the majority of JSON functions used to insert, select, update and delete data. More functions will be supported if necessary.Index JSON using generated column The full table scan is executed when you query a JSON field. When you run the EXPLAIN statement in TiDB, the results show that it is full table scan. Then, can you index the JSON field?First, this type of index is wrong:CREATE TABLE person ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255) NOT NULL, address_info JSON, KEY (address_info) ); This is not because of technical impossibility but because the direct comparison of JSON itself is meaningless. Although we can agree on some comparison rules, such as ARRAY is bigger than all OBJECT, it is useless. Therefore, as what is done in MySQL 5.7, TiDB prohibits the direct creation of index on JSON field, but you can index the fields in the JSON document in the form of generated column:CREATE TABLE person ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255) NOT NULL, address_info JSON, city VARCHAR(64) AS (JSON_UNQUOTE(JSON_EXTRACT(address_info, '$.city'))) VIRTUAL, KEY (city) ); In this table, the city column is a generated column. As the name implies, the column is generated by other columns in the table, and cannot be assigned a value when inserted or updated. For generating a column, you can specify it as VIRTUAL to prevent it from being explicitly saved in the record, but by other columns when needed. This is particularly useful when the column is wide and you need to save storage space. With this generated column, you can create an index on it, and it looks the same with other regular columns. In query, you can run the following statements:SELECT name, id FROM person WHERE city = 'Beijing'; In this way, you can create an index. Note: In the JSON document, if the field in the specified path does not exist, the result of JSON_EXTRACT will be NULL. The value of the generated column with index is also NULL. If this is not what you want to see, you can add a NOT NULL constraint on the generated column. In this way, when the value of the city field is NULL after you insert data, it can be detected. Limitations The current limitations of JSON and generated column are as follows: You cannot add the generated column in the storage type of STORED through ALTER TABLE. You cannot create an index on the generated column through ALTER TABLE. The above functions and some other JSON functions are under development."}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/json-functions-generated-column/", "title": "JSON 函数及 Generated Column", "content": " JSON 函数及 Generated Column 概述 为了在功能上兼容 MySQL 5.7 及以上,同时更好地支持文档类型存储,我们在最新版本的 TiDB 中加入了 JSON 的支持。TiDB 所支持的文档是指以 JSON 为编码类型的键值对的组合。用户可以在 TiDB 的表中使用 JSON 类型的字段,同时以生成列(generated column)的方式为 JSON 文档内部的字段建立索引。基于此,用户可以很灵活地处理那些 schema 不确定的业务,同时不必受限于传统文档数据库糟糕的读性能及匮乏的事务支持。JSON功能介绍 TiDB 的 JSON 主要参考了 MySQL 5.7 的用户接口。例如,可以创建一个表,包含一个 JSON 字段来存储那些复杂的信息:CREATE TABLE person ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255) NOT NULL, address_info JSON ); 当我们向表中插入数据时,便可以这样处理那些模式不确定的数据了:INSERT INTO person (name, address_info) VALUES ("John", '{"city": "Beijing"}'); 就这么简单!直接在 JSON 字段对应的位置上,放一个合法的 JSON 字符串,就可以向表中插入 JSON 了。TiDB 会解析这个文本,然后以一种更加紧凑、易于访问的二进制形式来保存。当然,你也可以将其他类型的数据用 CAST 转换为 JSON:INSERT INTO person (name, address_info) VALUES ("John", CAST('{"city": "Beijing"}' AS JSON)); INSERT INTO person (name, address_info) VALUES ("John", CAST('123' AS JSON)); INSERT INTO person (name, address_info) VALUES ("John", CAST(123 AS JSON)); 现在,如果我们想查询表中所有居住在北京的用户,该怎么做呢?需要把数据全拉回来,然后在业务层进行过滤吗?不需要,和 MongoDB 等文档数据库相同,我们有在服务端支持用户各种复杂组合查询条件的能力。你可以这样写 SQL:SELECT id, name FROM person WHERE JSON_EXTRACT(address_info, '$.city') = 'Beijing'; TiDB 支持 JSON_EXTRACT 函数,该函数与 MySQL 5.7 中 JSON_EXTRACT 的用法完全相同。这个函数的意思就是,从 address_info 这个文档中取出名为 city 这个字段。它的第二个参数是一个“路径表达式”,我们由此可以指定到底要取出哪个字段。关于路径表达式的完整语法描述比较复杂,我们还是通过几个简单的例子来了解其用法:SET @person = '{"name":"John","friends":[{"name":"Forest","age":16},{"name":"Zhang San","gender":"male"}]}'; SELECT JSON_EXTRACT(@person, '$.name'); -- gets "John" SELECT JSON_EXTRACT(@person, '$.friends[0].age'); -- gets 16 SELECT JSON_EXTRACT(@person, '$.friends[1].gender'); -- gets "male" SELECT JSON_EXTRACT(@person, '$.friends[2].name'); -- gets NULL 除了插入、查询外,对 JSON 的修改也是支持的。总的来说,目前我们支持的 MySQL 5.7 的 JSON 函数如下表所示: JSON_EXTRACT JSON_ARRAY JSON_OBJECT JSON_SET JSON_REPLACE JSON_INSERT JSON_REMOVE JSON_TYPE JSON_UNQUOTE 直接从名字上,我们便能得出这些函数的大致用途,而且它们的语义也与 MySQL 5.7 完全一致,因此,想要查询它们具体的用法,我们可以直接查阅 MySQL 5.7 的相关文档。MySQL 5.7 的用户可以无缝迁移至 TiDB。熟悉 MySQL 5.7 的用户会发现,TiDB 尚未完全支持所有 MySQL 5.7 中的 JSON 函数。这是因为我们的一期目标是能够提供完备的 MySQL X Plugin 支持即可,而这已经涵盖大部分常用的 JSON 增删改查的功能了。如有需要,我们会继续完善对其他函数的支持。使用生成列对 JSON 建索引 在有了上述的知识铺垫后,您可能会发现我们在查询 JSON 中的一个字段时,走的是全表扫描。使用 TiDB 的 EXPLAIN 语句时,一个比 MySQL 完备得多的结果会告诉我们,的确是全表扫描。那么,我们能否对 JSON 字段进行索引呢?首先,这种索引是错误的:CREATE TABLE person ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255) NOT NULL, address_info JSON, KEY (address_info) ); 这并非是因为技术上无法支持,而是因为对 JSON 的直接比较,本身就是没有意义的 —— 尽管我们可以人为地约定一些比较规则,比如 ARRAY 比所有的 OBJECT 都大 —— 但是这并没有什么用处。因此,正如 MySQL 5.7 所做的那样,我们禁止了直接在 JSON 字段上创建索引,而是通过生成列的方式,支持了对 JSON 文档内的某一字段建立索引:CREATE TABLE person ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255) NOT NULL, address_info JSON, city VARCHAR(64) AS (JSON_EXTRACT(address_info, '$.city')) VIRTUAL, KEY (city) ); 这个表中,city 列就是一个 生成列。顾名思义,该列由表中其他的列生成,而不能显式地在插入或更新时为它赋一个值。对于生成列,用户还可以指定其为 VIRTUAL 来避免它被显式地保存在记录中,而是在需要地时候再由其他列来生成,这对于列比较宽且需要节约存储空间地情况尤为有用。有了这个生成列,我们就可以在它上面建立索引了,在用户看来与常规的列便没什么两样,是不是很简单呢?而查询的时候,我们可以:SELECT name, id FROM person WHERE city = 'Beijing'; 这样,便可以走索引了!另外,需要注意的是,如果 JSON 文档中指定路径下的字段不存在,那么 JSON_EXTRACT 的结果会是 NULL ,这时,带有索引的生成列的值也就为 NULL 了。因此,如果这是用户不希望看到的,那也可以在生成列上增加 NOT NULL 约束,这样,当插入新的纪录算出来的 city 字段为 NULL 时,便可以检查出来了。目前的一些限制 目前 JSON 及生成列仍然有一些限制: 不能 ALTER TABLE 增加 STORED 存储方式的生成列; 不能 ALTER TABLE 在生成列上增加索引; 这些功能,包括其他一些 JSON 函数的实现尚在开发过程中。"}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/json-functions-generated-column/", "title": "JSON 函数及 Generated Column", "content": " JSON 函数及 Generated Column 概述 为了在功能上兼容 MySQL 5.7 及以上,同时更好地支持文档类型存储,我们在最新版本的 TiDB 中加入了 JSON 的支持。TiDB 所支持的文档是指以 JSON 为编码类型的键值对的组合。用户可以在 TiDB 的表中使用 JSON 类型的字段,同时以生成列(generated column)的方式为 JSON 文档内部的字段建立索引。基于此,用户可以很灵活地处理那些 schema 不确定的业务,同时不必受限于传统文档数据库糟糕的读性能及匮乏的事务支持。JSON功能介绍 TiDB 的 JSON 主要参考了 MySQL 5.7 的用户接口。例如,可以创建一个表,包含一个 JSON 字段来存储那些复杂的信息:CREATE TABLE person ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255) NOT NULL, address_info JSON ); 当我们向表中插入数据时,便可以这样处理那些模式不确定的数据了:INSERT INTO person (name, address_info) VALUES ("John", '{"city": "Beijing"}'); 就这么简单!直接在 JSON 字段对应的位置上,放一个合法的 JSON 字符串,就可以向表中插入 JSON 了。TiDB 会解析这个文本,然后以一种更加紧凑、易于访问的二进制形式来保存。当然,你也可以将其他类型的数据用 CAST 转换为 JSON:INSERT INTO person (name, address_info) VALUES ("John", CAST('{"city": "Beijing"}' AS JSON)); INSERT INTO person (name, address_info) VALUES ("John", CAST('123' AS JSON)); INSERT INTO person (name, address_info) VALUES ("John", CAST(123 AS JSON)); 现在,如果我们想查询表中所有居住在北京的用户,该怎么做呢?需要把数据全拉回来,然后在业务层进行过滤吗?不需要,和 MongoDB 等文档数据库相同,我们有在服务端支持用户各种复杂组合查询条件的能力。你可以这样写 SQL:SELECT id, name FROM person WHERE JSON_EXTRACT(address_info, '$.city') = 'Beijing'; TiDB 支持 JSON_EXTRACT 函数,该函数与 MySQL 5.7 中 JSON_EXTRACT 的用法完全相同。这个函数的意思就是,从 address_info 这个文档中取出名为 city 这个字段。它的第二个参数是一个“路径表达式”,我们由此可以指定到底要取出哪个字段。关于路径表达式的完整语法描述比较复杂,我们还是通过几个简单的例子来了解其用法:SET @person = '{"name":"John","friends":[{"name":"Forest","age":16},{"name":"Zhang San","gender":"male"}]}'; SELECT JSON_EXTRACT(@person, '$.name'); -- gets "John" SELECT JSON_EXTRACT(@person, '$.friends[0].age'); -- gets 16 SELECT JSON_EXTRACT(@person, '$.friends[1].gender'); -- gets "male" SELECT JSON_EXTRACT(@person, '$.friends[2].name'); -- gets NULL 除了插入、查询外,对 JSON 的修改也是支持的。总的来说,目前我们支持的 MySQL 5.7 的 JSON 函数如下表所示: JSON_EXTRACT JSON_ARRAY JSON_OBJECT JSON_SET JSON_REPLACE JSON_INSERT JSON_REMOVE JSON_TYPE JSON_UNQUOTE 直接从名字上,我们便能得出这些函数的大致用途,而且它们的语义也与 MySQL 5.7 完全一致,因此,想要查询它们具体的用法,我们可以直接查阅 MySQL 5.7 的相关文档。MySQL 5.7 的用户可以无缝迁移至 TiDB。熟悉 MySQL 5.7 的用户会发现,TiDB 尚未完全支持所有 MySQL 5.7 中的 JSON 函数。这是因为我们的一期目标是能够提供完备的 MySQL X Plugin 支持即可,而这已经涵盖大部分常用的 JSON 增删改查的功能了。如有需要,我们会继续完善对其他函数的支持。使用生成列对 JSON 建索引 在有了上述的知识铺垫后,您可能会发现我们在查询 JSON 中的一个字段时,走的是全表扫描。使用 TiDB 的 EXPLAIN 语句时,一个比 MySQL 完备得多的结果会告诉我们,的确是全表扫描。那么,我们能否对 JSON 字段进行索引呢?首先,这种索引是错误的:CREATE TABLE person ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255) NOT NULL, address_info JSON, KEY (address_info) ); 这并非是因为技术上无法支持,而是因为对 JSON 的直接比较,本身就是没有意义的 —— 尽管我们可以人为地约定一些比较规则,比如 ARRAY 比所有的 OBJECT 都大 —— 但是这并没有什么用处。因此,正如 MySQL 5.7 所做的那样,我们禁止了直接在 JSON 字段上创建索引,而是通过生成列的方式,支持了对 JSON 文档内的某一字段建立索引:CREATE TABLE person ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255) NOT NULL, address_info JSON, city VARCHAR(64) AS (JSON_UNQUOTE(JSON_EXTRACT(address_info, '$.city'))) VIRTUAL, KEY (city) ); 这个表中,city 列就是一个 生成列。顾名思义,该列由表中其他的列生成,而不能显式地在插入或更新时为它赋一个值。对于生成列,用户还可以指定其为 VIRTUAL 来避免它被显式地保存在记录中,而是在需要地时候再由其他列来生成,这对于列比较宽且需要节约存储空间地情况尤为有用。有了这个生成列,我们就可以在它上面建立索引了,在用户看来与常规的列便没什么两样,是不是很简单呢?而查询的时候,我们可以:SELECT name, id FROM person WHERE city = 'Beijing'; 这样,便可以走索引了!另外,需要注意的是,如果 JSON 文档中指定路径下的字段不存在,那么 JSON_EXTRACT 的结果会是 NULL ,这时,带有索引的生成列的值也就为 NULL 了。因此,如果这是用户不希望看到的,那也可以在生成列上增加 NOT NULL 约束,这样,当插入新的纪录算出来的 city 字段为 NULL 时,便可以检查出来了。目前的一些限制 目前 JSON 及生成列仍然有一些限制: 不能 ALTER TABLE 增加 STORED 存储方式的生成列; 不能 ALTER TABLE 在生成列上增加索引; 这些功能,包括其他一些 JSON 函数的实现尚在开发过程中。"}, {"url": "https://pingcap.com/docs-cn/sql/json-functions/", "title": "JSON 函数及语法糖", "content": " JSON 函数及语法糖 TiDB 支持 MySQL 5.7 GA 版本发布的大多数 JSON 函数。MySQL 5.7 发布后,又增加了更多 JSON 函数,TiDB 并未支持所有这些函数(参见未支持的函数)。创建 JSON 值的函数 函数及语法糖 功能描述 JSON_ARRAY([val[, val] …]) 根据一系列元素创建一个 JSON 文档 JSON_OBJECT(key, val[, key, val] …) 根据一系列 K/V 对创建一个 JSON 文档 搜索 JSON 值的函数 函数及语法糖 功能描述 JSON_CONTAINS(target, candidate[, path]) 通过返回 1 或 0 来表示目标 JSON 文档中是否包含给定的 candidate JSON 文档 JSON_CONTAINS_PATH(json_doc, one_or_all, path[, path] …) 通过返回 0 或 1 来表示一个 JSON 文档在给定路径是否包含数据 JSON_EXTRACT(json_doc, path[, path] …) 从 JSON 文档中解出某一路径对应的子文档 -> 返回执行路径后面的 JSON 列的值;JSON_EXTRACT(doc, path_literal) 的语法糖 ->> 返回执行路径后面的 JSON 列的值和转义后的结果; JSON_UNQUOTE(JSON_EXTRACT(doc, path_literal)) 的语法糖 JSON_KEYS(json_doc[, path]) 返回从 JSON 对象的顶级值作为 JSON array 的键,如果给定了路径参数,则从选定路径中获取顶级键 修改 JSON 值的函数 函数及语法糖 功能描述 JSON_INSERT(json_doc, path, val[, path, val] …) 在 JSON 文档中在某一路径下插入子文档 JSON_MERGE(json_doc, json_doc[, json_doc] …) 将多个 JSON 文档合并成一个文档,其类型为数组 JSON_REMOVE(json_doc, path[, path] …) 移除 JSON 文档中某一路径下的子文档 JSON_REPLACE(json_doc, path, val[, path, val] …) 替换 JSON 文档中的某一路径下的子文档 JSON_SET(json_doc, path, val[, path, val] …) 在 JSON 文档中为某一路径设置子文档 JSON_UNQUOTE(json_val) 去掉 JSON 文档外面的引号 返回 JSON 值属性的函数 函数及语法糖 功能描述 JSON_DEPTH(json_doc) 返回 JSON 文档的最大深度 JSON_LENGTH(json_doc[, path]) 返回 JSON 文档的长度;如果路径参数已定,则返回该路径下值的长度 JSON_TYPE(json_val) 检查某 JSON 文档内部内容的类型 未支持的函数 TiDB 暂未支持以下 JSON 函数。相关进展参见 TiDB #7546: JSON_APPEND 及其别名 JSON_ARRAY_APPEND JSON_ARRAY_INSERT JSON_DEPTH JSON_MERGE_PATCH JSON_MERGE_PRESERVE,使用别名 JSON_MERGE 替代 JSON_PRETTY JSON_QUOTE JSON_SEARCH JSON_STORAGE_SIZE JSON_VALID JSON_ARRAYAGG JSON_OBJECTAGG "}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/json-functions/", "title": "JSON 相关的函数和语法糖", "content": " JSON 相关的函数和语法糖 函数或语法糖 功能描述 JSON_EXTRACT(json_doc, path[, path] …) 从 JSON 文档中解出某一路径对应的子文档 JSON_UNQUOTE(json_val) 去掉 JSON 文档外面的引号 JSON_TYPE(json_val) 检查某 JSON 文档内部内容的类型 JSON_SET(json_doc, path, val[, path, val] …) 在 JSON 文档中为某一路径设置子文档 JSON_INSERT(json_doc, path, val[, path, val] …) 在 JSON 文档中在某一路径下插入子文档 JSON_REPLACE(json_doc, path, val[, path, val] …) 替换 JSON 文档中的某一路径下的子文档 JSON_REMOVE(json_doc, path[, path] …) 移除 JSON 文档中某一路径下的子文档 JSON_MERGE(json_doc, json_doc[, json_doc] …) 将多个 JSON 文档合并成一个文档,其类型为数组 JSON_OBJECT(key, val[, key, val] …) 根据一系列 K/V 对创建一个 JSON 文档 JSON_ARRAY([val[, val] …]) 根据一系列元素创建一个 JSON 文档 -> JSON_EXTRACT(doc, path_literal) 的语法糖 ->> JSON_UNQUOTE(JSONJSON_EXTRACT(doc, path_literal)) 的语法糖 "}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/json-functions/", "title": "JSON 相关的函数和语法糖", "content": " JSON 相关的函数和语法糖 函数或语法糖 功能描述 JSON_EXTRACT(json_doc, path[, path] …) 从 JSON 文档中解出某一路径对应的子文档 JSON_UNQUOTE(json_val) 去掉 JSON 文档外面的引号 JSON_TYPE(json_val) 检查某 JSON 文档内部内容的类型 JSON_SET(json_doc, path, val[, path, val] …) 在 JSON 文档中为某一路径设置子文档 JSON_INSERT(json_doc, path, val[, path, val] …) 在 JSON 文档中在某一路径下插入子文档 JSON_REPLACE(json_doc, path, val[, path, val] …) 替换 JSON 文档中的某一路径下的子文档 JSON_REMOVE(json_doc, path[, path] …) 移除 JSON 文档中某一路径下的子文档 JSON_MERGE(json_doc, json_doc[, json_doc] …) 将多个 JSON 文档合并成一个文档,其类型为数组 JSON_OBJECT(key, val[, key, val] …) 根据一系列 K/V 对创建一个 JSON 文档 JSON_ARRAY([val[, val] …]) 根据一系列元素创建一个 JSON 文档 -> JSON_EXTRACT(doc, path_literal) 的语法糖 ->> JSON_UNQUOTE(JSONJSON_EXTRACT(doc, path_literal)) 的语法糖 "}, {"url": "https://pingcap.com/docs/op-guide/dashboard-overview-info/", "title": "Key Metrics", "content": " Key Metrics If you use Ansible to deploy the TiDB cluster, the monitoring system is deployed at the same time. For more information, see TiDB Monitoring Framework Overview.The Grafana dashboard is divided into a series of sub dashboards which include Overview, PD, TiDB, TiKV, Node_exporter, Disk Performance, and so on. A lot of metrics are there to help you diagnose.For routine operations, you can get an overview of the component (PD, TiDB, TiKV) status and the entire cluster from the Overview dashboard, where the key metrics are displayed. This document provides a detailed description of these key metrics.Key metrics description To understand the key metrics displayed on the Overview dashboard, check the following table: Service Panel Name Description Normal Range Services Port Status Services Online the online nodes number of each service Services Port Status Services Offline the offline nodes number of each service PD Storage Capacity the total storage capacity of the TiDB cluster PD Current Storage Size the occupied storage capacity of the TiDB cluster PD Number of Regions the total number of Regions of the current cluster PD Leader Balance Ratio the leader ratio difference of the nodes with the biggest leader ratio and the smallest leader ratio It is less than 5% for a balanced situation and becomes bigger when you restart a node. PD Region Balance Ratio the Region ratio difference of the nodes with the biggest Region ratio and the smallest Region ratio It is less than 5% for a balanced situation and becomes bigger when you add or remove a node. PD Store Status – Up Stores the number of TiKV nodes that are up PD Store Status – Disconnect Stores the number of TiKV nodes that encounter abnormal communication within a short time PD Store Status – LowSpace Stores the number of TiKV nodes with an available space of less than 80% PD Store Status – Down Stores the number of TiKV nodes that are down The normal value is 0. If the number is bigger than 0, it means some node(s) are abnormal. PD Store Status – Offline Stores the number of TiKV nodes (still providing service) that are being made offline PD Store Status – Tombstone Stores the number of TiKV nodes that are successfully offline PD 99% completed_cmds_duration_seconds the 99th percentile duration to complete a pd-server request less than 5ms PD handle_requests_duration_seconds the request duration of a PD request TiDB Statement OPS the total number of executed SQL statements, including SELECT, INSERT, UPDATE and so on TiDB Duration the execution time of a SQL statement TiDB QPS By Instance the QPS on each TiDB instance TiDB Failed Query OPM the number of failed SQL statements, including syntax error and key conflicts and so on TiDB Connection Count the connection number of each TiDB instance TiDB Heap Memory Usage the size of heap memory used by each TiDB instance TiDB Transaction OPS the number of executed transactions per second TiDB Transaction Duration the execution time of a transaction TiDB KV Cmd OPS the number of executed KV commands TiDB KV Cmd Duration 99 the execution time of the KV command TiDB PD TSO OPS the number of TSO that TiDB obtains from PD TiDB PD TSO Wait Duration the time consumed when TiDB obtains TSO from PD TiDB TiClient Region Error OPS the number of Region related errors returned by TiKV TiDB Lock Resolve OPS the number of transaction related conflicts TiDB Load Schema Duration the time consumed when TiDB obtains Schema from TiKV TiDB KV Backoff OPS the number of errors returned by TiKV (such as transaction conflicts ) TiKV leader the number of leaders on each TiKV node TiKV region the number of Regions on each TiKV node TiKV CPU the CPU usage ratio on each TiKV node TiKV Memory the memory usage on each TiKV node TiKV store size the data amount on each TiKV node TiKV cf size the data amount on different CFs in the cluster TiKV channel full No data points is displayed in normal conditions. If a monitoring value displays, it means the corresponding TiKV node fails to handle the messages TiKV server report failures No data points is displayed in normal conditions. If Unreachable is displayed, it means TiKV encounters a communication issue. TiKV scheduler pending commands the number of commits on queue Occasional value peaks are normal. TiKV coprocessor pending requests the number of requests on queue 0 or very small TiKV coprocessor executor count the number of various query operations TiKV coprocessor request duration the time consumed by TiKV queries TiKV raft store CPU the CPU usage ratio of the raftstore thread Currently, it is a single thread. A value of over 80% indicates that the CPU usage ratio is very high. TiKV Coprocessor CPU the CPU usage ratio of the TiKV query thread, related to the application; complex queries consume a great deal of CPU System Info Vcores the number of CPU cores System Info Memory the total memory System Info CPU Usage the CPU usage ratio, 100% at a maximum System Info Load [1m] the overload within 1 minute System Info Memory Available the size of the available memory System Info Network Traffic the statistics of the network traffic System Info TCP Retrans the statistics about network monitoring and TCP System Info IO Util the disk usage ratio, 100% at a maximum; generally you need to consider adding a new node when the usage ratio is up to 80% ~ 90% Interface of the Overview dashboard "}, {"url": "https://pingcap.com/docs/v1.0/op-guide/dashboard-overview-info/", "title": "Key Metrics", "content": " Key Metrics If you use Ansible to deploy TiDB cluster, you can deploy the monitoring system at the same time. See Overview of the Monitoring Framework for more information.The Grafana dashboard is divided into four sub dashboards: node_export, PD, TiKV, and TiDB. There are a lot of metics there to help you diagnose. For routine operations, some of the key metrics are displayed on the Overview dashboard so that you can get the overview of the status of the components and the entire cluster. See the following section for their descriptions:Key metrics description Service Panel Name Description Normal Range PD Storage Capacity the total storage capacity of the TiDB cluster PD Current Storage Size the occupied storage capacity of the TiDB cluster PD Store Status – up store the number of TiKV nodes that are up PD Store Status – down store the number of TiKV nodes that are down 0. If the number is bigger than 0, it means some node(s) are not down. PD Store Status – offline store the number of TiKV nodes that are manually offline PD Store Status – Tombstone store the number of TiKV nodes that are Tombstone PD Current storage usage the storage occupancy rate of the TiKV cluster If it exceeds 80%, you need to consider adding more TiKV nodes. PD 99% completed cmds duration seconds the 99th percentile duration to complete a pd-server request less than 5ms PD average completed cmds duration seconds the average duration to complete a pd-server request less than 50ms PD leader balance ratio the leader ratio difference of the nodes with the biggest leader ratio and the smallest leader ratio It is less than 5% for a balanced situation. It becomes bigger when a node is restarting. PD region balance ratio the region ratio difference of the nodes with the biggest region ratio and the smallest region ratio It is less than 5% for a balanced situation. It becomes bigger when adding or removing a node. TiDB handle requests duration seconds the response time to get TSO from PD less than 100ms TiDB tidb server QPS the QPS of the cluster application specific TiDB connection count the number of connections from application servers to the database Application specific. If the number of connections hops, you need to find out the reasons. If it drops to 0, you can check if the network is broken; if it surges, you need to check the application. TiDB statement count the number of different types of statement within a given time application specific TiDB Query Duration 99th percentile the 99th percentile query time TiKV 99% & 99.99% scheduler command duration the 99th percentile and 99.99th percentile scheduler command duration For 99%, it is less than 50ms; for 99.99%, it is less than 100ms. TiKV 95% & 99.99% storage async_request duration the 95th percentile and 99.99th percentile Raft command duration For 95%, it is less than 50ms; for 99.99%, it is less than 100ms. TiKV server report failure message There might be an issue with the network or the message might not come from this cluster. If there are large amount of messages which contains unreachable, there might be an issue with the network. If the message contains store not match, the message does not come from this cluster. TiKV Vote the frequency of the Raft vote Usually, the value only changes when there is a split. If the value of Vote remains high for a long time, the system might have a severe issue and some nodes are not working. TiKV 95% and 99% coprocessor request duration the 95th percentile and the 99th percentile coprocessor request duration Application specific. Usually, the value does not remain high. TiKV Pending task the number of pending tasks Except for PD worker, it is not normal if the value is too high. TiKV stall RocksDB stall time If the value is bigger than 0, it means that RocksDB is too busy, and you need to pay attention to IO and CPU usage. TiKV channel full The channel is full and the threads are too busy. If the value is bigger than 0, the threads are too busy. TiKV 95% send message duration seconds the 95th percentile message sending time less than 50ms TiKV leader/region the number of leader/region per TiKV server application specific "}, {"url": "https://pingcap.com/docs/v2.0/op-guide/dashboard-overview-info/", "title": "Key Metrics", "content": " Key Metrics If you use Ansible to deploy the TiDB cluster, the monitoring system is deployed at the same time. For more information, see Overview of the Monitoring Framework .The Grafana dashboard is divided into a series of sub dashboards which include Overview, PD, TiDB, TiKV, Node_exporter, Disk Performance, and so on. A lot of metrics are there to help you diagnose.For routine operations, you can get an overview of the component (PD, TiDB, TiKV) status and the entire cluster from the Overview dashboard, where the key metrics are displayed. This document provides a detailed description of these key metrics.Key metrics description To understand the key metrics displayed on the Overview dashboard, check the following table: Service Panel Name Description Normal Range Services Port Status Services Online the online nodes number of each service Services Port Status Services Offline the offline nodes number of each service PD Storage Capacity the total storage capacity of the TiDB cluster PD Current Storage Size the occupied storage capacity of the TiDB cluster PD Number of Regions the total number of Regions of the current cluster PD Leader Balance Ratio the leader ratio difference of the nodes with the biggest leader ratio and the smallest leader ratio It is less than 5% for a balanced situation and becomes bigger when you restart a node. PD Region Balance Ratio the region ratio difference of the nodes with the biggest Region ratio and the smallest Region ratio It is less than 5% for a balanced situation and becomes bigger when you add or remove a node. PD Store Status – Up Stores the number of TiKV nodes that are up PD Store Status – Disconnect Stores the number of TiKV nodes that encounter abnormal communication within a short time PD Store Status – LowSpace Stores the number of TiKV nodes with an available space of less than 80% PD Store Status – Down Stores the number of TiKV nodes that are down The normal value is 0. If the number is bigger than 0, it means some node(s) are abnormal. PD Store Status – Offline Stores the number of TiKV nodes (still providing service) that are being made offline PD Store Status – Tombstone Stores the number of TiKV nodes that are successfully offline PD 99% completed_cmds_duration_seconds the 99th percentile duration to complete a pd-server request less than 5ms PD handle_requests_duration_seconds the request duration of a PD request TiDB Statement OPS the total number of executed SQL statements, including SELECT, INSERT, UPDATE and so on TiDB Duration the execution time of a SQL statement TiDB QPS By Instance the QPS on each TiDB instance TiDB Failed Query OPM the number of failed SQL statements, including syntax error and key conflicts and so on TiDB Connection Count the connection number of each TiDB instance TiDB Heap Memory Usage the size of heap memory used by each TiDB instance TiDB Transaction OPS the number of executed transactions per second TiDB Transaction Duration the execution time of a transaction TiDB KV Cmd OPS the number of executed KV commands TiDB KV Cmd Duration 99 the execution time of the KV command TiDB PD TSO OPS the number of TSO that TiDB obtains from PD TiDB PD TSO Wait Duration the time consumed when TiDB obtains TSO from PD TiDB TiClient Region Error OPS the number of Region related errors returned by TiKV TiDB Lock Resolve OPS the number of transaction related conflicts TiDB Load Schema Duration the time consumed when TiDB obtains Schema from TiKV TiDB KV Backoff OPS the number of errors returned by TiKV (such as transaction conflicts ) TiKV leader the number of leaders on each TiKV node TiKV region the number of Regions on each TiKV node TiKV CPU the CPU usage ratio on each TiKV node TiKV Memory the memory usage on each TiKV node TiKV store size the data amount on each TiKV node TiKV cf size the data amount on different CFs in the cluster TiKV channel full No data points is displayed in normal conditions. If a monitoring value displays, it means the corresponding TiKV node fails to handle the messages TiKV server report failures No data points is displayed in normal conditions. If Unreachable is displayed, it means TiKV encounters a communication issue. TiKV scheduler pending commands the number of commits on queue Occasional value peaks are normal. TiKV coprocessor pending requests the number of requests on queue 0 or very small TiKV coprocessor executor count the number of various query operations TiKV coprocessor request duration the time consumed by TiKV queries TiKV raft store CPU the CPU usage ratio of the raftstore thread Currently, it is a single thread. A value of over 80% indicates that the CPU usage ratio is very high. TiKV Coprocessor CPU the CPU usage ratio of the TiKV query thread, related to the application; complex queries consume a great deal of CPU System Info Vcores the number of CPU cores System Info Memory the total memory System Info CPU Usage the CPU usage ratio, 100% at a maximum System Info Load [1m] the overload within 1 minute System Info Memory Available the size of the available memory System Info Network Traffic the statistics of the network traffic System Info TCP Retrans the statistics about network monitoring and TCP System Info IO Util the disk usage ratio, 100% at a maximum; generally you need to consider adding a new node when the usage ratio is up to 80% ~ 90% Interface of the Overview dashboard "}, {"url": "https://pingcap.com/docs/op-guide/dashboard-pd-info/", "title": "Key Monitoring Metrics of PD", "content": " Key Monitoring Metrics of PD If you use Ansible to deploy the TiDB cluster, the monitoring system is deployed at the same time. For more information, see Overview of the Monitoring Framework.The Grafana dashboard is divided into a series of sub dashboards which include Overview, PD, TiDB, TiKV, Node_exporter, Disk Performance, and so on. A lot of metrics are there to help you diagnose.You can get an overview of the component PD status from the PD dashboard, where the key metrics are displayed. This document provides a detailed description of these key metrics.Key metrics description To understand the key metrics displayed on the Overview dashboard, check the following table: Service Panel name Description Normal range Cluster PD role It indicates whether the current PD is the leader or a follower. Cluster Storage capacity The total capacity size of the cluster Cluster Current storage size The current storage size of the cluster Cluster Number of Regions The total number of Regions without replicas Cluster Leader balance ratio The leader ratio difference of the instances with the biggest leader ratio and the smallest leader ratio It is less than 5% for a balanced situation and becomes bigger when you restart an instance Cluster Region balance ratio The Region ratio difference of the instances with the biggest Region ratio and the smallest Region ratio It is less than 5% for a balanced situation and becomes bigger when you add or remove an instance Cluster Normal stores The count of healthy stores Cluster Abnormal stores The count of unhealthy stores The normal value is 0. If the number is bigger than 0, it means at least one instance is abnormal. Cluster Current storage usage The current storage size and used ratio of the cluster Cluster Current peer count The current peer count of the cluster Cluster Metadata information It records the cluster ID, the last ID the allocator generated, and the last timestamp TSO generated. Cluster Region label isolation level The number of Regions in different label levels Cluster Region health It records the unusual Regions’ count which may include pending peers, down peers, extra peers, offline peers, missing peers, learner peers or incorrect namespaces The number of pending peers should be less than 100. The missing peers should not be persistently greater than 0. Balance Store capacity The capacity size of each TiKV instance Balance Store available The available capacity size of each TiKV instance Balance Store used The used capacity size of each TiKV instance Balance Size amplification The size amplification, which is equal to Store Region size over Store used capacity size, of each TiKV instance Balance Size available ratio It is equal to Store available capacity size over Store capacity size for each TiKV instance Balance Store leader score The leader score of each TiKV instance Balance Store Region score The Region score of each TiKV instance Balance Store leader size The total leader size of each TiKV instance Balance Store Region size The total Region size of each TiKV instance Balance Store leader count The leader count of each TiKV instance Balance Store Region count The Region count of each TiKV instance HotRegion Hot write Region’s leader distribution The total number of leader Regions under hot write on each TiKV instance HotRegion Hot write Region’s peer distribution The total number of Regions which are not leader under hot write on each TiKV instance HotRegion Hot write Region’s leader written bytes The total bytes of hot write on leader Regions for each TiKV instance HotRegion Hot write Region’s peer written bytes The total bytes of hot write on Regions which are not leader for each TiKV instance HotRegion Hot read Region’s leader distribution The total number of leader Regions under hot read on each TiKV instance HotRegion Hot read Region’s peer distribution The total number of Regions which are not leader under hot read on each TiKV instance HotRegion Hot read Region’s leader read bytes The total bytes of hot read on leader Regions for each TiKV instance HotRegion Hot read Region’s peer read bytes The total bytes of hot read on Regions which are not leader for each TiKV instance Scheduler Scheduler is running The current running schedulers Scheduler Balance leader movement The leader movement details among TiKV instances Scheduler Balance Region movement The Region movement details among TiKV instances Scheduler Balance leader event The count of balance leader events Scheduler Balance Region event The count of balance Region events Scheduler Balance leader scheduler The inner status of balance leader scheduler Scheduler Balance Region scheduler The inner status of balance Region scheduler Scheduler Namespace checker The namespace checker’s status Scheduler Replica checker The replica checker’s status Scheduler Region merge checker The merge checker’s status Operator Schedule operator create The number of different operators that are newly created Operator Schedule operator check The number of different operators that have been checked. It mainly checks if the current step is finished; if yes, it returns the next step to be executed. Operator Schedule operator finish The number of different operators that are finished Operator Schedule operator timeout The number of different operators that are timeout Operator Schedule operator replaced or canceled The number of different operators that are replaced or canceled Operator Schedule operators count by state The number of operators in different status Operator 99% Operator finish duration The time consumed when the operator is finished in .99 Operator 50% Operator finish duration The time consumed when the operator is finished in .50 Operator 99% Operator step duration The time consumed when the operator step is finished in .99 Operator 50% Operator step duration The time consumed when the operator step is finished in .50 gRPC Completed commands rate The rate of completing each kind of gRPC commands gRPC 99% Completed commands duration The time consumed of completing each kind of gRPC commands in .99 etcd Handle transactions count The count of etcd transactions etcd 99% Handle transactions duration The time consumed of handling etcd transactions in .99 etcd 99% WAL fsync duration The time consumed of writing WAL into the persistent storage in .99 The value is less than 1s. etcd 99% Peer round trip time seconds The latency of the network in .99 The value is less than 1s. etcd etcd disk wal fsync rate The rate of writing WAL into the persistent storage etcd Raft term The current term of Raft etcd Raft committed index The last committed index of Raft etcd Raft applied index The last applied index of Raft TiDB Handle requests count The count of TiDB requests TiDB Handle requests duration The time consumed of handling TiDB requests It should be less than 100ms in .99. Heartbeat Region heartbeat report The count of the heartbeats which each TiKV instance reports to PD Heartbeat Region heartbeat report error The count of the heartbeats with the error status Heartbeat Region heartbeat report active The count of the heartbeats with the ok status Heartbeat Region schedule push The count of the corresponding schedule commands which PD sends to each TiKV instance Heartbeat 99% Region heartbeat latency The heartbeat latency of each TiKV instance in .99 PD dashboard interface Cluster Balance HotRegion Scheduler Operator gRPC etcd TiDB Heartbeat "}, {"url": "https://pingcap.com/docs/op-guide/dashboard-tikv-info/", "title": "Key Monitoring Metrics of TiKV", "content": " Key Monitoring Metrics of TiKV If you use Ansible to deploy the TiDB cluster, the monitoring system is deployed at the same time. For more information, see Overview of the Monitoring Framework.The Grafana dashboard is divided into a series of sub dashboards which include Overview, PD, TiDB, TiKV, Node_exporter, Disk Performance, and so on. A lot of metrics are there to help you diagnose.You can get an overview of the component TiKV status from the TiKV dashboard, where the key metrics are displayed. This document provides a detailed description of these key metrics.Key metrics description To understand the key metrics displayed on the Overview dashboard, check the following table: Service Panel name Description Normal range Cluster Store size The storage size of each TiKV instance Cluster Available size The available capacity size of each TiKV instance Cluster Capacity size The capacity size of each TiKV instance Cluster CPU The CPU usage of each TiKV instance Cluster Memory The memory usage of each TiKV instance Cluster IO utilization The I/O utilization of each TiKV instance Cluster MBps The total bytes and keys of read and write on each TiKV instance Cluster QPS The QPS of different kinds of commands in each TiKV instance Cluster Errps The total number of the gRPC message failures Cluster Leader The number of leaders on each TiKV instance Cluster Region The number of Regions on each TiKV instance Errors Server is busy It contains some kinds of events such as write stall, channel full, scheduler busy, and coprocessor full, which will make the TiKV instance unavailable temporarily. Errors Server report failures The total number of reporting failure messages It should be 0 in normal case. Errors Raftstore error The number of different raftstore errors on each TiKV instance Errors Scheduler error The number of different scheduler errors on each TiKV instance Errors Coprocessor error The number of different coprocessor errors on each TiKV instance Errors gRPC message error The number of different gRPC message errors on each TiKV instance Errors Leader drop The count of dropped leader in each TiKV instance Errors Leader missing The count of missing leader in each TiKV instance Server Leader The number of leaders on each TiKV instance Server Region The number of Regions on each TiKV instance Server CF size The total size of each column family Server Store size The storage size of each TiKV instance Server Channel full The total number of channel full errors on each TiKV instance It should be 0 in normal case. Server Server report failures The total number of reporting failure messages Server Region average written keys The average rate of writing keys to Regions on each TiKV instance Server Region average written bytes The average rate of writing bytes to Regions on each TiKV instance Server Active written leaders The number of active leaders on each TiKV instance Server Approximate Region size The approximate Region size Raft IO Apply log duration The time consumed when Raft applies log Raft IO Apply log duration per server The time consumed when Raft applies log on each TiKV instance Raft IO Append log duration The time consumed when Raft appends log Raft IO Append log duration per server The time consumed when Raft appends log on each TiKV instance Raft process Ready handled The count of different ready type of Raft Raft process Process ready duration per server The time consumed when the peer processes ready in Raft It should be less than 2s in .9999. Raft process Process tick duration per server The time consumed when the peer processes tick in Raft Raft process 0.99 Duration of raftstore events The time consumed by raftstore events in .99 Raft message Sent messages per server The number of Raft messages sent by each TiKV instance Raft message Flush messages per server The number of Raft messages flushed by each TiKV instance Raft message Receive messages per server The number of Raft messages received by each TiKV instance Raft message Messages The number of different types of Raft messages that are sent Raft message Vote The total number of vote messages that are sent in Raft Raft message Raft dropped messages The number of different types of Raft messages that are dropped Raft propose Raft proposals per ready The proposal count of all Regions in a mio tick Raft propose Raft read/write proposals The total number of different kinds of proposals Raft propose Raft read proposals per server The number of read proposals which are made by each TiKV instance Raft propose Raft write proposals per server The number of write proposals which are made by each TiKV instance Raft propose Propose wait duration The wait time of each proposal Raft propose Propose wait duration per server The wait time of each proposal in each TiKV instance Raft propose Raft log speed The speed that peers propose log Raft admin Admin proposals The number of admin proposals Raft admin Admin apply The number of the processed apply command Raft admin Check split The number of raftstore split check Raft admin 99.99% Check split duration The time consumed when running split check in .9999 Local reader Local reader requests The number of rejections from the local read thread and The number of total requests Local reader Local read requests duration The wait time of local read requests Local reader Local read requests batch size The batch size of local read requests Storage Storage command total The total count of different kinds of commands received Storage Storage async request error The total number of engine asynchronous request errors Storage Storage async snapshot duration The time consumed by processing asynchronous snapshot requests It should be less than 1s in .99. Storage Storage async write duration The time consumed by processing asynchronous write requests It should be less than 1s in .99. Scheduler Scheduler stage total The total number of commands on each stage There should not be lots of errors in a short time. Scheduler Scheduler priority commands The count of different priority commands Scheduler Scheduler pending commands The count of pending commands on each TiKV instance Scheduler - batch_get Scheduler stage total The total number of commands on each stage in batch_get command There should not be lots of errors in a short time. Scheduler - batch_get Scheduler command duration The time consumed when executing batch_get command It should be less than 1s. Scheduler - batch_get Scheduler latch wait duration The time which is caused by latch wait in batch_get command It should be less than 1s. Scheduler - batch_get Scheduler keys read The count of keys read by a batch_get command Scheduler - batch_get Scheduler keys written The count of keys written by a batch_get command Scheduler - batch_get Scheduler scan details The keys scan details of each CF when executing batch_get command Scheduler - batch_get Scheduler scan details [lock] The keys scan details of lock CF when executing batch_get command Scheduler - batch_get Scheduler scan details [write] The keys scan details of write CF when executing batch_get command Scheduler - batch_get Scheduler scan details [default] The keys scan details of default CF when executing batch_get command Scheduler - cleanup Scheduler stage total The total number of commands on each stage in cleanup command There should not be lots of errors in a short time. Scheduler - cleanup Scheduler command duration The time consumed when executing cleanup command It should be less than 1s. Scheduler - cleanup Scheduler latch wait duration The time which is caused by latch wait in cleanup command It should be less than 1s. Scheduler - cleanup Scheduler keys read The count of keys read by a cleanup command Scheduler - cleanup …"}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/keywords-and-reserved-words/", "title": "Keywords and Reserved Words", "content": " Keywords and Reserved Words 关键字在 SQL 中有特殊的意义, 例如 SELECT, UPDATE, DELETE,在作为表名跟函数名的时候,需要特殊对待,例如作为表名,保留字需要被反引号包住:mysql> CREATE TABLE select (a INT); ERROR 1105 (HY000): line 0 column 19 near " (a INT)" (total length 27) mysql> CREATE TABLE `select` (a INT); Query OK, 0 rows affected (0.09 sec) BEGIN 和 END 是关键字, 但不是保留字,所以不需要反引号:mysql> CREATE TABLE `select` (BEGIN int, END int); Query OK, 0 rows affected (0.09 sec) 有一种特殊情况, 如果使用了限定符 .,那么也不需要用反引号:mysql> CREATE TABLE test.select (BEGIN int, END int); Query OK, 0 rows affected (0.08 sec) 下表列出了在 TiDB 中的关键字跟保留字,保留字用 ® 来标识: ACTION ADD ® ADDDATE ADMIN AFTER ALL ® ALTER ® ALWAYS ANALYZE® AND ® ANY AS ® ASC ® ASCII AUTO_INCREMENT AVG AVG_ROW_LENGTH BEGIN BETWEEN ® BIGINT ® BINARY ® BINLOG BIT BIT_XOR BLOB ® BOOL BOOLEAN BOTH ® BTREE BY ® BYTE CASCADE ® CASE ® CAST CHANGE ® CHAR ® CHARACTER ® CHARSET CHECK ® CHECKSUM COALESCE COLLATE ® COLLATION COLUMN ® COLUMNS COMMENT COMMIT COMMITTED COMPACT COMPRESSED COMPRESSION CONNECTION CONSISTENT CONSTRAINT ® CONVERT ® COUNT CREATE ® CROSS ® CURRENT_DATE ® CURRENT_TIME ® CURRENT_TIMESTAMP ® CURRENT_USER ® CURTIME DATA DATABASE ® DATABASES ® DATE DATE_ADD DATE_SUB DATETIME DAY DAY_HOUR ® DAY_MICROSECOND ® DAY_MINUTE ® DAY_SECOND ® DDL DEALLOCATE DEC DECIMAL ® DEFAULT ® DELAY_KEY_WRITE DELAYED ® DELETE ® DESC ® DESCRIBE ® DISABLE DISTINCT ® DISTINCTROW ® DIV ® DO DOUBLE ® DROP ® DUAL ® DUPLICATE DYNAMIC ELSE ® ENABLE ENCLOSED END ENGINE ENGINES ENUM ESCAPE ESCAPED EVENTS EXCLUSIVE EXECUTE EXISTS EXPLAIN ® EXTRACT FALSE ® FIELDS FIRST FIXED FLOAT ® FLUSH FOR ® FORCE ® FOREIGN ® FORMAT FROM ® FULL FULLTEXT ® FUNCTION GENERATED ® GET_FORMAT GLOBAL GRANT ® GRANTS GROUP ® GROUP_CONCAT HASH HAVING ® HIGH_PRIORITY ® HOUR HOUR_MICROSECOND ® HOUR_MINUTE ® HOUR_SECOND ® IDENTIFIED IF ® IGNORE ® IN ® INDEX ® INDEXES INFILE ® INNER ® INSERT ® INT ® INTEGER ® INTERVAL ® INTO ® IS ® ISOLATION JOBS JOIN ® JSON KEY ® KEY_BLOCK_SIZE KEYS ® KILL ® LEADING ® LEFT ® LESS LEVEL LIKE ® LIMIT ® LINES ® LOAD ® LOCAL LOCALTIME ® LOCALTIMESTAMP ® LOCK ® LONGBLOB ® LONGTEXT ® LOW_PRIORITY ® MAX MAX_ROWS MAXVALUE ® MEDIUMBLOB ® MEDIUMINT ® MEDIUMTEXT ® MICROSECOND MIN MIN_ROWS MINUTE MINUTE_MICROSECOND ® MINUTE_SECOND ® MIN MIN_ROWS MINUTE MINUTE_MICROSECOND MINUTE_SECOND MOD ® MODE MODIRY MONTH NAMES NATIONAL NATURAL ® NO NO_WRITE_TO_BINLOG ® NONE NOT ® NOW NULL ® NUMERIC ® NVARCHAR ® OFFSET ON ® ONLY OPTION ® OR ® ORDER ® OUTER ® PARTITION ® PARTITIONS PASSWORD PLUGINS POSITION PRECISION ® PREPARE PRIMARY ® PRIVILEGES PROCEDURE ® PROCESS PROCESSLIST QUARTER QUERY QUICK RANGE ® READ ® REAL ® REDUNDANT REFERENCES ® REGEXP ® RENAME ® REPEAT ® REPEATABLE REPLACE ® RESTRICT ® REVERSE REVOKE ® RIGHT ® RLIKE ® ROLLBACK ROW ROW_COUNT ROW_FORMAT SCHEMA SCHEMAS SECOND SECOND_MICROSECOND ® SELECT ® SERIALIZABLE SESSION SET ® SHARE SHARED SHOW ® SIGNED SMALLINT ® SNAPSHOT SOME SQL_CACHE SQL_CALC_FOUND_ROWS ® SQL_NO_CACHE START STARTING ® STATS STATS_BUCKETS STATS_HISTOGRAMS STATS_META STATS_PERSISTENT STATUS STORED ® SUBDATE SUBSTR SUBSTRING SUM SUPER TABLE ® TABLES TERMINATED ® TEXT THAN THEN ® TIDB TIDB_INLJ TIDB_SMJ TIME TIMESTAMP TIMESTAMPADD TIMESTAMPDIFF TINYBLOB ® TINYINT ® TINYTEXT ® TO ® TRAILING ® TRANSACTION TRIGGER ® TRIGGERS TRIM TRUE ® TRUNCATE UNCOMMITTED UNION ® UNIQUE ® UNKNOWN UNLOCK ® UNSIGNED ® UPDATE ® USE ® USER USING ® UTC_DATE ® UTC_TIME ® UTC_TIMESTAMP ® VALUE VALUES ® VARBINARY ® VARCHAR ® VARIABLES VIEW VIRTUAL ® WARNINGS WEEK WHEN ® WHERE ® WITH ® WRITE ® XOR ® YEAR YEAR_MONTH ® ZEROFILL ® "}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/keywords-and-reserved-words/", "title": "Keywords and Reserved Words", "content": " Keywords and Reserved Words 关键字在 SQL 中有特殊的意义, 例如 SELECT, UPDATE, DELETE,在作为表名跟函数名的时候,需要特殊对待,例如作为表名,保留字需要被反引号包住:mysql> CREATE TABLE select (a INT); ERROR 1105 (HY000): line 0 column 19 near " (a INT)" (total length 27) mysql> CREATE TABLE `select` (a INT); Query OK, 0 rows affected (0.09 sec) BEGIN 和 END 是关键字, 但不是保留字,所以不需要反引号:mysql> CREATE TABLE `select` (BEGIN int, END int); Query OK, 0 rows affected (0.09 sec) 有一种特殊情况, 如果使用了限定符 .,那么也不需要用反引号:mysql> CREATE TABLE test.select (BEGIN int, END int); Query OK, 0 rows affected (0.08 sec) 下表列出了在 TiDB 中的关键字跟保留字,保留字用 ® 来标识: ACTION ADD ® ADDDATE ADMIN AFTER ALL ® ALTER ® ALWAYS ANALYZE® AND ® ANY AS ® ASC ® ASCII AUTO_INCREMENT AVG AVG_ROW_LENGTH BEGIN BETWEEN ® BIGINT ® BINARY ® BINLOG BIT BIT_XOR BLOB ® BOOL BOOLEAN BOTH ® BTREE BY ® BYTE CASCADE ® CASE ® CAST CHANGE ® CHAR ® CHARACTER ® CHARSET CHECK ® CHECKSUM COALESCE COLLATE ® COLLATION COLUMN ® COLUMNS COMMENT COMMIT COMMITTED COMPACT COMPRESSED COMPRESSION CONNECTION CONSISTENT CONSTRAINT ® CONVERT ® COUNT CREATE ® CROSS ® CURRENT_DATE ® CURRENT_TIME ® CURRENT_TIMESTAMP ® CURRENT_USER ® CURTIME DATA DATABASE ® DATABASES ® DATE DATE_ADD DATE_SUB DATETIME DAY DAY_HOUR ® DAY_MICROSECOND ® DAY_MINUTE ® DAY_SECOND ® DDL DEALLOCATE DEC DECIMAL ® DEFAULT ® DELAY_KEY_WRITE DELAYED ® DELETE ® DESC ® DESCRIBE ® DISABLE DISTINCT ® DISTINCTROW ® DIV ® DO DOUBLE ® DROP ® DUAL ® DUPLICATE DYNAMIC ELSE ® ENABLE ENCLOSED END ENGINE ENGINES ENUM ESCAPE ESCAPED EVENTS EXCLUSIVE EXECUTE EXISTS EXPLAIN ® EXTRACT FALSE ® FIELDS FIRST FIXED FLOAT ® FLUSH FOR ® FORCE ® FOREIGN ® FORMAT FROM ® FULL FULLTEXT ® FUNCTION GENERATED ® GET_FORMAT GLOBAL GRANT ® GRANTS GROUP ® GROUP_CONCAT HASH HAVING ® HIGH_PRIORITY ® HOUR HOUR_MICROSECOND ® HOUR_MINUTE ® HOUR_SECOND ® IDENTIFIED IF ® IGNORE ® IN ® INDEX ® INDEXES INFILE ® INNER ® INSERT ® INT ® INTEGER ® INTERVAL ® INTO ® IS ® ISOLATION JOBS JOIN ® JSON KEY ® KEY_BLOCK_SIZE KEYS ® KILL ® LEADING ® LEFT ® LESS LEVEL LIKE ® LIMIT ® LINES ® LOAD ® LOCAL LOCALTIME ® LOCALTIMESTAMP ® LOCK ® LONGBLOB ® LONGTEXT ® LOW_PRIORITY ® MAX MAX_ROWS MAXVALUE ® MEDIUMBLOB ® MEDIUMINT ® MEDIUMTEXT ® MICROSECOND MIN MIN_ROWS MINUTE MINUTE_MICROSECOND ® MINUTE_SECOND ® MIN MIN_ROWS MINUTE MINUTE_MICROSECOND MINUTE_SECOND MOD ® MODE MODIRY MONTH NAMES NATIONAL NATURAL ® NO NO_WRITE_TO_BINLOG ® NONE NOT ® NOW NULL ® NUMERIC ® NVARCHAR ® OFFSET ON ® ONLY OPTION ® OR ® ORDER ® OUTER ® PARTITION ® PARTITIONS PASSWORD PLUGINS POSITION PRECISION ® PREPARE PRIMARY ® PRIVILEGES PROCEDURE ® PROCESS PROCESSLIST QUARTER QUERY QUICK RANGE ® READ ® REAL ® REDUNDANT REFERENCES ® REGEXP ® RENAME ® REPEAT ® REPEATABLE REPLACE ® RESTRICT ® REVERSE REVOKE ® RIGHT ® RLIKE ® ROLLBACK ROW ROW_COUNT ROW_FORMAT SCHEMA SCHEMAS SECOND SECOND_MICROSECOND ® SELECT ® SERIALIZABLE SESSION SET ® SHARE SHARED SHOW ® SIGNED SMALLINT ® SNAPSHOT SOME SQL_CACHE SQL_CALC_FOUND_ROWS ® SQL_NO_CACHE START STARTING ® STATS STATS_BUCKETS STATS_HISTOGRAMS STATS_META STATS_PERSISTENT STATUS STORED ® SUBDATE SUBSTR SUBSTRING SUM SUPER TABLE ® TABLES TERMINATED ® TEXT THAN THEN ® TIDB TIDB_INLJ TIDB_SMJ TIME TIMESTAMP TIMESTAMPADD TIMESTAMPDIFF TINYBLOB ® TINYINT ® TINYTEXT ® TO ® TRAILING ® TRANSACTION TRIGGER ® TRIGGERS TRIM TRUE ® TRUNCATE UNCOMMITTED UNION ® UNIQUE ® UNKNOWN UNLOCK ® UNSIGNED ® UPDATE ® USE ® USER USING ® UTC_DATE ® UTC_TIME ® UTC_TIMESTAMP ® VALUE VALUES ® VARBINARY ® VARCHAR ® VARIABLES VIEW VIRTUAL ® WARNINGS WEEK WHEN ® WHERE ® WITH ® WRITE ® XOR ® YEAR YEAR_MONTH ® ZEROFILL ® "}, {"url": "https://pingcap.com/docs/sql/keywords-and-reserved-words/", "title": "Keywords and Reserved Words", "content": " Keywords and Reserved Words Keywords are words that have significance in SQL. Certain keywords, such as SELECT, UPDATE, or DELETE, are reserved and require special treatment for use as identifiers such as table and column names. For example, as table names, the reserved words must be quoted with backquotes:mysql> CREATE TABLE select (a INT); ERROR 1105 (HY000): line 0 column 19 near " (a INT)" (total length 27) mysql> CREATE TABLE `select` (a INT); Query OK, 0 rows affected (0.09 sec) The BEGIN and END are keywords but not reserved words, so you do not need to quote them with backquotes:mysql> CREATE TABLE `select` (BEGIN int, END int); Query OK, 0 rows affected (0.09 sec) Exception: A word that follows a period . qualifier does not need to be quoted with backquotes either:mysql> CREATE TABLE test.select (BEGIN int, END int); Query OK, 0 rows affected (0.08 sec) The following table lists the keywords and reserved words in TiDB. The reserved words are labelled with ®. ACTION ADD ® ADDDATE ADMIN AFTER ALL ® ALTER ® ALWAYS ANALYZE® AND ® ANY AS ® ASC ® ASCII AUTO_INCREMENT AVG AVG_ROW_LENGTH BEGIN BETWEEN ® BIGINT ® BINARY ® BINLOG BIT BIT_XOR BLOB ® BOOL BOOLEAN BOTH ® BTREE BY ® BYTE CASCADE ® CASE ® CAST CHANGE ® CHAR ® CHARACTER ® CHARSET CHECK ® CHECKSUM COALESCE COLLATE ® COLLATION COLUMN ® COLUMNS COMMENT COMMIT COMMITTED COMPACT COMPRESSED COMPRESSION CONNECTION CONSISTENT CONSTRAINT ® CONVERT ® COUNT CREATE ® CROSS ® CURRENT_DATE ® CURRENT_TIME ® CURRENT_TIMESTAMP ® CURRENT_USER ® CURTIME DATA DATABASE ® DATABASES ® DATE DATE_ADD DATE_SUB DATETIME DAY DAY_HOUR ® DAY_MICROSECOND ® DAY_MINUTE ® DAY_SECOND ® DDL DEALLOCATE DEC DECIMAL ® DEFAULT ® DELAY_KEY_WRITE DELAYED ® DELETE ® DESC ® DESCRIBE ® DISABLE DISTINCT ® DISTINCTROW ® DIV ® DO DOUBLE ® DROP ® DUAL ® DUPLICATE DYNAMIC ELSE ® ENABLE ENCLOSED END ENGINE ENGINES ENUM ESCAPE ESCAPED EVENTS EXCLUSIVE EXECUTE EXISTS EXPLAIN ® EXTRACT FALSE ® FIELDS FIRST FIXED FLOAT ® FLUSH FOR ® FORCE ® FOREIGN ® FORMAT FROM ® FULL FULLTEXT ® FUNCTION GENERATED ® GET_FORMAT GLOBAL GRANT ® GRANTS GROUP ® GROUP_CONCAT HASH HAVING ® HIGH_PRIORITY ® HOUR HOUR_MICROSECOND ® HOUR_MINUTE ® HOUR_SECOND ® IDENTIFIED IF ® IGNORE ® IN ® INDEX ® INDEXES INFILE ® INNER ® INSERT ® INT ® INTEGER ® INTERVAL ® INTO ® IS ® ISOLATION JOBS JOIN ® JSON KEY ® KEY_BLOCK_SIZE KEYS ® KILL ® LEADING ® LEFT ® LESS LEVEL LIKE ® LIMIT ® LINES ® LOAD ® LOCAL LOCALTIME ® LOCALTIMESTAMP ® LOCK ® LONGBLOB ® LONGTEXT ® LOW_PRIORITY ® MAX MAX_ROWS MAXVALUE ® MEDIUMBLOB ® MEDIUMINT ® MEDIUMTEXT ® MICROSECOND MIN MIN_ROWS MINUTE MINUTE_MICROSECOND ® MINUTE_SECOND ® MIN MIN_ROWS MINUTE MINUTE_MICROSECOND MINUTE_SECOND MOD ® MODE MODIRY MONTH NAMES NATIONAL NATURAL ® NO NO_WRITE_TO_BINLOG ® NONE NOT ® NOW NULL ® NUMERIC ® NVARCHAR ® OFFSET ON ® ONLY OPTION ® OR ® ORDER ® OUTER ® PARTITION ® PARTITIONS PASSWORD PLUGINS POSITION PRECISION ® PREPARE PRIMARY ® PRIVILEGES PROCEDURE ® PROCESS PROCESSLIST QUARTER QUERY QUICK RANGE ® READ ® REAL ® REDUNDANT REFERENCES ® REGEXP ® RENAME ® REPEAT ® REPEATABLE REPLACE ® RESTRICT ® REVERSE REVOKE ® RIGHT ® RLIKE ® ROLLBACK ROW ROW_COUNT ROW_FORMAT SCHEMA SCHEMAS SECOND SECOND_MICROSECOND ® SELECT ® SERIALIZABLE SESSION SET ® SHARE SHARED SHOW ® SIGNED SMALLINT ® SNAPSHOT SOME SQL_CACHE SQL_CALC_FOUND_ROWS ® SQL_NO_CACHE START STARTING ® STATS STATS_BUCKETS STATS_HISTOGRAMS STATS_META STATS_PERSISTENT STATUS STORED ® SUBDATE SUBSTR SUBSTRING SUM SUPER TABLE ® TABLES TERMINATED ® TEXT THAN THEN ® TIDB TIDB_INLJ TIDB_SMJ TIME TIMESTAMP TIMESTAMPADD TIMESTAMPDIFF TINYBLOB ® TINYINT ® TINYTEXT ® TO ® TRAILING ® TRANSACTION TRIGGER ® TRIGGERS TRIM TRUE ® TRUNCATE UNCOMMITTED UNION ® UNIQUE ® UNKNOWN UNLOCK ® UNSIGNED ® UPDATE ® USE ® USER USING ® UTC_DATE ® UTC_TIME ® UTC_TIMESTAMP ® VALUE VALUES ® VARBINARY ® VARCHAR ® VARIABLES VIEW VIRTUAL ® WARNINGS WEEK WHEN ® WHERE ® WITH ® WRITE ® XOR ® YEAR YEAR_MONTH ® ZEROFILL ® "}, {"url": "https://pingcap.com/docs/v1.0/sql/keywords-and-reserved-words/", "title": "Keywords and Reserved Words", "content": " Keywords and Reserved Words Keywords are words that have significance in SQL. Certain keywords, such as SELECT, UPDATE, or DELETE, are reserved and require special treatment for use as identifiers such as table and column names. For example, as table names, the reserved words must be quoted with backquotes:mysql> CREATE TABLE select (a INT); ERROR 1105 (HY000): line 0 column 19 near " (a INT)" (total length 27) mysql> CREATE TABLE `select` (a INT); Query OK, 0 rows affected (0.09 sec) The BEGIN and END are keywords but not reserved words, so you do not need to quote them with backquotes:mysql> CREATE TABLE `select` (BEGIN int, END int); Query OK, 0 rows affected (0.09 sec) Exception: A word that follows a period . qualifier does not need to be quoted with backquotes either:mysql> CREATE TABLE test.select (BEGIN int, END int); Query OK, 0 rows affected (0.08 sec) The following table lists the keywords and reserved words in TiDB. The reserved words are labelled with ®. ACTION ADD ® ADDDATE ADMIN AFTER ALL ® ALTER ® ALWAYS ANALYZE® AND ® ANY AS ® ASC ® ASCII AUTO_INCREMENT AVG AVG_ROW_LENGTH BEGIN BETWEEN ® BIGINT ® BINARY ® BINLOG BIT BIT_XOR BLOB ® BOOL BOOLEAN BOTH ® BTREE BY ® BYTE CASCADE ® CASE ® CAST CHANGE ® CHAR ® CHARACTER ® CHARSET CHECK ® CHECKSUM COALESCE COLLATE ® COLLATION COLUMN ® COLUMNS COMMENT COMMIT COMMITTED COMPACT COMPRESSED COMPRESSION CONNECTION CONSISTENT CONSTRAINT ® CONVERT ® COUNT CREATE ® CROSS ® CURRENT_DATE ® CURRENT_TIME ® CURRENT_TIMESTAMP ® CURRENT_USER ® CURTIME DATA DATABASE ® DATABASES ® DATE DATE_ADD DATE_SUB DATETIME DAY DAY_HOUR ® DAY_MICROSECOND ® DAY_MINUTE ® DAY_SECOND ® DDL DEALLOCATE DEC DECIMAL ® DEFAULT ® DELAY_KEY_WRITE DELAYED ® DELETE ® DESC ® DESCRIBE ® DISABLE DISTINCT ® DISTINCTROW ® DIV ® DO DOUBLE ® DROP ® DUAL ® DUPLICATE DYNAMIC ELSE ® ENABLE ENCLOSED END ENGINE ENGINES ENUM ESCAPE ESCAPED EVENTS EXCLUSIVE EXECUTE EXISTS EXPLAIN ® EXTRACT FALSE ® FIELDS FIRST FIXED FLOAT ® FLUSH FOR ® FORCE ® FOREIGN ® FORMAT FROM ® FULL FULLTEXT ® FUNCTION GENERATED ® GET_FORMAT GLOBAL GRANT ® GRANTS GROUP ® GROUP_CONCAT HASH HAVING ® HIGH_PRIORITY ® HOUR HOUR_MICROSECOND ® HOUR_MINUTE ® HOUR_SECOND ® IDENTIFIED IF ® IGNORE ® IN ® INDEX ® INDEXES INFILE ® INNER ® INSERT ® INT ® INTEGER ® INTERVAL ® INTO ® IS ® ISOLATION JOBS JOIN ® JSON KEY ® KEY_BLOCK_SIZE KEYS ® KILL ® LEADING ® LEFT ® LESS LEVEL LIKE ® LIMIT ® LINES ® LOAD ® LOCAL LOCALTIME ® LOCALTIMESTAMP ® LOCK ® LONGBLOB ® LONGTEXT ® LOW_PRIORITY ® MAX MAX_ROWS MAXVALUE ® MEDIUMBLOB ® MEDIUMINT ® MEDIUMTEXT ® MICROSECOND MIN MIN_ROWS MINUTE MINUTE_MICROSECOND ® MINUTE_SECOND ® MIN MIN_ROWS MINUTE MINUTE_MICROSECOND MINUTE_SECOND MOD ® MODE MODIRY MONTH NAMES NATIONAL NATURAL ® NO NO_WRITE_TO_BINLOG ® NONE NOT ® NOW NULL ® NUMERIC ® NVARCHAR ® OFFSET ON ® ONLY OPTION ® OR ® ORDER ® OUTER ® PARTITION ® PARTITIONS PASSWORD PLUGINS POSITION PRECISION ® PREPARE PRIMARY ® PRIVILEGES PROCEDURE ® PROCESS PROCESSLIST QUARTER QUERY QUICK RANGE ® READ ® REAL ® REDUNDANT REFERENCES ® REGEXP ® RENAME ® REPEAT ® REPEATABLE REPLACE ® RESTRICT ® REVERSE REVOKE ® RIGHT ® RLIKE ® ROLLBACK ROW ROW_COUNT ROW_FORMAT SCHEMA SCHEMAS SECOND SECOND_MICROSECOND ® SELECT ® SERIALIZABLE SESSION SET ® SHARE SHARED SHOW ® SIGNED SMALLINT ® SNAPSHOT SOME SQL_CACHE SQL_CALC_FOUND_ROWS ® SQL_NO_CACHE START STARTING ® STATS STATS_BUCKETS STATS_HISTOGRAMS STATS_META STATS_PERSISTENT STATUS STORED ® SUBDATE SUBSTR SUBSTRING SUM SUPER TABLE ® TABLES TERMINATED ® TEXT THAN THEN ® TIDB TIDB_INLJ TIDB_SMJ TIME TIMESTAMP TIMESTAMPADD TIMESTAMPDIFF TINYBLOB ® TINYINT ® TINYTEXT ® TO ® TRAILING ® TRANSACTION TRIGGER ® TRIGGERS TRIM TRUE ® TRUNCATE UNCOMMITTED UNION ® UNIQUE ® UNKNOWN UNLOCK ® UNSIGNED ® UPDATE ® USE ® USER USING ® UTC_DATE ® UTC_TIME ® UTC_TIMESTAMP ® VALUE VALUES ® VARBINARY ® VARCHAR ® VARIABLES VIEW VIRTUAL ® WARNINGS WEEK WHEN ® WHERE ® WITH ® WRITE ® XOR ® YEAR YEAR_MONTH ® ZEROFILL ® "}, {"url": "https://pingcap.com/docs/v2.0/sql/keywords-and-reserved-words/", "title": "Keywords and Reserved Words", "content": " Keywords and Reserved Words Keywords are words that have significance in SQL. Certain keywords, such as SELECT, UPDATE, or DELETE, are reserved and require special treatment for use as identifiers such as table and column names. For example, as table names, the reserved words must be quoted with backquotes:mysql> CREATE TABLE select (a INT); ERROR 1105 (HY000): line 0 column 19 near " (a INT)" (total length 27) mysql> CREATE TABLE `select` (a INT); Query OK, 0 rows affected (0.09 sec) The BEGIN and END are keywords but not reserved words, so you do not need to quote them with backquotes:mysql> CREATE TABLE `select` (BEGIN int, END int); Query OK, 0 rows affected (0.09 sec) Exception: A word that follows a period . qualifier does not need to be quoted with backquotes either:mysql> CREATE TABLE test.select (BEGIN int, END int); Query OK, 0 rows affected (0.08 sec) The following table lists the keywords and reserved words in TiDB. The reserved words are labelled with ®. ACTION ADD ® ADDDATE ADMIN AFTER ALL ® ALTER ® ALWAYS ANALYZE® AND ® ANY AS ® ASC ® ASCII AUTO_INCREMENT AVG AVG_ROW_LENGTH BEGIN BETWEEN ® BIGINT ® BINARY ® BINLOG BIT BIT_XOR BLOB ® BOOL BOOLEAN BOTH ® BTREE BY ® BYTE CASCADE ® CASE ® CAST CHANGE ® CHAR ® CHARACTER ® CHARSET CHECK ® CHECKSUM COALESCE COLLATE ® COLLATION COLUMN ® COLUMNS COMMENT COMMIT COMMITTED COMPACT COMPRESSED COMPRESSION CONNECTION CONSISTENT CONSTRAINT ® CONVERT ® COUNT CREATE ® CROSS ® CURRENT_DATE ® CURRENT_TIME ® CURRENT_TIMESTAMP ® CURRENT_USER ® CURTIME DATA DATABASE ® DATABASES ® DATE DATE_ADD DATE_SUB DATETIME DAY DAY_HOUR ® DAY_MICROSECOND ® DAY_MINUTE ® DAY_SECOND ® DDL DEALLOCATE DEC DECIMAL ® DEFAULT ® DELAY_KEY_WRITE DELAYED ® DELETE ® DESC ® DESCRIBE ® DISABLE DISTINCT ® DISTINCTROW ® DIV ® DO DOUBLE ® DROP ® DUAL ® DUPLICATE DYNAMIC ELSE ® ENABLE ENCLOSED END ENGINE ENGINES ENUM ESCAPE ESCAPED EVENTS EXCLUSIVE EXECUTE EXISTS EXPLAIN ® EXTRACT FALSE ® FIELDS FIRST FIXED FLOAT ® FLUSH FOR ® FORCE ® FOREIGN ® FORMAT FROM ® FULL FULLTEXT ® FUNCTION GENERATED ® GET_FORMAT GLOBAL GRANT ® GRANTS GROUP ® GROUP_CONCAT HASH HAVING ® HIGH_PRIORITY ® HOUR HOUR_MICROSECOND ® HOUR_MINUTE ® HOUR_SECOND ® IDENTIFIED IF ® IGNORE ® IN ® INDEX ® INDEXES INFILE ® INNER ® INSERT ® INT ® INTEGER ® INTERVAL ® INTO ® IS ® ISOLATION JOBS JOIN ® JSON KEY ® KEY_BLOCK_SIZE KEYS ® KILL ® LEADING ® LEFT ® LESS LEVEL LIKE ® LIMIT ® LINES ® LOAD ® LOCAL LOCALTIME ® LOCALTIMESTAMP ® LOCK ® LONGBLOB ® LONGTEXT ® LOW_PRIORITY ® MAX MAX_ROWS MAXVALUE ® MEDIUMBLOB ® MEDIUMINT ® MEDIUMTEXT ® MICROSECOND MIN MIN_ROWS MINUTE MINUTE_MICROSECOND ® MINUTE_SECOND ® MIN MIN_ROWS MINUTE MINUTE_MICROSECOND MINUTE_SECOND MOD ® MODE MODIRY MONTH NAMES NATIONAL NATURAL ® NO NO_WRITE_TO_BINLOG ® NONE NOT ® NOW NULL ® NUMERIC ® NVARCHAR ® OFFSET ON ® ONLY OPTION ® OR ® ORDER ® OUTER ® PARTITION ® PARTITIONS PASSWORD PLUGINS POSITION PRECISION ® PREPARE PRIMARY ® PRIVILEGES PROCEDURE ® PROCESS PROCESSLIST QUARTER QUERY QUICK RANGE ® READ ® REAL ® REDUNDANT REFERENCES ® REGEXP ® RENAME ® REPEAT ® REPEATABLE REPLACE ® RESTRICT ® REVERSE REVOKE ® RIGHT ® RLIKE ® ROLLBACK ROW ROW_COUNT ROW_FORMAT SCHEMA SCHEMAS SECOND SECOND_MICROSECOND ® SELECT ® SERIALIZABLE SESSION SET ® SHARE SHARED SHOW ® SIGNED SMALLINT ® SNAPSHOT SOME SQL_CACHE SQL_CALC_FOUND_ROWS ® SQL_NO_CACHE START STARTING ® STATS STATS_BUCKETS STATS_HISTOGRAMS STATS_META STATS_PERSISTENT STATUS STORED ® SUBDATE SUBSTR SUBSTRING SUM SUPER TABLE ® TABLES TERMINATED ® TEXT THAN THEN ® TIDB TIDB_INLJ TIDB_SMJ TIME TIMESTAMP TIMESTAMPADD TIMESTAMPDIFF TINYBLOB ® TINYINT ® TINYTEXT ® TO ® TRAILING ® TRANSACTION TRIGGER ® TRIGGERS TRIM TRUE ® TRUNCATE UNCOMMITTED UNION ® UNIQUE ® UNKNOWN UNLOCK ® UNSIGNED ® UPDATE ® USE ® USER USING ® UTC_DATE ® UTC_TIME ® UTC_TIMESTAMP ® VALUE VALUES ® VARBINARY ® VARCHAR ® VARIABLES VIEW VIRTUAL ® WARNINGS WEEK WHEN ® WHERE ® WITH ® WRITE ® XOR ® YEAR YEAR_MONTH ® ZEROFILL ® "}, {"url": "https://pingcap.com/tidb-academy/mysql_dbas/query-optimization/lab-recap/", "title": "Lab Recap: Query Optimization", "content": " Lab Recap: Query Optimization "}, {"url": "https://pingcap.com/tidb-academy/mysql_dbas/tidb-overview/lab-recap/", "title": "Lab Recap: TiDB Platform Lab", "content": " Lab Recap: TiDB Platform Lab "}, {"url": "https://pingcap.com/docs/sql/literal-values/", "title": "Literal Values", "content": " Literal Values This document describes String literals, Numeric literals, NULL values, Hexadecimal literals, Date and time literals, Boolean literals, and Bit-value literals.String literals A string is a sequence of bytes or characters, enclosed within either single quote ' or double quote " characters. For example:'example string' "example string" Quoted strings placed next to each other are concatenated to a single string. The following lines are equivalent:'a string' 'a' ' ' 'string' "a" ' ' "string" If the ANSI_QUOTES SQL MODE is enabled, string literals can be quoted only within single quotation marks because a string quoted within double quotation marks is interpreted as an identifier.A binary string is a string of bytes. Each binary string has a character set and collation named binary. A non-binary string is a string of characters. It has a character set other than binary and a collation that is compatible with the character set.For both types of strings, comparisons are based on the numeric values of the string unit. For binary strings, the unit is the byte. For non-binary strings, the unit is the character and some character sets support multibyte characters.A string literal may have an optional character set introducer and COLLATE clause, to designate it as a string that uses a specific character set and collation. TiDB only supports this in syntax, but does not process it.[_charset_name]'string' [COLLATE collation_name] For example:SELECT _latin1'string'; SELECT _binary'string'; SELECT _utf8'string' COLLATE utf8_bin; You can use N’literal’ (or n’literal’) to create a string in the national character set. The following statements are equivalent:SELECT N'some text'; SELECT n'some text'; SELECT _utf8'some text'; Escape characters: 0: An ASCII NUL (X’00’) character ': A single quote (‘) character ": A double quote (“)character b: A backspace character n: A newline (linefeed) character r: A carriage return character t: A tab character z: ASCII 26 (Ctrl + Z) : A backslash character %: A % character _: A _ character You can use the following ways to include quote characters within a string: A ' inside a string quoted with ' may be written as ''. A " inside a string quoted with " may be written as "". Precede the quote character by an escape character . A ' inside a string quoted with " needs no special treatment, and a " inside a string quoted with ' needs no special treatment either. For more information, see String Literals in MySQL.Numeric literals Numeric literals include integer and DECIMAL literals and floating-point literals.Integer may include . as a decimal separator. Numbers may be preceded by - or + to indicate a negative or positive value respectively.Exact-value numeric literals can be represented as 1, .2, 3.4, -5, -6.78, +9.10.Numeric literals can also be represented in scientific notation, such as 1.2E3, 1.2E-3, -1.2E3, -1.2E-3.For more information, see Numeric Literals in MySQL.NULL values The NULL value means “no data”. NULL can be written in any letter case. A synonym is N (case sensitive).Be aware that the NULL value is different from values such as 0 for numeric types or the empty string '' for string types.Hexadecimal literals Hexadecimal literal values are written using X'val' or 0xval notation, where val contains hexadecimal digits. A leading 0x is case sensitive and cannot be written as 0X.Legal hexadecimal literals:X'ac12' X'12AC' x'ac12' x'12AC' 0xac12 0x12AC Illegal hexadecimal literals:X'1z' (z is not a hexadecimal legal digit) 0X12AC (0X must be written as 0x) Hexadecimal literals written using X'val' notation must contain an even number of digits. To avoid the syntax error, pad the value with a leading zero:mysql> select X'aff'; ERROR 1105 (HY000): line 0 column 13 near ""hex literal: invalid hexadecimal format, must even numbers, but 3 (total length 13) mysql> select X'0aff'; +---------+ | X'0aff' | +---------+ | | +---------+ 1 row in set (0.00 sec) By default, a hexadecimal literal is a binary string.To convert a string or a number to a string in hexadecimal format, use the HEX() function:mysql> SELECT HEX('TiDB'); +-------------+ | HEX('TiDB') | +-------------+ | 54694442 | +-------------+ 1 row in set (0.01 sec) mysql> SELECT X'54694442'; +-------------+ | X'54694442' | +-------------+ | TiDB | +-------------+ 1 row in set (0.00 sec) Date and time literals Date and time values can be represented in several formats, such as quoted strings or as numbers. When TiDB expects a date, it interprets any of '2015-07-21', '20150721' and 20150721 as a date.TiDB supports the following formats for date values: As a string in either 'YYYY-MM-DD' or 'YY-MM-DD' format. The - delimiter is “relaxed” in syntax. Any punctuation character may be used as the delimiter between date parts. For example, '2017-08-24', '2017&08&24' and '2012@12^31' are equivalent. The only delimiter recognized is the . character, which is treated as a decimal point to separate the integer and fractional parts. The date and time parts can be separated by T other than a space. For example, 2017-8-24 10:42:00 and 2017-8-24T10:42:00 are equivalent. As a string with no delimiters in either 'YYYYMMDDHHMMSS' or 'YYMMDDHHMMSS' format. For example, '20170824104520' and '170824104520' are interpreted as '2017-08-24 10:45:20'. But '170824304520' is illegal because the hour part exceeds the legal range. As a number in either YYYYMMDDHHMMSS or YYMMDDHHMMSS format, without single quotation marks or double quotation marks. For example, 20170824104520 is interpreted as '2017-08-24 10:45:20'. A DATETIME or TIMESTAMP value can include a trailing fractional seconds part in up to microseconds (6 digits) precision. The fractional part should always be separated from the rest of the time by a decimal point.Dates containing two-digit year values are ambiguous. It is recommended to use the four-digit format. TiDB interprets two-digit year values using the following rules: Year values in the range of 70-99 are converted to 1970-1999. Year values in the range of 00-69 are converted to 2000-2069. For values specified as strings that include date part delimiters, it is unnecessary to specify two digits for month or day values that are less than 10. '2017-8-4' is the same as '2017-08-04'. Similarly, for values specified as strings that include time part delimiters, it is unnecessary to specify two digits for hour, minute, or second values that are less than 10. '2017-08-24 1:2:3' is the same as '2017-08-24 01:02:03'.In TiDB, the date or time values specified as numbers are interpreted according their length: 6 digits: YYMMDD 12 digits: YYMMDDHHMMSS 8 digits: YYYYMMDD 14 digits: YYYYMMDDHHMMSS TiDB supports the following formats for time values: As a string in 'D HH:MM:SS' format. You can also use one of the following “relaxed” syntaxes: 'HH:MM:SS', 'HH:MM', 'D HH:MM', 'D HH', or 'SS'. Here D represents days and the legal value range is 0-34. As a number in 'HHMMSS' format. For example, 231010 is interpreted as '23:10:10'. A number in any of the SS, MMSS or HHMMSS format can be treated as time. The time value can also include a trailing fractional part in up to 6 digits precision. The . character represents the decimal point.For more information, see Date and Time Literals in MySQL.Boolean literals The constants TRUE and FALSE evaluate to 1 and 0 respectively, which are not case sensitive.mysql> SELECT TRUE, true, tRuE, FALSE, FaLsE, false; +------+------+------+-------+-------+-------+ | TRUE | true | tRuE | FALSE | FaLsE | false | +------+------+------+-------+-------+-------+ | 1 | 1 | 1 | 0 | 0 | 0 | …"}, {"url": "https://pingcap.com/docs/v1.0/sql/literal-values/", "title": "Literal Values", "content": " Literal Values String literals A string is a sequence of bytes or characters, enclosed within either single quote ' or double quote " characters. For example:'example string' "example string" Quoted strings placed next to each other are concatenated to a single string. The following lines are equivalent:'a string' 'a' ' ' 'string' "a" ' ' "string" If the ANSI_QUOTES SQL MODE is enabled, string literals can be quoted only within single quotation marks because a string quoted within double quotation marks is interpreted as an identifier.A binary string is a string of bytes. Each binary string has a character set and collation named binary. A non-binary string is a string of characters. It has a character set other than binary and a collation that is compatible with the character set.For both types of strings, comparisons are based on the numeric values of the string unit. For binary strings, the unit is the byte. For non-binary strings, the unit is the character and some character sets support multibyte characters.A string literal may have an optional character set introducer and COLLATE clause, to designate it as a string that uses a specific character set and collation. TiDB only supports this in syntax, but does not process it.[_charset_name]'string' [COLLATE collation_name] For example:SELECT _latin1'string'; SELECT _binary'string'; SELECT _utf8'string' COLLATE utf8_bin; You can use N’literal’ (or n’literal’) to create a string in the national character set. The following statements are equivalent:SELECT N'some text'; SELECT n'some text'; SELECT _utf8'some text'; Escape characters: 0: An ASCII NUL (X’00’) character ': A single quote (‘) character ": A double quote (“)character b: A backspace character n: A newline (linefeed) character r: A carriage return character t: A tab character z: ASCII 26 (Ctrl + Z) : A backslash character %: A % character _: A _ character You can use the following ways to include quote characters within a string: A ' inside a string quoted with ' may be written as ''. A " inside a string quoted with " may be written as "". Precede the quote character by an escape character . A ' inside a string quoted with " needs no special treatment, and a " inside a string quoted with ' needs no special treatment either. For more information, see String Literals in MySQL.Numeric literals Numeric literals include integer and DECIMAL literals and floating-point literals.Integer may include . as a decimal separator. Numbers may be preceded by - or + to indicate a negative or positive value respectively.Exact-value numeric literals can be represented as 1, .2, 3.4, -5, -6.78, +9.10.Numeric literals can also be represented in scientific notation, such as 1.2E3, 1.2E-3, -1.2E3, -1.2E-3.For more information, see Numeric Literals in MySQL.NULL values The NULL value means “no data”. NULL can be written in any letter case. A synonym is N (case sensitive).Be aware that the NULL value is different from values such as 0 for numeric types or the empty string '' for string types.Hexadecimal literals Hexadecimal literal values are written using X'val' or 0xval notation, where val contains hexadecimal digits. A leading 0x is case sensitive and cannot be written as 0X.Legal hexadecimal literals:X'ac12' X'12AC' x'ac12' x'12AC' 0xac12 0x12AC Illegal hexadecimal literals:X'1z' (z is not a hexadecimal legal digit) 0X12AC (0X must be written as 0x) Hexadecimal literals written using X'val' notation must contain an even number of digits. To avoid the syntax error, pad the value with a leading zero:mysql> select X'aff'; ERROR 1105 (HY000): line 0 column 13 near ""hex literal: invalid hexadecimal format, must even numbers, but 3 (total length 13) mysql> select X'0aff'; +---------+ | X'0aff' | +---------+ | | +---------+ 1 row in set (0.00 sec) By default, a hexadecimal literal is a binary string.To convert a string or a number to a string in hexadecimal format, use the HEX() function:mysql> SELECT HEX('TiDB'); +-------------+ | HEX('TiDB') | +-------------+ | 54694442 | +-------------+ 1 row in set (0.01 sec) mysql> SELECT X'54694442'; +-------------+ | X'54694442' | +-------------+ | TiDB | +-------------+ 1 row in set (0.00 sec) Date and time literals Date and time values can be represented in several formats, such as quoted strings or as numbers. When TiDB expects a date, it interprets any of '2015-07-21', '20150721' and 20150721 as a date.TiDB supports the following formats for date values: As a string in either 'YYYY-MM-DD' or 'YY-MM-DD' format. The - delimiter is “relaxed” in syntax. Any punctuation character may be used as the delimiter between date parts. For example, '2017-08-24', '2017&08&24' and '2012@12^31' are equivalent. The only delimiter recognized is the . character, which is treated as a decimal point to separate the integer and fractional parts. The date and time parts can be separated by T other than a space. For example, 2017-8-24 10:42:00 and 2017-8-24T10:42:00 are equivalent. As a string with no delimiters in either 'YYYYMMDDHHMMSS' or 'YYMMDDHHMMSS' format. For example, '20170824104520' and '170824104520' are interpreted as '2017-08-24 10:45:20'. But '170824304520' is illegal because the hour part exceeds the legal range. As a number in either YYYYMMDDHHMMSS or YYMMDDHHMMSS format, without single quotation marks or double quotation marks. For example, 20170824104520 is interpreted as '2017-08-24 10:45:20'. A DATETIME or TIMESTAMP value can include a trailing fractional seconds part in up to microseconds (6 digits) precision. The fractional part should always be separated from the rest of the time by a decimal point.Dates containing two-digit year values are ambiguous. It is recommended to use the four-digit format. TiDB interprets two-digit year values using the following rules: Year values in the range of 70-99 are converted to 1970-1999. Year values in the range of 00-69 are converted to 2000-2069. For values specified as strings that include date part delimiters, it is unnecessary to specify two digits for month or day values that are less than 10. '2017-8-4' is the same as '2017-08-04'. Similarly, for values specified as strings that include time part delimiters, it is unnecessary to specify two digits for hour, minute, or second values that are less than 10. '2017-08-24 1:2:3' is the same as '2017-08-24 01:02:03'.In TiDB, the date or time values specified as numbers are interpreted according their length: 6 digits: YYMMDD 12 digits: YYMMDDHHMMSS 8 digits: YYYYMMDD 14 digits: YYYYMMDDHHMMSS TiDB supports the following formats for time values: As a string in 'D HH:MM:SS' format. You can also use one of the following “relaxed” syntaxes: 'HH:MM:SS', 'HH:MM', 'D HH:MM', 'D HH', or 'SS'. Here D represents days and the legal value range is 0-34. As a number in 'HHMMSS' format. For example, 231010 is interpreted as '23:10:10'. A number in any of the SS, MMSS or HHMMSS format can be treated as time. The time value can also include a trailing fractional part in up to 6 digits precision. The . character represents the decimal point.For more information, see Date and Time Literals in MySQL.Boolean literals The constants TRUE and FALSE evaluate to 1 and 0 respectively, which are not case sensitive.mysql> SELECT TRUE, true, tRuE, FALSE, FaLsE, false; +------+------+------+-------+-------+-------+ | TRUE | true | tRuE | FALSE | FaLsE | false | +------+------+------+-------+-------+-------+ | 1 | 1 | 1 | 0 | 0 | 0 | +------+------+------+-------+-------+-------+ 1 row in set (0.00 sec) Bit-value literals Bit-value literals are written using b'val' or 0bval notation. The val is a binary value …"}, {"url": "https://pingcap.com/docs/v2.0/sql/literal-values/", "title": "Literal Values", "content": " Literal Values This document describes String literals, Numeric literals, NULL values, Hexadecimal literals, Date and time literals, Boolean literals, and Bit-value literals.String literals A string is a sequence of bytes or characters, enclosed within either single quote ' or double quote " characters. For example:'example string' "example string" Quoted strings placed next to each other are concatenated to a single string. The following lines are equivalent:'a string' 'a' ' ' 'string' "a" ' ' "string" If the ANSI_QUOTES SQL MODE is enabled, string literals can be quoted only within single quotation marks because a string quoted within double quotation marks is interpreted as an identifier.A binary string is a string of bytes. Each binary string has a character set and collation named binary. A non-binary string is a string of characters. It has a character set other than binary and a collation that is compatible with the character set.For both types of strings, comparisons are based on the numeric values of the string unit. For binary strings, the unit is the byte. For non-binary strings, the unit is the character and some character sets support multibyte characters.A string literal may have an optional character set introducer and COLLATE clause, to designate it as a string that uses a specific character set and collation. TiDB only supports this in syntax, but does not process it.[_charset_name]'string' [COLLATE collation_name] For example:SELECT _latin1'string'; SELECT _binary'string'; SELECT _utf8'string' COLLATE utf8_bin; You can use N’literal’ (or n’literal’) to create a string in the national character set. The following statements are equivalent:SELECT N'some text'; SELECT n'some text'; SELECT _utf8'some text'; Escape characters: 0: An ASCII NUL (X’00’) character ': A single quote (‘) character ": A double quote (“)character b: A backspace character n: A newline (linefeed) character r: A carriage return character t: A tab character z: ASCII 26 (Ctrl + Z) : A backslash character %: A % character _: A _ character You can use the following ways to include quote characters within a string: A ' inside a string quoted with ' may be written as ''. A " inside a string quoted with " may be written as "". Precede the quote character by an escape character . A ' inside a string quoted with " needs no special treatment, and a " inside a string quoted with ' needs no special treatment either. For more information, see String Literals in MySQL.Numeric literals Numeric literals include integer and DECIMAL literals and floating-point literals.Integer may include . as a decimal separator. Numbers may be preceded by - or + to indicate a negative or positive value respectively.Exact-value numeric literals can be represented as 1, .2, 3.4, -5, -6.78, +9.10.Numeric literals can also be represented in scientific notation, such as 1.2E3, 1.2E-3, -1.2E3, -1.2E-3.For more information, see Numeric Literals in MySQL.NULL values The NULL value means “no data”. NULL can be written in any letter case. A synonym is N (case sensitive).Be aware that the NULL value is different from values such as 0 for numeric types or the empty string '' for string types.Hexadecimal literals Hexadecimal literal values are written using X'val' or 0xval notation, where val contains hexadecimal digits. A leading 0x is case sensitive and cannot be written as 0X.Legal hexadecimal literals:X'ac12' X'12AC' x'ac12' x'12AC' 0xac12 0x12AC Illegal hexadecimal literals:X'1z' (z is not a hexadecimal legal digit) 0X12AC (0X must be written as 0x) Hexadecimal literals written using X'val' notation must contain an even number of digits. To avoid the syntax error, pad the value with a leading zero:mysql> select X'aff'; ERROR 1105 (HY000): line 0 column 13 near ""hex literal: invalid hexadecimal format, must even numbers, but 3 (total length 13) mysql> select X'0aff'; +---------+ | X'0aff' | +---------+ | | +---------+ 1 row in set (0.00 sec) By default, a hexadecimal literal is a binary string.To convert a string or a number to a string in hexadecimal format, use the HEX() function:mysql> SELECT HEX('TiDB'); +-------------+ | HEX('TiDB') | +-------------+ | 54694442 | +-------------+ 1 row in set (0.01 sec) mysql> SELECT X'54694442'; +-------------+ | X'54694442' | +-------------+ | TiDB | +-------------+ 1 row in set (0.00 sec) Date and time literals Date and time values can be represented in several formats, such as quoted strings or as numbers. When TiDB expects a date, it interprets any of '2015-07-21', '20150721' and 20150721 as a date.TiDB supports the following formats for date values: As a string in either 'YYYY-MM-DD' or 'YY-MM-DD' format. The - delimiter is “relaxed” in syntax. Any punctuation character may be used as the delimiter between date parts. For example, '2017-08-24', '2017&08&24' and '2012@12^31' are equivalent. The only delimiter recognized is the . character, which is treated as a decimal point to separate the integer and fractional parts. The date and time parts can be separated by T other than a space. For example, 2017-8-24 10:42:00 and 2017-8-24T10:42:00 are equivalent. As a string with no delimiters in either 'YYYYMMDDHHMMSS' or 'YYMMDDHHMMSS' format. For example, '20170824104520' and '170824104520' are interpreted as '2017-08-24 10:45:20'. But '170824304520' is illegal because the hour part exceeds the legal range. As a number in either YYYYMMDDHHMMSS or YYMMDDHHMMSS format, without single quotation marks or double quotation marks. For example, 20170824104520 is interpreted as '2017-08-24 10:45:20'. A DATETIME or TIMESTAMP value can include a trailing fractional seconds part in up to microseconds (6 digits) precision. The fractional part should always be separated from the rest of the time by a decimal point.Dates containing two-digit year values are ambiguous. It is recommended to use the four-digit format. TiDB interprets two-digit year values using the following rules: Year values in the range of 70-99 are converted to 1970-1999. Year values in the range of 00-69 are converted to 2000-2069. For values specified as strings that include date part delimiters, it is unnecessary to specify two digits for month or day values that are less than 10. '2017-8-4' is the same as '2017-08-04'. Similarly, for values specified as strings that include time part delimiters, it is unnecessary to specify two digits for hour, minute, or second values that are less than 10. '2017-08-24 1:2:3' is the same as '2017-08-24 01:02:03'.In TiDB, the date or time values specified as numbers are interpreted according their length: 6 digits: YYMMDD 12 digits: YYMMDDHHMMSS 8 digits: YYYYMMDD 14 digits: YYYYMMDDHHMMSS TiDB supports the following formats for time values: As a string in 'D HH:MM:SS' format. You can also use one of the following “relaxed” syntaxes: 'HH:MM:SS', 'HH:MM', 'D HH:MM', 'D HH', or 'SS'. Here D represents days and the legal value range is 0-34. As a number in 'HHMMSS' format. For example, 231010 is interpreted as '23:10:10'. A number in any of the SS, MMSS or HHMMSS format can be treated as time. The time value can also include a trailing fractional part in up to 6 digits precision. The . character represents the decimal point.For more information, see Date and Time Literals in MySQL.Boolean literals The constants TRUE and FALSE evaluate to 1 and 0 respectively, which are not case sensitive.mysql> SELECT TRUE, true, tRuE, FALSE, FaLsE, false; +------+------+------+-------+-------+-------+ | TRUE | true | tRuE | FALSE | FaLsE | false | +------+------+------+-------+-------+-------+ | 1 | 1 | 1 | 0 | 0 | 0 | …"}, {"url": "https://pingcap.com/tidb-academy/mysql_dbas/mysql-compatibility/lab/", "title": "Load Sample Data", "content": " Load Sample Data "}, {"url": "https://pingcap.com/docs/tools/loader/", "title": "Loader Instructions", "content": " Loader Instructions What is Loader? Loader is a data import tool to load data to TiDB.Download the Binary.Why did we develop Loader? Since tools like mysqldump will take us days to migrate massive amounts of data, we used the mydumper/myloader suite to multi-thread export and import data. During the process, we found that mydumper works well. However, as myloader lacks functions of error retry and savepoint, it is inconvenient for us to use. Therefore, we developed loader, which reads the output data files of mydumper and imports data to TiDB through the MySQL protocol.What can Loader do? Multi-thread import data Support table level concurrent import and scattered hot spot write Support concurrent import of a single large table and scattered hot spot write Support mydumper data format Support error retry Support savepoint Improve the speed of importing data through system variable Usage Note: Do not import the mysql system database from the MySQL instance to the downstream TiDB instance. If mydumper uses the -m parameter, the data is exported without the table structure and the loader can not import the data. If you use the default checkpoint-schema parameter, after importing the data of a database, run drop database tidb_loader before you begin to import the next database. It is recommended to specify the checkpoint-schema = "tidb_loader" parameter when importing data. Parameter description -L string: the log level setting, which can be set as debug, info, warn, error, fatal (default: "info") -P int: the port of TiDB (default: 4000) -V boolean: prints version and exit -c string: config file -checkpoint-schema string: the database name of checkpoint. In the execution process, loader will constantly update this database. After recovering from an interruption, loader will get the process of the last run through this database. (default: "tidb_loader") -d string: the storage directory of data that need to import (default: "./") -h string: the host of TiDB (default: "127.0.0.1") -p string: the account and password of TiDB -pprof-addr string: the pprof address of Loader. It tunes the performance of Loader (default: ":10084") -t int: the number of thread,increase this as TiKV nodes increase (default: 16) -u string: the user name of TiDB (default: "root") Configuration file Apart from command line parameters, you can also use configuration files. The format is shown as below:# Loader log level, which can be set as "debug", "info", "warn", "error" and "fatal" (default: "info") log-level = "info" # Loader log file log-file = "loader.log" # Directory of the dump to import (default: "./") dir = "./" # Loader pprof address, used to tune the performance of Loader (default: "127.0.0.1:10084") pprof-addr = "127.0.0.1:10084" # The checkpoint data is saved to TiDB, and the schema name is defined here. checkpoint-schema = "tidb_loader" # Number of threads restoring concurrently for worker pool (default: 16). Each worker restore one file at a time. pool-size = 16 # The target database information [db] host = "127.0.0.1" user = "root" password = "" port = 4000 # The sharding synchronising rules support wildcharacter. # 1. The asterisk character (*, also called "star") matches zero or more characters, # for example, "doc*" matches "doc" and "document" but not "dodo"; # asterisk character must be in the end of the wildcard word, # and there is only one asterisk in one wildcard word. # 2. The question mark '?' matches exactly one character. # [[route-rules]] # pattern-schema = "shard_db_*" # pattern-table = "shard_table_*" # target-schema = "shard_db" # target-table = "shard_table" Usage example Command line parameter:./bin/loader -d ./test -h 127.0.0.1 -u root -P 4000 Or use configuration file “config.toml”:./bin/loader -c=config.toml FAQ The scenario of synchronising data from sharded tables Loader supports importing data from sharded tables into one table within one database according to the route-rules. Before synchronising, check the following items: Whether the sharding rules can be represented using the route-rules syntax. Whether the sharded tables contain monotone increasing primary keys, or whether there are conflicts in the unique indexes or the primary keys after the combination. To combine tables, start the route-rules parameter in the configuration file of Loader: To use the table combination function, it is required to fill the pattern-schema and target-schema. If the pattern-table and target-table are NULL, the table name is not combined or converted. [[route-rules]] pattern-schema = "example_db" pattern-table = "table_*" target-schema = "example_db" target-table = "table""}, {"url": "https://pingcap.com/docs/v1.0/tools/loader/", "title": "Loader Instructions", "content": " Loader Instructions What is Loader? Loader is a data import tool to load data to TiDB.Download the Binary.Why did we develop Loader? Since tools like mysqldump will take us days to migrate massive amounts of data, we used the mydumper/myloader suite of Percona to multi-thread export and import data. During the process, we found that mydumper works well. However, as myloader lacks functions of error retry and savepoint, it is inconvenient for us to use. Therefore, we developed loader, which reads the output data files of mydumper and imports data to TiDB through mysql protocol.What can Loader do? Multi-thread import data Support table level concurrent import and scattered hot spot write Support concurrent import of a single large table and scattered hot spot write Support mydumper data format Support error retry Support savepoint Improve the speed of importing data through system variable Usage Note: - Do not import the mysql system database from the MySQL instance to the downstream TiDB instance. - If mydumper uses the -m parameter, the data is exported without the table structure and the loader can not import the data. - If you use the default checkpoint-schema parameter, after importing the data of a database, run drop database tidb_loader before you begin to import the next database. - It is recommended to specify the checkpoint-schema = "tidb_loader" parameter when importing data. Parameter description -L string: the log level setting, which can be set as debug, info, warn, error, fatal (default: "info") -P int: the port of TiDB (default: 4000) -V boolean: prints version and exit -c string: config file -checkpoint-schema string: the database name of checkpoint. In the execution process, loader will constantly update this database. After recovering from an interruption, loader will get the process of the last run through this database. (default: "tidb_loader") -d string: the storage directory of data that need to import (default: "./") -h string: the host of TiDB (default: "127.0.0.1") -p string: the account and password of TiDB -pprof-addr string: the pprof address of Loader. It tunes the perfomance of Loader (default: ":10084") -t int: the number of thread,increase this as TiKV nodes increase (default: 16) -u string: the user name of TiDB (default: "root") Configuration file Apart from command line parameters, you can also use configuration files. The format is shown as below:# Loader log level, which can be set as "debug", "info", "warn", "error" and "fatal" (default: "info") log-level = "info" # Loader log file log-file = "loader.log" # Directory of the dump to import (default: "./") dir = "./" # Loader pprof address, used to tune the performance of Loader (default: "127.0.0.1:10084") pprof-addr = "127.0.0.1:10084" # The checkpoint data is saved to TiDB, and the schema name is defined here. checkpoint-schema = "tidb_loader" # Number of threads restoring concurrently for worker pool (default: 16). Each worker restore one file at a time. pool-size = 16 # The target database information [db] host = "127.0.0.1" user = "root" password = "" port = 4000 # The sharding synchronising rules support wildcharacter. # 1. The asterisk character (*, also called "star") matches zero or more characters, # for example, "doc*" matches "doc" and "document" but not "dodo"; # asterisk character must be in the end of the wildcard word, # and there is only one asterisk in one wildcard word. # 2. The question mark '?' matches exactly one character. # [[route-rules]] # pattern-schema = "shard_db_*" # pattern-table = "shard_table_*" # target-schema = "shard_db" # target-table = "shard_table" Usage example Command line parameter:./bin/loader -d ./test -h 127.0.0.1 -u root -P 4000 Or use configuration file “config.toml”:./bin/loader -c=config.toml FAQ The scenario of synchronising data from sharded tables Loader supports importing data from sharded tables into one table within one database according to the route-rules. Before synchronising, check the following items: Whether the sharding rules can be represented using the route-rules syntax. Whether the sharded tables contain monotone increasing primary keys, or whether there are conflicts in the unique indexes or the primary keys after the combination. To combine tables, start the route-rules parameter in the configuration file of Loader: To use the table combination function, it is required to fill the pattern-schema and target-schema. If the pattern-table and target-table are NULL, the table name is not combined or converted. [[route-rules]] pattern-schema = "example_db" pattern-table = "table_*" target-schema = "example_db" target-table = "table""}, {"url": "https://pingcap.com/docs/v2.0/tools/loader/", "title": "Loader Instructions", "content": " Loader Instructions What is Loader? Loader is a data import tool to load data to TiDB.Download the Binary.Why did we develop Loader? Since tools like mysqldump will take us days to migrate massive amounts of data, we used the mydumper/myloader suite to multi-thread export and import data. During the process, we found that mydumper works well. However, as myloader lacks functions of error retry and savepoint, it is inconvenient for us to use. Therefore, we developed loader, which reads the output data files of mydumper and imports data to TiDB through the MySQL protocol.What can Loader do? Multi-thread import data Support table level concurrent import and scattered hot spot write Support concurrent import of a single large table and scattered hot spot write Support mydumper data format Support error retry Support savepoint Improve the speed of importing data through system variable Usage Note: Do not import the mysql system database from the MySQL instance to the downstream TiDB instance. If mydumper uses the -m parameter, the data is exported without the table structure and the loader can not import the data. If you use the default checkpoint-schema parameter, after importing the data of a database, run drop database tidb_loader before you begin to import the next database. It is recommended to specify the checkpoint-schema = "tidb_loader" parameter when importing data. Parameter description -L string: the log level setting, which can be set as debug, info, warn, error, fatal (default: "info") -P int: the port of TiDB (default: 4000) -V boolean: prints version and exit -c string: config file -checkpoint-schema string: the database name of checkpoint. In the execution process, loader will constantly update this database. After recovering from an interruption, loader will get the process of the last run through this database. (default: "tidb_loader") -d string: the storage directory of data that need to import (default: "./") -h string: the host of TiDB (default: "127.0.0.1") -p string: the account and password of TiDB -pprof-addr string: the pprof address of Loader. It tunes the performance of Loader (default: ":10084") -t int: the number of thread,increase this as TiKV nodes increase (default: 16) -u string: the user name of TiDB (default: "root") Configuration file Apart from command line parameters, you can also use configuration files. The format is shown as below:# Loader log level, which can be set as "debug", "info", "warn", "error" and "fatal" (default: "info") log-level = "info" # Loader log file log-file = "loader.log" # Directory of the dump to import (default: "./") dir = "./" # Loader pprof address, used to tune the performance of Loader (default: "127.0.0.1:10084") pprof-addr = "127.0.0.1:10084" # The checkpoint data is saved to TiDB, and the schema name is defined here. checkpoint-schema = "tidb_loader" # Number of threads restoring concurrently for worker pool (default: 16). Each worker restore one file at a time. pool-size = 16 # The target database information [db] host = "127.0.0.1" user = "root" password = "" port = 4000 # The sharding synchronising rules support wildcharacter. # 1. The asterisk character (*, also called "star") matches zero or more characters, # for example, "doc*" matches "doc" and "document" but not "dodo"; # asterisk character must be in the end of the wildcard word, # and there is only one asterisk in one wildcard word. # 2. The question mark '?' matches exactly one character. # [[route-rules]] # pattern-schema = "shard_db_*" # pattern-table = "shard_table_*" # target-schema = "shard_db" # target-table = "shard_table" Usage example Command line parameter:./bin/loader -d ./test -h 127.0.0.1 -u root -P 4000 Or use configuration file “config.toml”:./bin/loader -c=config.toml FAQ The scenario of synchronising data from sharded tables Loader supports importing data from sharded tables into one table within one database according to the route-rules. Before synchronising, check the following items: Whether the sharding rules can be represented using the route-rules syntax. Whether the sharded tables contain monotone increasing primary keys, or whether there are conflicts in the unique indexes or the primary keys after the combination. To combine tables, start the route-rules parameter in the configuration file of Loader: To use the table combination function, it is required to fill the pattern-schema and target-schema. If the pattern-table and target-table are NULL, the table name is not combined or converted. [[route-rules]] pattern-schema = "example_db" pattern-table = "table_*" target-schema = "example_db" target-table = "table""}, {"url": "https://pingcap.com/docs-cn/tools/loader/", "title": "Loader 使用文档", "content": " Loader 使用文档 Loader 简介 Loader 是由 PingCAP 开发的数据导入工具,用于向 TiDB 中导入数据。Binary 下载为什么我们要做这个工具 当数据量比较大的时候,如果用 mysqldump 这样的工具迁移数据会比较慢。我们尝试了 mydumper/myloader 套件,能够多线程导出和导入数据。在使用过程中,mydumper 问题不大,但是 myloader 由于缺乏出错重试、断点续传这样的功能,使用起来很不方便。所以我们开发了 loader,能够读取 mydumper 的输出数据文件,通过 MySQL protocol 向 TiDB/MySQL 中导入数据。Loader 有哪些优点 多线程导入 支持表级别的并发导入,分散写入热点 支持对单个大表并发导入,分散写入热点 支持 mydumper 数据格式 出错重试 断点续导 通过 system variable 优化 TiDB 导入数据速度 使用方法 注意事项 请勿使用 loader 导入 MySQL 实例中 mysql 系统数据库到下游 TiDB。如果 mydumper 使用 -m 参数,会导出不带表结构的数据,这时 loader 无法导入数据。如果使用默认的 checkpoint-schema 参数,在导完一个 database 数据库后,请 drop database tidb_loader 后再开始导入下一个 database。推荐数据库开始导入的时候,明确指定 checkpoint-schema = "tidb_loader" 参数。参数说明 -L string log 级别设置,可以设置为 debug, info, warn, error, fatal (默认为 "info") -P int TiDB/MySQL 的端口 (默认为 4000) -V 打印 loader 版本 -c string 指定配置文件启动 loader -checkpoint-schema string checkpoint 数据库名,loader 在运行过程中会不断的更新这个数据库,在中断并恢复后,会通过这个库获取上次运行的进度 (默认为 "tidb_loader") -d string 需要导入的数据存放路径 (default "./") -h string TiDB 服务 host IP (default "127.0.0.1") -p string TiDB 账户密码 -pprof-addr string Loader 的 pprof 地址,用于对 Loader 进行性能调试 (默认为 ":10084") -t int 线程数 (默认为 16). 每个线程同一时刻只能操作一个数据文件。 -u string TiDB 的用户名 (默认为 "root") 配置文件 除了使用命令行参数外,还可以使用配置文件来配置,配置文件的格式如下:# 日志输出等级;可以设置为 debug, info, warn, error, fatal (默认为 "info") log-level = "info" # 指定 loader 日志目录 log-file = "loader.log" # 需要导入的数据存放路径 (default "./") dir = "./" # Loader 的 pprof 地址,用于对 Loader 进行性能调试 (默认为 ":10084") pprof-addr = "127.0.0.1:10084" # checkpoint 数据库名,loader 在运行过程中会不断的更新这个数据库,在中断并恢复后, # 会通过这个库获取上次运行的进度 (默认为 "tidb_loader") checkpoint-schema = "tidb_loader" # 线程数 (默认为 16). 每个线程同一时刻只能操作一个数据文件。 pool-size = 16 # 目标数据库信息 [db] host = "127.0.0.1" user = "root" password = "" port = 4000 # sharding 同步规则,采用 wildcharacter # 1. 星号字符 (*) 可以匹配零个或者多个字符, # 例子, doc* 匹配 doc 和 document, 但是和 dodo 不匹配; # 星号只能放在 pattern 结尾,并且一个 pattern 中只能有一个 # 2. 问号字符 (?) 匹配任一一个字符 # [[route-rules]] # pattern-schema = "shard_db_*" # pattern-table = "shard_table_*" # target-schema = "shard_db" # target-table = "shard_table" 使用示例 通过命令行参数:./bin/loader -d ./test -h 127.0.0.1 -u root -P 4000 或者使用配置文件 “config.toml”:./bin/loader -c=config.toml FAQ 合库合表场景案例说明 根据配置文件的 route-rules 可以支持将分库分表的数据导入到同一个库同一个表中,但是在开始前需要检查分库分表规则: 是否可以利用 route-rules 的语义规则表示 分表中是否包含唯一递增主键,或者合并后是否包含数据上有冲突的唯一索引或者主键 Loader 需要配置文件中开启 route-rules 参数以提供合库合表功能 如果使用该功能,必须填写 pattern-schema 与 target-schema 如果 pattern-table 与 target-table 为空,将不进行表名称合并或转换 [[route-rules]] pattern-schema = "example_db" pattern-table = "table_*" target-schema = "example_db" target-table = "table""}, {"url": "https://pingcap.com/docs-cn/v1.0/tools/loader/", "title": "Loader 使用文档", "content": " Loader 使用文档 Loader 是什么 是由 PingCAP 开发的数据导入工具,可以用于向 TiDB 中导入数据。Binary 下载为什么我们要做这个东西 当数据量比较大的时候,如果用 mysqldump 这样的工具迁移数据会比较慢。我们尝试了 Percona 的 mydumper/myloader 套件,能够多线程导出和导入数据。在使用过程中,mydumper 问题不大,但是 myloader 由于缺乏出错重试、断点续传这样的功能,使用起来很不方便。所以我们开发了 loader,能够读取 mydumper 的输出数据文件,通过 mysql protocol 向 TiDB/MySQL 中导入数据。Loader 有哪些优点 多线程导入 支持表级别的并发导入,分散写入热点 支持对单个大表并发导入,分散写入热点 支持 mydumper 数据格式 出错重试 断点续导 通过 system variable 优化 TiDB 导入数据速度 使用方法 注意事项 请勿使用 loader 导入 MySQL 实例中 mysql 系统数据库到下游 TiDB。如果 mydumper 使用 -m 参数,会导出不带表结构的数据,这时 loader 无法导入数据。如果使用默认的 checkpoint-schema 参数,在导完一个 database 数据库后,请 drop database tidb_loader 后再开始导入下一个 database。推荐数据库开始导入的时候,明确指定 checkpoint-schema = "tidb_loader" 参数。参数说明 -L string log 级别设置,可以设置为 debug, info, warn, error, fatal (默认为 "info") -P int TiDB/MySQL 的端口 (默认为 4000) -V 打印 loader 版本 -c string 指定配置文件启动 loader -checkpoint-schema string checkpoint 数据库名,loader 在运行过程中会不断的更新这个数据库,在中断并恢复后,会通过这个库获取上次运行的进度 (默认为 "tidb_loader") -d string 需要导入的数据存放路径 (default "./") -h string TiDB 服务 host IP (default "127.0.0.1") -p string TiDB 账户密码 -pprof-addr string Loader 的 pprof 地址,用于对 Loader 进行性能调试 (默认为 ":10084") -t int 线程数 (默认为 16). 每个线程同一时刻只能操作一个数据文件。 -u string TiDB 的用户名 (默认为 "root") 配置文件 除了使用命令行参数外,还可以使用配置文件来配置,配置文件的格式如下:# 日志输出等级;可以设置为 debug, info, warn, error, fatal (默认为 "info") log-level = "info" # 指定 loader 日志目录 log-file = "loader.log" # 需要导入的数据存放路径 (default "./") dir = "./" # Loader 的 pprof 地址,用于对 Loader 进行性能调试 (默认为 ":10084") pprof-addr = "127.0.0.1:10084" # checkpoint 数据库名,loader 在运行过程中会不断的更新这个数据库,在中断并恢复后, # 会通过这个库获取上次运行的进度 (默认为 "tidb_loader") checkpoint-schema = "tidb_loader" # 线程数 (默认为 16). 每个线程同一时刻只能操作一个数据文件。 pool-size = 16 # 目标数据库信息 [db] host = "127.0.0.1" user = "root" password = "" port = 4000 # sharding 同步规则,采用 wildcharacter # 1. 星号字符 (*) 可以匹配零个或者多个字符, # 例子, doc* 匹配 doc 和 document, 但是和 dodo 不匹配; # 星号只能放在 pattern 结尾,并且一个 pattern 中只能有一个 # 2. 问号字符 (?) 匹配任一一个字符 # [[route-rules]] # pattern-schema = "shard_db_*" # pattern-table = "shard_table_*" # target-schema = "shard_db" # target-table = "shard_table" 使用示例 通过命令行参数:./bin/loader -d ./test -h 127.0.0.1 -u root -P 4000 或者使用配置文件 “config.toml”:./bin/loader -c=config.toml FAQ 合库合表场景案例说明 根据配置文件的 route-rules 可以支持将分库分表的数据导入到同一个库同一个表中,但是在开始前需要检查分库分表规则: 是否可以利用 route-rules 的语义规则表示 分表中是否包含唯一递增主键,或者合并后是否包含数据上有冲突的唯一索引或者主键 Loader 需要配置文件中开启 route-rules 参数以提供合库合表功能 如果使用该功能,必须填写 pattern-schema 与 target-schema 如果 pattern-table 与 target-table 为空,将不进行表名称合并或转换 [[route-rules]] pattern-schema = "example_db" pattern-table = "table_*" target-schema = "example_db" target-table = "table""}, {"url": "https://pingcap.com/docs-cn/v2.0/tools/loader/", "title": "Loader 使用文档", "content": " Loader 使用文档 Loader 是什么 是由 PingCAP 开发的数据导入工具,可以用于向 TiDB 中导入数据。Binary 下载为什么我们要做这个东西 当数据量比较大的时候,如果用 mysqldump 这样的工具迁移数据会比较慢。我们尝试了 Percona 的 mydumper/myloader 套件,能够多线程导出和导入数据。在使用过程中,mydumper 问题不大,但是 myloader 由于缺乏出错重试、断点续传这样的功能,使用起来很不方便。所以我们开发了 loader,能够读取 mydumper 的输出数据文件,通过 mysql protocol 向 TiDB/MySQL 中导入数据。Loader 有哪些优点 多线程导入 支持表级别的并发导入,分散写入热点 支持对单个大表并发导入,分散写入热点 支持 mydumper 数据格式 出错重试 断点续导 通过 system variable 优化 TiDB 导入数据速度 使用方法 注意事项 请勿使用 loader 导入 MySQL 实例中 mysql 系统数据库到下游 TiDB。如果 mydumper 使用 -m 参数,会导出不带表结构的数据,这时 loader 无法导入数据。如果使用默认的 checkpoint-schema 参数,在导完一个 database 数据库后,请 drop database tidb_loader 后再开始导入下一个 database。推荐数据库开始导入的时候,明确指定 checkpoint-schema = "tidb_loader" 参数。参数说明 -L string log 级别设置,可以设置为 debug, info, warn, error, fatal (默认为 "info") -P int TiDB/MySQL 的端口 (默认为 4000) -V 打印 loader 版本 -c string 指定配置文件启动 loader -checkpoint-schema string checkpoint 数据库名,loader 在运行过程中会不断的更新这个数据库,在中断并恢复后,会通过这个库获取上次运行的进度 (默认为 "tidb_loader") -d string 需要导入的数据存放路径 (default "./") -h string TiDB 服务 host IP (default "127.0.0.1") -p string TiDB 账户密码 -pprof-addr string Loader 的 pprof 地址,用于对 Loader 进行性能调试 (默认为 ":10084") -t int 线程数 (默认为 16). 每个线程同一时刻只能操作一个数据文件。 -u string TiDB 的用户名 (默认为 "root") 配置文件 除了使用命令行参数外,还可以使用配置文件来配置,配置文件的格式如下:# 日志输出等级;可以设置为 debug, info, warn, error, fatal (默认为 "info") log-level = "info" # 指定 loader 日志目录 log-file = "loader.log" # 需要导入的数据存放路径 (default "./") dir = "./" # Loader 的 pprof 地址,用于对 Loader 进行性能调试 (默认为 ":10084") pprof-addr = "127.0.0.1:10084" # checkpoint 数据库名,loader 在运行过程中会不断的更新这个数据库,在中断并恢复后, # 会通过这个库获取上次运行的进度 (默认为 "tidb_loader") checkpoint-schema = "tidb_loader" # 线程数 (默认为 16). 每个线程同一时刻只能操作一个数据文件。 pool-size = 16 # 目标数据库信息 [db] host = "127.0.0.1" user = "root" password = "" port = 4000 # sharding 同步规则,采用 wildcharacter # 1. 星号字符 (*) 可以匹配零个或者多个字符, # 例子, doc* 匹配 doc 和 document, 但是和 dodo 不匹配; # 星号只能放在 pattern 结尾,并且一个 pattern 中只能有一个 # 2. 问号字符 (?) 匹配任一一个字符 # [[route-rules]] # pattern-schema = "shard_db_*" # pattern-table = "shard_table_*" # target-schema = "shard_db" # target-table = "shard_table" 使用示例 通过命令行参数:./bin/loader -d ./test -h 127.0.0.1 -u root -P 4000 或者使用配置文件 “config.toml”:./bin/loader -c=config.toml FAQ 合库合表场景案例说明 根据配置文件的 route-rules 可以支持将分库分表的数据导入到同一个库同一个表中,但是在开始前需要检查分库分表规则: 是否可以利用 route-rules 的语义规则表示 分表中是否包含唯一递增主键,或者合并后是否包含数据上有冲突的唯一索引或者主键 Loader 需要配置文件中开启 route-rules 参数以提供合库合表功能 如果使用该功能,必须填写 pattern-schema 与 target-schema 如果 pattern-table 与 target-table 为空,将不进行表名称合并或转换 [[route-rules]] pattern-schema = "example_db" pattern-table = "table_*" target-schema = "example_db" target-table = "table""}, {"url": "https://pingcap.com/docs/tools/data-migration-manage-task/", "title": "Manage the Data Synchronization Task", "content": " Manage the Data Synchronization Task This document describes how to manage and maintain the data synchronization task using the dmctl component. For the Data Migration cluster deployed using DM-Ansible, the dmctl binary file is in dm-ansible/dmctl.dmctl basic usage This section shows the basic usage of dmctl commands.dmctl help $ ./dmctl --help Usage of dmctl: -V prints version and exit # Prints the version information. -encrypt string # Encrypts the database password according to the encryption method provided by DM; used in DM configuration files. ​ encrypt plaintext to ciphertext -master-addr string # dm-master access address. dmctl interacts with dm-master to complete task management operations. ​ master API server addr Database password encryption In DM configuration files, you need to use the password encrypted using dmctl, otherwise an error occurs. For a same original password, the password is different after each encryption.$ ./dmctl -encrypt 123456 VjX8cEeTX+qcvZ3bPaO4h0C80pe/1aU= Task management overview $ ./dmctl -master-addr 172.16.30.14 # Enters the command line mode to interact with DM-master Welcome to dmctl Release Version: v1.0.0-100-g2bef6f8b Git Commit Hash: 2bef6f8beda34c0dff57377005c71589b48aa3c5 Git Branch: dm-master UTC Build Time: 2018-11-02 10:03:18 Go Version: go version go1.11 linux/amd64 » help DM control Usage: dmctl [command] Available Commands: break-ddl-lock force to break DM-worker's DDL lock generate-task-config generate a task config with config file help Help about any command pause-relay pause DM-worker's relay unit pause-task pause a running task with name query-status query task's status refresh-worker-tasks refresh worker -> tasks mapper resume-relay resume DM-worker's relay unit resume-task resume a paused task with name show-ddl-locks show un-resolved DDL locks sql-inject sql-inject injects (limited) sqls into syncer as binlog event sql-replace sql-replace replaces sql in specific binlog_pos with other sqls, each sql must ends with semicolon; sql-skip sql-skip skips specified binlog position start-task start a task with config file stop-task stop a task with name switch-relay-master switch master server of DM-worker's relay unit unlock-ddl-lock force to unlock DDL lock update-master-config update configure of DM-master update-task update a task's config for routes, filters, column-mappings, black-white-list Flags: -h, --help help for dmctl -w, --worker strings DM-worker ID # Use "dmctl [command] --help" for more information about a command. Manage the data synchronization task This section describes how to use the task management commands to execute the following operations: Create the data synchronization task Check the data synchronization task status Pause the data synchronization task Restart the data synchronization task Stop the data synchronization task Update the data synchronization task Create the data synchronization task You can use the task management command to create the data synchronization task. When you create the data management task, DM checks the privilege of upstream database instances and the table schema. For the table schemas of all sharded tables in the sharding data synchronization task, DM executes the following two checks: Whether the auto-increment and unique column exists in the table, whether the corresponding partition id type of column mapping rule exists, and whether a conflict exists Whether the upstream and downstream table schemas to be synchronized are consistent » help start-task start a task with config file Usage: dmctl start-task [-w worker ...] <config_file> [flags] Flags: -h, --help help for start-task Global Flags: -w, --worker strings dm-worker ID Command usage example start-task [ -w "172.16.30.15:10081"] ./task.yaml Flags description -w: (Optional) This flag specifies the group of DM-workers to execute task.yaml. If it is set, only subtasks of the specified task on these DM-workers are started. config_file: (Required) This flag specifies the file path of task.yaml. Returned results { ​ "result": true, ​ "msg": "", ​ "workers": [ ​ { ​ "result": true, ​ "worker": "172.16.30.15:10081", ​ "msg": "" ​ }, ​ { ​ "result": true, ​ "worker": "172.16.30.16:10081", ​ "msg": "" ​ } ​ ] } Check the data synchronization task status You can use the task management command to check the status of the data synchronization task.» help query-status query task's status Usage: dmctl query-status [-w worker ...] [task_name] [flags] Flags: -h, --help help for query-status Global Flags: -w, --worker strings dm-worker ID Command usage example query-status Flags description -w: (Optional) This flag specifies the group of DM-workers where the subtasks of the synchronization task (that you want to query) run. task_name: (Optional) This flag specifies the task name. If it is not set, the results of all data synchronization tasks are returned. Returned results » query-status { ​ "result": true, ​ "msg": "", ​ "workers": [ ​ { ​ "result": true, ​ "worker": "172.16.30.15:10081", ​ "msg": "", ​ "subTaskStatus": [ ​ { ​ "name": "test", ​ "stage": "Running", ​ "unit": "Sync", ​ "result": null, ​ "unresolvedDDLLockID": "", ​ "sync": { ​ "TotalEvents": "0", ​ "TotalTps": "0", ​ "RecentTps": "0", ​ "MasterBinlog": "(mysql-bin.000004, 484)", ​ "MasterBinlogGtid": "", ​ "SyncerBinlog": "(mysql-bin.000004, 484)", ​ "SyncerBinlogGtid": "", "blockingDDLs": [ ], "unresolvedGroups": [ ] ​ } ​ } ​ ], ​ "relayStatus": { ​ "MasterBinlog": "(mysql-bin.000004, 484)", ​ "MasterBinlogGtid": "", "relaySubDir": "0-1.000001", ​ "RelayBinlog": "(mysql-bin.000004, 484)", ​ "RelayBinlogGtid": "", "relayCatchUpMaster": true, "stage": "Running", "result": null ​ } ​ }, ​ { ​ "result": true, ​ "worker": "172.16.30.16:10081", ​ "msg": "", ​ "subTaskStatus": [ ​ { ​ "name": "test", ​ "stage": "Running", ​ "unit": "Sync", ​ "result": null, ​ "unresolvedDDLLockID": "", ​ "sync": { ​ "TotalEvents": "0", ​ "TotalTps": "0", ​ "RecentTps": "0", ​ "MasterBinlog": "(mysql-bin.000004, 4809)", ​ "MasterBinlogGtid": "", ​ "SyncerBinlog": "(mysql-bin.000004, 4809)", ​ "SyncerBinlogGtid": "", "blockingDDLs": [ ], "unresolvedGroups": [ ] ​ } ​ } ​ ], ​ "relayStatus": { ​ "MasterBinlog": "(mysql-bin.000004, 4809)", ​ "MasterBinlogGtid": "", "relaySubDir": "0-1.000001", ​ "RelayBinlog": "(mysql-bin.000004, 4809)", ​ "RelayBinlogGtid": "", "relayCatchUpMaster": true, "stage": "Running", "result": null ​ } ​ } ​ ] } Pause the data synchronization task You can use the task management command to pause the data synchronization task.» help pause-task pause a running task with name Usage: dmctl pause-task [-w worker ...] <task_name> [flags] Flags: -h, --help help for pause-task Global Flags: -w, --worker strings DM-worker ID Command usage example pause-task [-w "127.0.0.1:10181"] task-name Flags description -w: (Optional) This flag specifies the group of DM-workers where the subtasks of the synchronization task (that you want to pause) run. If it is set, only subtasks on the specified …"}, {"url": "https://pingcap.com/recruit-cn/campus/campus-2019-marketing-specialist/", "title": "Marketing Specialist", "content": " 市场专员 岗位职责: 市场营销策略的战术执行和专项营销活动的支持,包括品牌、社区、营销类活动的信息收集,执行和活动后传播及效果汇总; 协助社区的用户运营和内容运营,构建及完善社区成员关系网,提升活跃度; 跟踪和分析市场运营数据及媒体指标,负责市场类标准信息的定期更新和整理分类; 周边衍生品的开发及制作,管理供应商,以及物料的日常分发管理。 任职要求: 计算机、市场营销、语言类专业,对编程有基础或有了解者优先; 具有较强的逻辑思维能力、协调能力与文字功底; 良好的沟通技能及团队合作能力,做事细致,责任感强。 加分项:熟悉技术开源社区,对社区需求有敏感性。待遇:8K - 15K,13薪 + 奖金,优秀者可面议联系方式:hire@pingcap.com工作地点:北京"}, {"url": "https://pingcap.com/docs/op-guide/migration/", "title": "Migrate Data from MySQL to TiDB", "content": " Migrate Data from MySQL to TiDB Use the mydumper/loader tool to export and import all the data You can use mydumper to export data from MySQL and loader to import the data into TiDB. Note: Although TiDB also supports the official mysqldump tool from MySQL for data migration, it is not recommended to use it. Its performance is much lower than mydumper / loader and it takes much time to migrate large amounts of data. mydumper/loader is more powerful. For more information, see https://github.com/maxbube/mydumper. Export data from MySQL Use the mydumper tool to export data from MySQL by using the following command:./bin/mydumper -h 127.0.0.1 -P 3306 -u root -t 16 -F 64 -B test -T t1,t2 --skip-tz-utc -o ./var/test In this command, -B test: means the data is exported from the test database. -T t1,t2: means only the t1 and t2 tables are exported. -t 16: means 16 threads are used to export the data. -F 64: means a table is partitioned into chunks and one chunk is 64MB. --skip-tz-utc: the purpose of adding this parameter is to ignore the inconsistency of time zone setting between MySQL and the data exporting machine and to disable automatic conversion. Note: On the Cloud platforms which require the super privilege, such as on the Aliyun platform, add the --no-locks parameter to the command. If not, you might get the error message that you don’t have the privilege. Import data to TiDB Use loader to import the data from MySQL to TiDB. See Loader instructions for more information../bin/loader -h 127.0.0.1 -u root -P 4000 -t 32 -d ./var/test After the data is imported, you can view the data in TiDB using the MySQL client:mysql -h127.0.0.1 -P4000 -uroot mysql> show tables; +----------------+ | Tables_in_test | +----------------+ | t1 | | t2 | +----------------+ mysql> select * from t1; +----+------+ | id | age | +----+------+ | 1 | 1 | | 2 | 2 | | 3 | 3 | +----+------+ mysql> select * from t2; +----+------+ | id | name | +----+------+ | 1 | a | | 2 | b | | 3 | c | +----+------+ Best practice To migrate data quickly, especially for huge amount of data, you can refer to the following recommendations. Keep the exported data file as small as possible and it is recommended keep it within 64M. You can use the -F parameter to set the value. You can adjust the -t parameter of loader based on the number and the load of TiKV instances. For example, if there are three TiKV instances, -t can be set to 3 * (1 ~ n). If the load of TiKV is too high and the log backoffer.maxSleep 15000ms is exceeded is displayed many times, decrease the value of -t; otherwise, increase it. A sample and the configuration The total size of the exported files is 214G. A single table has 8 columns and 2 billion rows. The cluster topology: 12 TiKV instances: 4 nodes, 3 TiKV instances per node 4 TiDB instances 3 PD instances The configuration of each node: CPU: Intel Xeon E5-2670 v3 @ 2.30GHz 48 vCPU [2 x 12 physical cores] Memory: 128G Disk: sda [raid 10, 300G] sdb[RAID 5, 2T] Operating System: CentOS 7.3 The -F parameter of mydumper is set to 16 and the -t parameter of loader is set to 64. Results: It takes 11 hours to import all the data, which is 19.4G/hour.Use the syncer tool to import data incrementally (optional) The previous section introduces how to import all the history data from MySQL to TiDB using mydumper/loader. But this is not applicable if the data in MySQL is updated after the migration and it is expected to import the updated data quickly.Therefore, TiDB provides the syncer tool for an incremental data import from MySQL to TiDB.See Download the TiDB enterprise toolset to download the syncer tool.Download the TiDB enterprise toolset (Linux) # Download the enterprise tool package. wget http://download.pingcap.org/tidb-enterprise-tools-latest-linux-amd64.tar.gz wget http://download.pingcap.org/tidb-enterprise-tools-latest-linux-amd64.sha256 # Check the file integrity. If the result is OK, the file is correct. sha256sum -c tidb-enterprise-tools-latest-linux-amd64.sha256 # Extract the package. tar -xzf tidb-enterprise-tools-latest-linux-amd64.tar.gz cd tidb-enterprise-tools-latest-linux-amd64 Assuming the data from t1 and t2 is already imported to TiDB using mydumper/loader. Now we hope that any updates to these two tables are synchronized to TiDB in real time.Obtain the position to synchronize The data exported from MySQL contains a metadata file which includes the position information. Take the following metadata information as an example:Started dump at: 2017-04-28 10:48:10 SHOW MASTER STATUS: Log: mysql-bin.000003 Pos: 930143241 GTID: Finished dump at: 2017-04-28 10:48:11 The position information (Pos: 930143241) needs to be stored in the syncer.meta file for syncer to synchronize:# cat syncer.meta binlog-name = "mysql-bin.000003" binlog-pos = 930143241 Note: The syncer.meta file only needs to be configured once when it is first used. The position will be automatically updated when binlog is synchronized. Start syncer The config.toml file for syncer:log-level = "info" server-id = 101 # The file path for meta: meta = "./syncer.meta" worker-count = 16 batch = 10 # The testing address for pprof. It can also be used by Prometheus to pull the syncer metrics. status-addr = ":10081" skip-sqls = ["ALTER USER", "CREATE USER"] # Support whitelist filter. You can specify the database and table to be synchronized. For example: # Synchronize all the tables of db1 and db2: replicate-do-db = ["db1","db2"] # Synchronize db1.table1. [[replicate-do-table]] db-name ="db1" tbl-name = "table1" # Synchronize db3.table2. [[replicate-do-table]] db-name ="db3" tbl-name = "table2" # Support regular expressions. Start with '~' to use regular expressions. # To synchronize all the databases that start with `test`: replicate-do-db = ["~^test.*"] # The sharding synchronising rules support wildcharacter. # 1. The asterisk character (*, also called "star") matches zero or more characters, # for example, "doc*" matches "doc" and "document" but not "dodo"; # asterisk character must be in the end of the wildcard word, # and there is only one asterisk in one wildcard word. # 2. The question mark ? matches exactly one character. #[[route-rules]] #pattern-schema = "route_*" #pattern-table = "abc_*" #target-schema = "route" #target-table = "abc" #[[route-rules]] #pattern-schema = "route_*" #pattern-table = "xyz_*" #target-schema = "route" #target-table = "xyz" [from] host = "127.0.0.1" user = "root" password = "" port = 3306 [to] host = "127.0.0.1" user = "root" password = "" port = 4000 Start syncer:./bin/syncer -config config.toml 2016/10/27 15:22:01 binlogsyncer.go:226: [info] begin to sync binlog from position (mysql-bin.000003, 1280) 2016/10/27 15:22:01 binlogsyncer.go:130: [info] register slave for master server 127.0.0.1:3306 2016/10/27 15:22:01 binlogsyncer.go:552: [info] rotate to (mysql-bin.000003, 1280) 2016/10/27 15:22:01 syncer.go:549: [info] rotate binlog to (mysql-bin.000003, 1280) Insert data into MySQL INSERT INTO t1 VALUES (4, 4), (5, 5); Log in TiDB and view the data mysql -h127.0.0.1 -P4000 -uroot -p mysql> select * from t1; +----+------+ | id | age | +----+------+ | 1 | 1 | | 2 | 2 | | 3 | 3 | | 4 | 4 | | 5 | 5 | +----+------+ syncer outputs the current synchronized data statistics every 30 seconds:2017/06/08 01:18:51 syncer.go:934: [info] [syncer]total events = 15, total tps = 130, recent tps = 4, master-binlog = (ON.000001, 11992), master-binlog-gtid=53ea0ed1-9bf8-11e6-8bea-64006a897c73:1-74, syncer-binlog = (ON.000001, 2504), syncer-binlog-gtid = 53ea0ed1-9bf8-11e6-8bea-64006a897c73:1-17 2017/06/08 01:19:21 syncer.go:934: [info] [syncer]total events = 15, total tps = 191, recent tps = 2, master-binlog = …"}, {"url": "https://pingcap.com/docs/v1.0/op-guide/migration/", "title": "Migrate Data from MySQL to TiDB", "content": " Migrate Data from MySQL to TiDB Use the mydumper / loader tool to export and import all the data You can use mydumper to export data from MySQL and loader to import the data into TiDB. Note: Although TiDB also supports the official mysqldump tool from MySQL for data migration, it is not recommended to use it. Its performance is much lower than mydumper / loader and it takes much time to migrate large amounts of data. mydumper/loader is more powerful. For more information, see https://github.com/maxbube/mydumper. Export data from MySQL Use the mydumper tool to export data from MySQL by using the following command:./bin/mydumper -h 127.0.0.1 -P 3306 -u root -t 16 -F 64 -B test -T t1,t2 --skip-tz-utc -o ./var/test In this command, -B test: means the data is exported from the test database. -T t1,t2: means only the t1 and t2 tables are exported. -t 16: means 16 threads are used to export the data. -F 64: means a table is partitioned into chunks and one chunk is 64MB. --skip-tz-utc: the purpose of adding this parameter is to ignore the inconsistency of time zone setting between MySQL and the data exporting machine and to disable automatic conversion. Note: On the Cloud platforms which require the super privilege, such as on the Aliyun platform, add the --no-locks parameter to the command. If not, you might get the error message that you don’t have the privilege. Import data to TiDB Use loader to import the data from MySQL to TiDB. See Loader instructions for more information../bin/loader -h 127.0.0.1 -u root -P 4000 -t 32 -d ./var/test After the data is imported, you can view the data in TiDB using the MySQL client:mysql -h127.0.0.1 -P4000 -uroot mysql> show tables; +----------------+ | Tables_in_test | +----------------+ | t1 | | t2 | +----------------+ mysql> select * from t1; +----+------+ | id | age | +----+------+ | 1 | 1 | | 2 | 2 | | 3 | 3 | +----+------+ mysql> select * from t2; +----+------+ | id | name | +----+------+ | 1 | a | | 2 | b | | 3 | c | +----+------+ Best practice To migrate data quickly, especially for huge amount of data, you can refer to the following recommendations. Keep the exported data file as small as possible and it is recommended keep it within 64M. You can use the -F parameter to set the value. You can adjust the -t parameter of loader based on the number and the load of TiKV instances. For example, if there are three TiKV instances, -t can be set to 3 * (1 ~ n). If the load of TiKV is too high and the log backoffer.maxSleep 15000ms is exceeded is displayed many times, decrease the value of -t; otherwise, increase it. A sample and the configuration The total size of the exported files is 214G. A single table has 8 columns and 2 billion rows. The cluster topology: 12 TiKV instances: 4 nodes, 3 TiKV instances per node 4 TiDB instances 3 PD instances The configuration of each node: CPU: Intel Xeon E5-2670 v3 @ 2.30GHz 48 vCPU [2 x 12 physical cores] Memory: 128G Disk: sda [raid 10, 300G] sdb[RAID 5, 2T] Operating System: CentOS 7.3 The -F parameter of mydumper is set to 16 and the -t parameter of loader is set to 64. Results: It takes 11 hours to import all the data, which is 19.4G/hour.Use the syncer tool to import data incrementally (optional) The previous section introduces how to import all the history data from MySQL to TiDB using mydumper/loader. But this is not applicable if the data in MySQL is updated after the migration and it is expected to import the updated data quickly.Therefore, TiDB provides the syncer tool for an incremental data import from MySQL to TiDB.See Download the TiDB enterprise toolset to download the syncer tool.Download the TiDB enterprise toolset (Linux) # Download the enterprise tool package. wget http://download.pingcap.org/tidb-enterprise-tools-latest-linux-amd64.tar.gz wget http://download.pingcap.org/tidb-enterprise-tools-latest-linux-amd64.sha256 # Check the file integrity. If the result is OK, the file is correct. sha256sum -c tidb-enterprise-tools-latest-linux-amd64.sha256 # Extract the package. tar -xzf tidb-enterprise-tools-latest-linux-amd64.tar.gz cd tidb-enterprise-tools-latest-linux-amd64 Assuming the data from t1 and t2 is already imported to TiDB using mydumper/loader. Now we hope that any updates to these two tables are synchronised to TiDB in real time.Obtain the position to synchronise The data exported from MySQL contains a metadata file which includes the position information. Take the following metadata information as an example:Started dump at: 2017-04-28 10:48:10 SHOW MASTER STATUS: Log: mysql-bin.000003 Pos: 930143241 GTID: Finished dump at: 2017-04-28 10:48:11 The position information (Pos: 930143241) needs to be stored in the syncer.meta file for syncer to synchronize:# cat syncer.meta binlog-name = "mysql-bin.000003" binlog-pos = 930143241 Note: The syncer.meta file only needs to be configured once when it is first used. The position will be automatically updated when binlog is synchronised. Start syncer The config.toml file for syncer:log-level = "info" server-id = 101 # The file path for meta: meta = "./syncer.meta" worker-count = 16 batch = 10 # The testing address for pprof. It can also be used by Prometheus to pull the syncer metrics. status-addr = ":10081" skip-sqls = ["ALTER USER", "CREATE USER"] # Support whitelist filter. You can specify the database and table to be synchronised. For example: # Synchronise all the tables of db1 and db2: replicate-do-db = ["db1","db2"] # Synchronise db1.table1. [[replicate-do-table]] db-name ="db1" tbl-name = "table1" # Synchronise db3.table2. [[replicate-do-table]] db-name ="db3" tbl-name = "table2" # Support regular expressions. Start with '~' to use regular expressions. # To synchronise all the databases that start with `test`: replicate-do-db = ["~^test.*"] # The sharding synchronising rules support wildcharacter. # 1. The asterisk character (*, also called "star") matches zero or more characters, # for example, "doc*" matches "doc" and "document" but not "dodo"; # asterisk character must be in the end of the wildcard word, # and there is only one asterisk in one wildcard word. # 2. The question mark ? matches exactly one character. #[[route-rules]] #pattern-schema = "route_*" #pattern-table = "abc_*" #target-schema = "route" #target-table = "abc" #[[route-rules]] #pattern-schema = "route_*" #pattern-table = "xyz_*" #target-schema = "route" #target-table = "xyz" [from] host = "127.0.0.1" user = "root" password = "" port = 3306 [to] host = "127.0.0.1" user = "root" password = "" port = 4000 Start syncer:./bin/syncer -config config.toml 2016/10/27 15:22:01 binlogsyncer.go:226: [info] begin to sync binlog from position (mysql-bin.000003, 1280) 2016/10/27 15:22:01 binlogsyncer.go:130: [info] register slave for master server 127.0.0.1:3306 2016/10/27 15:22:01 binlogsyncer.go:552: [info] rotate to (mysql-bin.000003, 1280) 2016/10/27 15:22:01 syncer.go:549: [info] rotate binlog to (mysql-bin.000003, 1280) Insert data into MySQL INSERT INTO t1 VALUES (4, 4), (5, 5); Log in TiDB and view the data mysql -h127.0.0.1 -P4000 -uroot -p mysql> select * from t1; +----+------+ | id | age | +----+------+ | 1 | 1 | | 2 | 2 | | 3 | 3 | | 4 | 4 | | 5 | 5 | +----+------+ syncer outputs the current synchronised data statistics every 30 seconds:2017/06/08 01:18:51 syncer.go:934: [info] [syncer]total events = 15, total tps = 130, recent tps = 4, master-binlog = (ON.000001, 11992), master-binlog-gtid=53ea0ed1-9bf8-11e6-8bea-64006a897c73:1-74, syncer-binlog = (ON.000001, 2504), syncer-binlog-gtid = 53ea0ed1-9bf8-11e6-8bea-64006a897c73:1-17 2017/06/08 01:19:21 syncer.go:934: [info] [syncer]total events = 15, total tps = 191, recent tps = 2, master-binlog = …"}, {"url": "https://pingcap.com/docs/v2.0/op-guide/migration/", "title": "Migrate Data from MySQL to TiDB", "content": " Migrate Data from MySQL to TiDB Use the mydumper / loader tool to export and import all the data You can use mydumper to export data from MySQL and loader to import the data into TiDB. Note: Although TiDB also supports the official mysqldump tool from MySQL for data migration, it is not recommended to use it. Its performance is much lower than mydumper / loader and it takes much time to migrate large amounts of data. mydumper/loader is more powerful. For more information, see https://github.com/maxbube/mydumper. Export data from MySQL Use the mydumper tool to export data from MySQL by using the following command:./bin/mydumper -h 127.0.0.1 -P 3306 -u root -t 16 -F 64 -B test -T t1,t2 --skip-tz-utc -o ./var/test In this command, -B test: means the data is exported from the test database. -T t1,t2: means only the t1 and t2 tables are exported. -t 16: means 16 threads are used to export the data. -F 64: means a table is partitioned into chunks and one chunk is 64MB. --skip-tz-utc: the purpose of adding this parameter is to ignore the inconsistency of time zone setting between MySQL and the data exporting machine and to disable automatic conversion. Note: On the Cloud platforms which require the super privilege, such as on the Aliyun platform, add the --no-locks parameter to the command. If not, you might get the error message that you don’t have the privilege. Import data to TiDB Use loader to import the data from MySQL to TiDB. See Loader instructions for more information../bin/loader -h 127.0.0.1 -u root -P 4000 -t 32 -d ./var/test After the data is imported, you can view the data in TiDB using the MySQL client:mysql -h127.0.0.1 -P4000 -uroot mysql> show tables; +----------------+ | Tables_in_test | +----------------+ | t1 | | t2 | +----------------+ mysql> select * from t1; +----+------+ | id | age | +----+------+ | 1 | 1 | | 2 | 2 | | 3 | 3 | +----+------+ mysql> select * from t2; +----+------+ | id | name | +----+------+ | 1 | a | | 2 | b | | 3 | c | +----+------+ Best practice To migrate data quickly, especially for huge amount of data, you can refer to the following recommendations. Keep the exported data file as small as possible and it is recommended keep it within 64M. You can use the -F parameter to set the value. You can adjust the -t parameter of loader based on the number and the load of TiKV instances. For example, if there are three TiKV instances, -t can be set to 3 * (1 ~ n). If the load of TiKV is too high and the log backoffer.maxSleep 15000ms is exceeded is displayed many times, decrease the value of -t; otherwise, increase it. A sample and the configuration The total size of the exported files is 214G. A single table has 8 columns and 2 billion rows. The cluster topology: 12 TiKV instances: 4 nodes, 3 TiKV instances per node 4 TiDB instances 3 PD instances The configuration of each node: CPU: Intel Xeon E5-2670 v3 @ 2.30GHz 48 vCPU [2 x 12 physical cores] Memory: 128G Disk: sda [raid 10, 300G] sdb[RAID 5, 2T] Operating System: CentOS 7.3 The -F parameter of mydumper is set to 16 and the -t parameter of loader is set to 64. Results: It takes 11 hours to import all the data, which is 19.4G/hour.Use the syncer tool to import data incrementally (optional) The previous section introduces how to import all the history data from MySQL to TiDB using mydumper/loader. But this is not applicable if the data in MySQL is updated after the migration and it is expected to import the updated data quickly.Therefore, TiDB provides the syncer tool for an incremental data import from MySQL to TiDB.See Download the TiDB enterprise toolset to download the syncer tool.Download the TiDB enterprise toolset (Linux) # Download the enterprise tool package. wget http://download.pingcap.org/tidb-enterprise-tools-latest-linux-amd64.tar.gz wget http://download.pingcap.org/tidb-enterprise-tools-latest-linux-amd64.sha256 # Check the file integrity. If the result is OK, the file is correct. sha256sum -c tidb-enterprise-tools-latest-linux-amd64.sha256 # Extract the package. tar -xzf tidb-enterprise-tools-latest-linux-amd64.tar.gz cd tidb-enterprise-tools-latest-linux-amd64 Assuming the data from t1 and t2 is already imported to TiDB using mydumper/loader. Now we hope that any updates to these two tables are synchronized to TiDB in real time.Obtain the position to synchronize The data exported from MySQL contains a metadata file which includes the position information. Take the following metadata information as an example:Started dump at: 2017-04-28 10:48:10 SHOW MASTER STATUS: Log: mysql-bin.000003 Pos: 930143241 GTID: Finished dump at: 2017-04-28 10:48:11 The position information (Pos: 930143241) needs to be stored in the syncer.meta file for syncer to synchronize:# cat syncer.meta binlog-name = "mysql-bin.000003" binlog-pos = 930143241 Note: The syncer.meta file only needs to be configured once when it is first used. The position will be automatically updated when binlog is synchronized. Start syncer The config.toml file for syncer:log-level = "info" server-id = 101 # The file path for meta: meta = "./syncer.meta" worker-count = 16 batch = 10 # The testing address for pprof. It can also be used by Prometheus to pull the syncer metrics. status-addr = ":10081" skip-sqls = ["ALTER USER", "CREATE USER"] # Support whitelist filter. You can specify the database and table to be synchronized. For example: # Synchronize all the tables of db1 and db2: replicate-do-db = ["db1","db2"] # Synchronize db1.table1. [[replicate-do-table]] db-name ="db1" tbl-name = "table1" # Synchronize db3.table2. [[replicate-do-table]] db-name ="db3" tbl-name = "table2" # Support regular expressions. Start with '~' to use regular expressions. # To synchronize all the databases that start with `test`: replicate-do-db = ["~^test.*"] # The sharding synchronizing rules support wildcharacter. # 1. The asterisk character (*, also called "star") matches zero or more characters, # for example, "doc*" matches "doc" and "document" but not "dodo"; # asterisk character must be in the end of the wildcard word, # and there is only one asterisk in one wildcard word. # 2. The question mark ? matches exactly one character. #[[route-rules]] #pattern-schema = "route_*" #pattern-table = "abc_*" #target-schema = "route" #target-table = "abc" #[[route-rules]] #pattern-schema = "route_*" #pattern-table = "xyz_*" #target-schema = "route" #target-table = "xyz" [from] host = "127.0.0.1" user = "root" password = "" port = 3306 [to] host = "127.0.0.1" user = "root" password = "" port = 4000 Start syncer:./bin/syncer -config config.toml 2016/10/27 15:22:01 binlogsyncer.go:226: [info] begin to sync binlog from position (mysql-bin.000003, 1280) 2016/10/27 15:22:01 binlogsyncer.go:130: [info] register slave for master server 127.0.0.1:3306 2016/10/27 15:22:01 binlogsyncer.go:552: [info] rotate to (mysql-bin.000003, 1280) 2016/10/27 15:22:01 syncer.go:549: [info] rotate binlog to (mysql-bin.000003, 1280) Insert data into MySQL INSERT INTO t1 VALUES (4, 4), (5, 5); Log in TiDB and view the data mysql -h127.0.0.1 -P4000 -uroot -p mysql> select * from t1; +----+------+ | id | age | +----+------+ | 1 | 1 | | 2 | 2 | | 3 | 3 | | 4 | 4 | | 5 | 5 | +----+------+ syncer outputs the current synchronized data statistics every 30 seconds:2017/06/08 01:18:51 syncer.go:934: [info] [syncer]total events = 15, total tps = 130, recent tps = 4, master-binlog = (ON.000001, 11992), master-binlog-gtid=53ea0ed1-9bf8-11e6-8bea-64006a897c73:1-74, syncer-binlog = (ON.000001, 2504), syncer-binlog-gtid = 53ea0ed1-9bf8-11e6-8bea-64006a897c73:1-17 2017/06/08 01:19:21 syncer.go:934: [info] [syncer]total events = 15, total tps = 191, recent tps = 2, master-binlog = …"}, {"url": "https://pingcap.com/docs/op-guide/migration-overview/", "title": "Migration Overview", "content": " Migration Overview Overview This document describes how to migrate data from MySQL to TiDB in detail.See the following for the assumed MySQL and TiDB server information: Name Address Port User Password MySQL 127.0.0.1 3306 root * TiDB 127.0.0.1 4000 root * Scenarios To import all the history data. This needs the following tools: Checker: to check if the schema is compatible with TiDB. Mydumper: to export data from MySQL. Loader: to import data to TiDB. To incrementally synchronize data after all the history data is imported. This needs the following tools: Checker: to check if the schema is compatible with TiDB. Mydumper: to export data from MySQL. Loader: to import data to TiDB. Syncer: to incrementally synchronize data from MySQL to TiDB. Note: To incrementally synchronize data from MySQL to TiDB, the binary logging (binlog) must be enabled and must use the row format in MySQL. Enable binary logging (binlog) in MySQL Before using the syncer tool, make sure: Binlog is enabled in MySQL. See Setting the Replication Master Configuration. Binlog must use the row format which is the recommended binlog format in MySQL 5.7. It can be configured using the following statement:SET GLOBAL binlog_format = ROW; Use the checker tool to check the schema Before migrating, you can use the checker tool in TiDB to check if TiDB supports the table schema of the data to be migrated. If the checker fails to check a certain table schema, it means that the table is not currently supported by TiDB and therefore the data in the table cannot be migrated.See Download the TiDB toolset to download the checker tool.Download the TiDB toolset (Linux) # Download the tool package. wget http://download.pingcap.org/tidb-enterprise-tools-latest-linux-amd64.tar.gz wget http://download.pingcap.org/tidb-enterprise-tools-latest-linux-amd64.sha256 # Check the file integrity. If the result is OK, the file is correct. sha256sum -c tidb-enterprise-tools-latest-linux-amd64.sha256 # Extract the package. tar -xzf tidb-enterprise-tools-latest-linux-amd64.tar.gz cd tidb-enterprise-tools-latest-linux-amd64 A sample to use the checker tool Create several tables in the test database in MySQL and insert data.USE test; CREATE TABLE t1 (id INT, age INT, PRIMARY KEY(id)) ENGINE=InnoDB; CREATE TABLE t2 (id INT, name VARCHAR(256), PRIMARY KEY(id)) ENGINE=InnoDB; INSERT INTO t1 VALUES (1, 1), (2, 2), (3, 3); INSERT INTO t2 VALUES (1, "a"), (2, "b"), (3, "c"); Use the checker tool to check all the tables in the test database../bin/checker -host 127.0.0.1 -port 3306 -user root test 2016/10/27 13:11:49 checker.go:48: [info] Checking database test 2016/10/27 13:11:49 main.go:37: [info] Database DSN: root:@tcp(127.0.0.1:3306)/test?charset=utf8 2016/10/27 13:11:49 checker.go:63: [info] Checking table t1 2016/10/27 13:11:49 checker.go:69: [info] Check table t1 succ 2016/10/27 13:11:49 checker.go:63: [info] Checking table t2 2016/10/27 13:11:49 checker.go:69: [info] Check table t2 succ Use the checker tool to check one of the tables in the test database.Note: Assuming you need to migrate the t1 table only in this sample../bin/checker -host 127.0.0.1 -port 3306 -user root test t1 2016/10/27 13:13:56 checker.go:48: [info] Checking database test 2016/10/27 13:13:56 main.go:37: [info] Database DSN: root:@tcp(127.0.0.1:3306)/test?charset=utf8 2016/10/27 13:13:56 checker.go:63: [info] Checking table t1 2016/10/27 13:13:56 checker.go:69: [info] Check table t1 succ Check database succ! A sample of a table that cannot be migrated Create the following t_error table in MySQL:CREATE TABLE t_error ( a INT NOT NULL, PRIMARY KEY (a)) ENGINE=InnoDB TABLESPACE ts1 PARTITION BY RANGE (a) PARTITIONS 3 ( PARTITION P1 VALUES LESS THAN (2), PARTITION P2 VALUES LESS THAN (4) TABLESPACE ts2, PARTITION P3 VALUES LESS THAN (6) TABLESPACE ts3); Use the checker tool to check the table. If the following error is displayed, the t_error table cannot be migrated../bin/checker -host 127.0.0.1 -port 3306 -user root test t_error 2017/08/04 11:14:35 checker.go:48: [info] Checking database test 2017/08/04 11:14:35 main.go:39: [info] Database DSN: root:@tcp(127.0.0.1:3306)/test?charset=utf8 2017/08/04 11:14:35 checker.go:63: [info] Checking table t1 2017/08/04 11:14:35 checker.go:67: [error] Check table t1 failed with err: line 3 column 29 near " ENGINE=InnoDB DEFAULT CHARSET=latin1 /*!50100 PARTITION BY RANGE (a) (PARTITION P1 VALUES LESS THAN (2) ENGINE = InnoDB, PARTITION P2 VALUES LESS THAN (4) TABLESPACE = ts2 ENGINE = InnoDB, PARTITION P3 VALUES LESS THAN (6) TABLESPACE = ts3 ENGINE = InnoDB) */" (total length 354) github.com/pingcap/tidb/parser/yy_parser.go:96: github.com/pingcap/tidb/parser/yy_parser.go:109: /home/jenkins/workspace/build_tidb_tools_master/go/src/github.com/pingcap/tidb-tools/checker/checker.go:122: parse CREATE TABLE `t1` ( `a` int(11) NOT NULL, PRIMARY KEY (`a`) ) /*!50100 TABLESPACE ts1 */ ENGINE=InnoDB DEFAULT CHARSET=latin1 /*!50100 PARTITION BY RANGE (a) (PARTITION P1 VALUES LESS THAN (2) ENGINE = InnoDB, PARTITION P2 VALUES LESS THAN (4) TABLESPACE = ts2 ENGINE = InnoDB, PARTITION P3 VALUES LESS THAN (6) TABLESPACE = ts3 ENGINE = InnoDB) */ error /home/jenkins/workspace/build_tidb_tools_master/go/src/github.com/pingcap/tidb-tools/checker/checker.go:114: 2017/08/04 11:14:35 main.go:83: [error] Check database test with 1 errors and 0 warnings. "}, {"url": "https://pingcap.com/docs/v1.0/op-guide/migration-overview/", "title": "Migration Overview", "content": " Migration Overview Overview This document describes how to migrate data from MySQL to TiDB in detail.See the following for the assumed MySQL and TiDB server information: Name Address Port User Password MySQL 127.0.0.1 3306 root * TiDB 127.0.0.1 4000 root * Scenarios To import all the history data. This needs the following tools: Checker: to check if the shema is compatible with TiDB. Mydumper: to export data from MySQL. Loader: to import data to TiDB. To incrementally synchronise data after all the history data is imported. This needs the following tools: Checker: to check if the shema is compatible with TiDB. Mydumper: to export data from MySQL. Loader: to import data to TiDB. Syncer: to incrementally synchronize data from MySQL to TiDB. Note: To incrementally synchronize data from MySQL to TiDB, the binary logging (binlog) must be enabled and must use the row format in MySQL. Enable binary logging (binlog) in MySQL Before using the syncer tool, make sure: + Binlog is enabled in MySQL. See Setting the Replication Master Configuration. Binlog must use the row format which is the recommended binlog format in MySQL 5.7. It can be configured using the following statement:SET GLOBAL binlog_format = ROW; Use the checker tool to check the schema Before migrating, you can use the checker tool in TiDB to check if TiDB supports the table schema of the data to be migrated. If the checker fails to check a certain table schema, it means that the table is not currently supported by TiDB and therefore the data in the table cannot be migrated.See Download the TiDB toolset to download the checker tool.Download the TiDB toolset (Linux) # Download the tool package. wget http://download.pingcap.org/tidb-enterprise-tools-latest-linux-amd64.tar.gz wget http://download.pingcap.org/tidb-enterprise-tools-latest-linux-amd64.sha256 # Check the file integrity. If the result is OK, the file is correct. sha256sum -c tidb-enterprise-tools-latest-linux-amd64.sha256 # Extract the package. tar -xzf tidb-enterprise-tools-latest-linux-amd64.tar.gz cd tidb-enterprise-tools-latest-linux-amd64 A sample to use the checker tool Create several tables in the test database in MySQL and insert data.USE test; CREATE TABLE t1 (id INT, age INT, PRIMARY KEY(id)) ENGINE=InnoDB; CREATE TABLE t2 (id INT, name VARCHAR(256), PRIMARY KEY(id)) ENGINE=InnoDB; INSERT INTO t1 VALUES (1, 1), (2, 2), (3, 3); INSERT INTO t2 VALUES (1, "a"), (2, "b"), (3, "c"); Use the checker tool to check all the tables in the test database../bin/checker -host 127.0.0.1 -port 3306 -user root test 2016/10/27 13:11:49 checker.go:48: [info] Checking database test 2016/10/27 13:11:49 main.go:37: [info] Database DSN: root:@tcp(127.0.0.1:3306)/test?charset=utf8 2016/10/27 13:11:49 checker.go:63: [info] Checking table t1 2016/10/27 13:11:49 checker.go:69: [info] Check table t1 succ 2016/10/27 13:11:49 checker.go:63: [info] Checking table t2 2016/10/27 13:11:49 checker.go:69: [info] Check table t2 succ Use the checker tool to check one of the tables in the test database.Note: Assuming you need to migrate the t1 table only in this sample../bin/checker -host 127.0.0.1 -port 3306 -user root test t1 2016/10/27 13:13:56 checker.go:48: [info] Checking database test 2016/10/27 13:13:56 main.go:37: [info] Database DSN: root:@tcp(127.0.0.1:3306)/test?charset=utf8 2016/10/27 13:13:56 checker.go:63: [info] Checking table t1 2016/10/27 13:13:56 checker.go:69: [info] Check table t1 succ Check database succ! A sample of a table that cannot be migrated Create the following t_error table in MySQL:CREATE TABLE t_error ( a INT NOT NULL, PRIMARY KEY (a)) ENGINE=InnoDB TABLESPACE ts1 PARTITION BY RANGE (a) PARTITIONS 3 ( PARTITION P1 VALUES LESS THAN (2), PARTITION P2 VALUES LESS THAN (4) TABLESPACE ts2, PARTITION P3 VALUES LESS THAN (6) TABLESPACE ts3); Use the checker tool to check the table. If the following error is displayed, the t_error table cannot be migrated../bin/checker -host 127.0.0.1 -port 3306 -user root test t_error 2017/08/04 11:14:35 checker.go:48: [info] Checking database test 2017/08/04 11:14:35 main.go:39: [info] Database DSN: root:@tcp(127.0.0.1:3306)/test?charset=utf8 2017/08/04 11:14:35 checker.go:63: [info] Checking table t1 2017/08/04 11:14:35 checker.go:67: [error] Check table t1 failed with err: line 3 column 29 near " ENGINE=InnoDB DEFAULT CHARSET=latin1 /*!50100 PARTITION BY RANGE (a) (PARTITION P1 VALUES LESS THAN (2) ENGINE = InnoDB, PARTITION P2 VALUES LESS THAN (4) TABLESPACE = ts2 ENGINE = InnoDB, PARTITION P3 VALUES LESS THAN (6) TABLESPACE = ts3 ENGINE = InnoDB) */" (total length 354) github.com/pingcap/tidb/parser/yy_parser.go:96: github.com/pingcap/tidb/parser/yy_parser.go:109: /home/jenkins/workspace/build_tidb_tools_master/go/src/github.com/pingcap/tidb-tools/checker/checker.go:122: parse CREATE TABLE `t1` ( `a` int(11) NOT NULL, PRIMARY KEY (`a`) ) /*!50100 TABLESPACE ts1 */ ENGINE=InnoDB DEFAULT CHARSET=latin1 /*!50100 PARTITION BY RANGE (a) (PARTITION P1 VALUES LESS THAN (2) ENGINE = InnoDB, PARTITION P2 VALUES LESS THAN (4) TABLESPACE = ts2 ENGINE = InnoDB, PARTITION P3 VALUES LESS THAN (6) TABLESPACE = ts3 ENGINE = InnoDB) */ error /home/jenkins/workspace/build_tidb_tools_master/go/src/github.com/pingcap/tidb-tools/checker/checker.go:114: 2017/08/04 11:14:35 main.go:83: [error] Check database test with 1 errors and 0 warnings. "}, {"url": "https://pingcap.com/docs/v2.0/op-guide/migration-overview/", "title": "Migration Overview", "content": " Migration Overview Overview This document describes how to migrate data from MySQL to TiDB in detail.See the following for the assumed MySQL and TiDB server information: Name Address Port User Password MySQL 127.0.0.1 3306 root * TiDB 127.0.0.1 4000 root * Scenarios To import all the history data. This needs the following tools: Checker: to check if the shema is compatible with TiDB. Mydumper: to export data from MySQL. Loader: to import data to TiDB. To incrementally synchronise data after all the history data is imported. This needs the following tools: Checker: to check if the shema is compatible with TiDB. Mydumper: to export data from MySQL. Loader: to import data to TiDB. Syncer: to incrementally synchronize data from MySQL to TiDB. Note: To incrementally synchronize data from MySQL to TiDB, the binary logging (binlog) must be enabled and must use the row format in MySQL. Enable binary logging (binlog) in MySQL Before using the syncer tool, make sure: + Binlog is enabled in MySQL. See Setting the Replication Master Configuration. Binlog must use the row format which is the recommended binlog format in MySQL 5.7. It can be configured using the following statement:SET GLOBAL binlog_format = ROW; Use the checker tool to check the schema Before migrating, you can use the checker tool in TiDB to check if TiDB supports the table schema of the data to be migrated. If the checker fails to check a certain table schema, it means that the table is not currently supported by TiDB and therefore the data in the table cannot be migrated.See Download the TiDB toolset to download the checker tool.Download the TiDB toolset (Linux) # Download the tool package. wget http://download.pingcap.org/tidb-enterprise-tools-latest-linux-amd64.tar.gz wget http://download.pingcap.org/tidb-enterprise-tools-latest-linux-amd64.sha256 # Check the file integrity. If the result is OK, the file is correct. sha256sum -c tidb-enterprise-tools-latest-linux-amd64.sha256 # Extract the package. tar -xzf tidb-enterprise-tools-latest-linux-amd64.tar.gz cd tidb-enterprise-tools-latest-linux-amd64 A sample to use the checker tool Create several tables in the test database in MySQL and insert data.USE test; CREATE TABLE t1 (id INT, age INT, PRIMARY KEY(id)) ENGINE=InnoDB; CREATE TABLE t2 (id INT, name VARCHAR(256), PRIMARY KEY(id)) ENGINE=InnoDB; INSERT INTO t1 VALUES (1, 1), (2, 2), (3, 3); INSERT INTO t2 VALUES (1, "a"), (2, "b"), (3, "c"); Use the checker tool to check all the tables in the test database../bin/checker -host 127.0.0.1 -port 3306 -user root test 2016/10/27 13:11:49 checker.go:48: [info] Checking database test 2016/10/27 13:11:49 main.go:37: [info] Database DSN: root:@tcp(127.0.0.1:3306)/test?charset=utf8 2016/10/27 13:11:49 checker.go:63: [info] Checking table t1 2016/10/27 13:11:49 checker.go:69: [info] Check table t1 succ 2016/10/27 13:11:49 checker.go:63: [info] Checking table t2 2016/10/27 13:11:49 checker.go:69: [info] Check table t2 succ Use the checker tool to check one of the tables in the test database.Note: Assuming you need to migrate the t1 table only in this sample../bin/checker -host 127.0.0.1 -port 3306 -user root test t1 2016/10/27 13:13:56 checker.go:48: [info] Checking database test 2016/10/27 13:13:56 main.go:37: [info] Database DSN: root:@tcp(127.0.0.1:3306)/test?charset=utf8 2016/10/27 13:13:56 checker.go:63: [info] Checking table t1 2016/10/27 13:13:56 checker.go:69: [info] Check table t1 succ Check database succ! A sample of a table that cannot be migrated Create the following t_error table in MySQL:CREATE TABLE t_error ( a INT NOT NULL, PRIMARY KEY (a)) ENGINE=InnoDB TABLESPACE ts1 PARTITION BY RANGE (a) PARTITIONS 3 ( PARTITION P1 VALUES LESS THAN (2), PARTITION P2 VALUES LESS THAN (4) TABLESPACE ts2, PARTITION P3 VALUES LESS THAN (6) TABLESPACE ts3); Use the checker tool to check the table. If the following error is displayed, the t_error table cannot be migrated../bin/checker -host 127.0.0.1 -port 3306 -user root test t_error 2017/08/04 11:14:35 checker.go:48: [info] Checking database test 2017/08/04 11:14:35 main.go:39: [info] Database DSN: root:@tcp(127.0.0.1:3306)/test?charset=utf8 2017/08/04 11:14:35 checker.go:63: [info] Checking table t1 2017/08/04 11:14:35 checker.go:67: [error] Check table t1 failed with err: line 3 column 29 near " ENGINE=InnoDB DEFAULT CHARSET=latin1 /*!50100 PARTITION BY RANGE (a) (PARTITION P1 VALUES LESS THAN (2) ENGINE = InnoDB, PARTITION P2 VALUES LESS THAN (4) TABLESPACE = ts2 ENGINE = InnoDB, PARTITION P3 VALUES LESS THAN (6) TABLESPACE = ts3 ENGINE = InnoDB) */" (total length 354) github.com/pingcap/tidb/parser/yy_parser.go:96: github.com/pingcap/tidb/parser/yy_parser.go:109: /home/jenkins/workspace/build_tidb_tools_master/go/src/github.com/pingcap/tidb-tools/checker/checker.go:122: parse CREATE TABLE `t1` ( `a` int(11) NOT NULL, PRIMARY KEY (`a`) ) /*!50100 TABLESPACE ts1 */ ENGINE=InnoDB DEFAULT CHARSET=latin1 /*!50100 PARTITION BY RANGE (a) (PARTITION P1 VALUES LESS THAN (2) ENGINE = InnoDB, PARTITION P2 VALUES LESS THAN (4) TABLESPACE = ts2 ENGINE = InnoDB, PARTITION P3 VALUES LESS THAN (6) TABLESPACE = ts3 ENGINE = InnoDB) */ error /home/jenkins/workspace/build_tidb_tools_master/go/src/github.com/pingcap/tidb-tools/checker/checker.go:114: 2017/08/04 11:14:35 main.go:83: [error] Check database test with 1 errors and 0 warnings. "}, {"url": "https://pingcap.com/tidb-academy/mysql_dbas/upgrades/migration/", "title": "Migrations", "content": " Migrations Resources ProxySQL mirroring pt-upgrade Transcript A migration is similar to an upgrade, in that it typically happens on a less sensitive timeframe, but also in that as well as bringing great new features; there is a higher chance there may be performance or functionality regressions.When we talk about performance in a very broad sense, with users interacting with databases, they tend to feel the variance and not the mean. Let me explain this with an example:Your application consists of 20 queries and 15 of those 20 actually have a performance improvement after the migration. On average, and on aggregate performance is better!But that might not be good enough, since 2 of those queries now perform far worse!Can you see the dilemma?Those two queries were a critical path for a set of users and they are now intolerably worse. Telling them that most users will see a performance improvement is more likely to start a fight than give them any reassurance.So as part of your upgrade: you want to try and find a way to identify those two queries. What are they? Can they be improved with the use of indexes? If we can’t use indexes, do we need to use an optimizer hint to force a particular execution plan?You get the picture. What would be really helpful is if there was an automated tool to detect differences between two systems. And there are such tools!Because TiDB speaks the MySQL protocol, another side benefit is you benefit from the tools ecosystem surrounding the MySQL Server. So for example, you can use ProxySQL to mirror queries between a MySQL system and a TiDB system, or pt-upgrade to replay a slow query log and compare both results and timing between two systems.I will link to both tools then in the resources section for this video."}, {"url": "https://pingcap.com/tidb-planet/milestones/", "title": "Milestones", "content": ""}, {"url": "https://pingcap.com/docs/sql/miscellaneous-functions/", "title": "Miscellaneous Functions", "content": " Miscellaneous Functions Name Description ANY_VALUE() Suppress ONLY_FULL_GROUP_BY value rejection SLEEP() Sleep for a number of seconds UUID() Return a Universal Unique Identifier (UUID) VALUES() Defines the values to be used during an INSERT INET_ATON() Return the numeric value of an IP address INET_NTOA() Return the IP address from a numeric value INET6_ATON() Return the numeric value of an IPv6 address INET6_NTOA() Return the IPv6 address from a numeric value IS_IPV4() Whether argument is an IPv4 address IS_IPV4_COMPAT() Whether argument is an IPv4-compatible address IS_IPV4_MAPPED() Whether argument is an IPv4-mapped address IS_IPV6() Whether argument is an IPv6 address GET_LOCK() Get a named lock RELEASE_LOCK() Releases the named lock "}, {"url": "https://pingcap.com/docs/v1.0/sql/miscellaneous-functions/", "title": "Miscellaneous Functions", "content": " Miscellaneous Functions Name Description ANY_VALUE() Suppress ONLY_FULL_GROUP_BY value rejection SLEEP() Sleep for a number of seconds UUID() Return a Universal Unique Identifier (UUID) VALUES() Defines the values to be used during an INSERT INET_ATON() Return the numeric value of an IP address INET_NTOA() Return the IP address from a numeric value INET6_ATON() Return the numeric value of an IPv6 address INET6_NTOA() Return the IPv6 address from a numeric value IS_IPV4() Whether argument is an IPv4 address IS_IPV4_COMPAT() Whether argument is an IPv4-compatible address IS_IPV4_MAPPED() Whether argument is an IPv4-mapped address IS_IPV6() Whether argument is an IPv6 address GET_LOCK() Get a named lock RELEASE_LOCK() Releases the named lock "}, {"url": "https://pingcap.com/docs/v2.0/sql/miscellaneous-functions/", "title": "Miscellaneous Functions", "content": " Miscellaneous Functions Name Description ANY_VALUE() Suppress ONLY_FULL_GROUP_BY value rejection SLEEP() Sleep for a number of seconds UUID() Return a Universal Unique Identifier (UUID) VALUES() Defines the values to be used during an INSERT INET_ATON() Return the numeric value of an IP address INET_NTOA() Return the IP address from a numeric value INET6_ATON() Return the numeric value of an IPv6 address INET6_NTOA() Return the IPv6 address from a numeric value IS_IPV4() Whether argument is an IPv4 address IS_IPV4_COMPAT() Whether argument is an IPv4-compatible address IS_IPV4_MAPPED() Whether argument is an IPv4-mapped address IS_IPV6() Whether argument is an IPv6 address GET_LOCK() Get a named lock RELEASE_LOCK() Releases the named lock "}, {"url": "https://pingcap.com/docs/op-guide/monitor/", "title": "Monitor a TiDB Cluster", "content": " Monitor a TiDB Cluster Currently there are two types of interfaces to monitor the state of the TiDB cluster: Using the HTTP interface to get the internal information of a component, which is called the component state interface. Using Prometheus to record the detailed information of the various operations in the components, which is called the Metrics interface. The component state interface You can use this type of interface to monitor the basic information of the component. This interface can act as the interface to monitor Keepalive. In addition, the interface of the Placement Driver (PD) can get the details of the entire TiKV cluster.TiDB server The TiDB API address: http://${host}:${port}The default port: 10080For all api_name details, see TiDB HTTP API.In the following example, http://${host}:${port}/status is used to get the current TiDB server state and to determine whether the server is alive. The result is returned in the JSON format.curl http://127.0.0.1:10080/status { connections: 0, version: "5.5.31-TiDB-1.0", git_hash: "b99521846ff6f71f06e2d49a3f98fa1c1d93d91b" } In this example, connections: the current number of clients connected to the TiDB server version: the TiDB version number git_hash: the Git Hash of the current TiDB code PD server The PD API address: http://${host}:${port}/pd/api/v1/${api_name}The default port: 2379See PD API doc for detailed information about various API names.The interface can be used to get the state of all the TiKV servers and the information about load balancing. It is the most important and frequently-used interface to get the state information of all the TiKV nodes. See the following example for the information about a single-node TiKV cluster:curl http://127.0.0.1:2379/pd/api/v1/stores { "count": 1 // the number of the TiKV node "stores": [ // the list of the TiKV node // the detailed information about the single TiKV node { "store": { "id": 1, "address": "127.0.0.1:22161", "state": 0 }, "status": { "store_id": 1, // the ID of the node "capacity": 1968874332160, // the total capacity "available": 1264847716352, // the available capacity "region_count": 1, // the count of Regions in this node "sending_snap_count": 0, "receiving_snap_count": 0, "start_ts": "2016-10-24T19:54:00.110728339+08:00", // the starting timestamp "last_heartbeat_ts": "2016-10-25T10:52:54.973669928+08:00", // the timestamp of the last heartbeat "total_region_count": 1, // the count of the total Regions "leader_region_count": 1, // the count of the Leader Regions "uptime": "14h58m54.862941589s" }, "scores": [ 100, 35 ] } ] } The metrics interface You can use this type of interface to monitor the state and performance of the entire cluster. The metrics data is displayed in Prometheus and Grafana. See Use Prometheus and Grafana for how to set up the monitoring system.You can get the following metrics for each component:TiDB server query processing time to monitor the latency and throughput the DDL process monitoring TiKV client related monitoring PD client related monitoring PD server the total number of times that the command executes the total number of times that a certain command fails the duration that a command succeeds the duration that a command fails the duration that a command finishes and returns result TiKV server Garbage Collection (GC) monitoring the total number of times that the TiKV command executes the duration that Scheduler executes commands the total number of times of the Raft propose command the duration that Raft executes commands the total number of times that Raft commands fail the total number of times that Raft processes the ready state Use Prometheus and Grafana The deployment architecture See the following diagram for the deployment architecture: Note: You must add the Prometheus Pushgateway addresses to the startup parameters of the TiDB, PD and TiKV components. Set up the monitoring system See the following links for your reference: Prometheus Pushgateway: https://github.com/prometheus/pushgateway Prometheus Server: https://github.com/prometheus/prometheus#install Grafana: http://docs.grafana.org Configuration Configure TiDB, PD and TiKV TiDB: Set the two parameters: --metrics-addr and --metrics-interval. Set the Pushgateway address as the --metrics-addr parameter. Set the push frequency as the --metrics-interval parameter. The unit is s, and the default value is 15. PD: update the toml configuration file with the Pushgateway address and the push frequency:[metric] # Prometheus client push interval, set "0s" to disable prometheus. interval = "15s" # Prometheus Pushgateway address, leaves it empty will disable prometheus. address = "host:port" TiKV: update the toml configuration file with the Pushgateway address and the the push frequency. Set the job field as “tikv”.[metric] # the Prometheus client push interval. Setting the value to 0s stops Prometheus client from pushing. interval = "15s" # the Prometheus Pushgateway address. Leaving it empty stops Prometheus client from pushing. address = "host:port" # the Prometheus client push job name. Note: A node id will automatically append, e.g., "tikv_1". job = "tikv" Configure PushServer Generally, it does not need to be configured. You can use the default port: 9091.Configure Prometheus Add the Pushgateway address to the yaml configuration file:scrape_configs: # The job name is added as a label `job=<job_name>` to any timeseries scraped from this config. - job_name: 'TiDB' # Override the global default and scrape targets from this job every 5 seconds. scrape_interval: 5s honor_labels: true static_configs: - targets: ['host:port'] # use the Pushgateway address labels: group: 'production' Configure Grafana Create a Prometheus data source Login the Grafana Web interface. The default address is: http://localhost:3000 The default account name: admin The password for the default account: admin Click the Grafana logo to open the sidebar menu. Click “Data Sources” in the sidebar. Click “Add data source”. Specify the data source information: Specify the name for the data source. For Type, select Prometheus. For Url, specify the Prometheus address. Specify other fields as needed. Click “Add” to save the new data source. Create a Grafana dashboard Click the Grafana logo to open the sidebar menu. On the sidebar menu, click “Dashboards” -> “Import” to open the “Import Dashboard” window. Click “Upload .json File” to upload a JSON file (Download TiDB Grafana Config). Click “Save & Open”. A Prometheus dashboard is created. "}, {"url": "https://pingcap.com/docs/v1.0/op-guide/monitor/", "title": "Monitor a TiDB Cluster", "content": " Monitor a TiDB Cluster Currently there are two types of interfaces to monitor the state of the TiDB cluster: Using the HTTP interface to get the internal information of a component, which is called the component state interface. Using Prometheus to record the detailed information of the various operations in the components, which is called the Metrics interface. The component state interface You can use this type of interface to monitor the basic information of the component. This interface can act as the interface to monitor Keepalive. In addition, the interface of the Placement Driver (PD) can get the details of the entire TiKV cluster.TiDB server The HTTP interface of TiDB is: http://host:port/statusThe default port number is: 10080 which can be set using the --status flag.The interface can be used to get the current TiDB server state and to determine whether the server is alive. The result is returned in the following JSON format:curl http://127.0.0.1:10080/status { connections: 0, version: "5.5.31-TiDB-1.0", git_hash: "b99521846ff6f71f06e2d49a3f98fa1c1d93d91b" } In this example, connection: the current number of clients connected to the TiDB server version: the TiDB version number git_hash: the Git Hash of the current TiDB code PD server The API address of PD is: http://${host}:${port}/pd/api/v1/${api_name}The default port number is: 2379.See PD API doc for detailed information about various API names.The interface can be used to get the state of all the TiKV servers and the information about load balancing. It is the most important and frequently-used interface to get the state information of all the TiKV nodes. See the following example for the the information about a single-node TiKV cluster:curl http://127.0.0.1:2379/pd/api/v1/stores { "count": 1 // the number of the TiKV node "stores": [ // the list of the TiKV node // the detailed information about the single TiKV node { "store": { "id": 1, "address": "127.0.0.1:22161", "state": 0 }, "status": { "store_id": 1, // the ID of the node "capacity": 1968874332160, // the total capacity "available": 1264847716352, // the available capacity "region_count": 1, // the count of Regions in this node "sending_snap_count": 0, "receiving_snap_count": 0, "start_ts": "2016-10-24T19:54:00.110728339+08:00", // the starting timestamp "last_heartbeat_ts": "2016-10-25T10:52:54.973669928+08:00", // the timestamp of the last heartbeat "total_region_count": 1, // the count of the total Regions "leader_region_count": 1, // the count of the Leader Regions "uptime": "14h58m54.862941589s" }, "scores": [ 100, 35 ] } ] } The metrics interface You can use this type of interface to monitor the state and performance of the entire cluster. The metrics data is displayed in Prometheus and Grafana. See Use Prometheus and Grafana for how to set up the monitoring system.You can get the following metrics for each component:TiDB server query processing time to monitor the latency and throughput the DDL process monitoring TiKV client related monitoring PD client related monitoring PD server the total number of times that the command executes the total number of times that a certain command fails the duration that a command succeeds the duration that a command fails the duration that a command finishes and returns result TiKV server Garbage Collection (GC) monitoring the total number of times that the TiKV command executes the duration that Scheduler executes commands the total number of times of the Raft propose command the duration that Raft executes commands the total number of times that Raft commands fail the total number of times that Raft processes the ready state Use Prometheus and Grafana The deployment architecture See the following diagram for the deployment architecture: Note: You must add the Prometheus Pushgateway addresses to the startup parameters of the TiDB, PD and TiKV components. Set up the monitoring system See the following links for your reference: Prometheus Push Gateway: https://github.com/prometheus/pushgateway Prometheus Server: https://github.com/prometheus/prometheus#install Grafana: http://docs.grafana.org Configuration Configure TiDB, PD and TiKV TiDB: Set the two parameters: --metrics-addr and --metrics-interval. Set the Push Gateway address as the --metrics-addr parameter. Set the push frequency as the --metrics-interval parameter. The unit is s, and the default value is 15. PD: update the toml configuration file with the Push Gateway address and the the push frequency:[metric] # prometheus client push interval, set "0s" to disable prometheus. interval = "15s" # prometheus pushgateway address, leaves it empty will disable prometheus. address = "host:port" TiKV: update the toml configuration file with the Push Gateway address and the the push frequency. Set the job field as “tikv”.[metric] # the Prometheus client push interval. Setting the value to 0s stops Prometheus client from pushing. interval = "15s" # the Prometheus pushgateway address. Leaving it empty stops Prometheus client from pushing. address = "host:port" # the Prometheus client push job name. Note: A node id will automatically append, e.g., "tikv_1". job = "tikv" Configure PushServer Generally, it does not need to be configured. You can use the default port: 9091.Configure Prometheus Add the Push Gateway address to the yaml configuration file:scrape_configs: # The job name is added as a label `job=<job_name>` to any timeseries scraped from this config. - job_name: 'TiDB' # Override the global default and scrape targets from this job every 5 seconds. scrape_interval: 5s honor_labels: true static_configs: - targets: ['host:port'] # use the Push Gateway address labels: group: 'production' Configure Grafana Create a Prometheus data source Login the Grafana Web interface. The default address is: http://localhost:3000 The default account name: admin The password for the default account: admin Click the Grafana logo to open the sidebar menu. Click “Data Sources” in the sidebar. Click “Add data source”. Specify the data source information: Specify the name for the data source. For Type, select Prometheus. For Url, specify the Prometheus address. Specify other fields as needed. Click “Add” to save the new data source. Create a Grafana dashboard Click the Grafana logo to open the sidebar menu. On the sidebar menu, click “Dashboards” -> “Import” to open the “Import Dashboard” window. Click “Upload .json File” to upload a JSON file ( Download TiDB Grafana Config ). Click “Save & Open”. A Prometheus dashboard is created. "}, {"url": "https://pingcap.com/docs/v2.0/op-guide/monitor/", "title": "Monitor a TiDB Cluster", "content": " Monitor a TiDB Cluster Currently there are two types of interfaces to monitor the state of the TiDB cluster: Using the HTTP interface to get the internal information of a component, which is called the component state interface. Using Prometheus to record the detailed information of the various operations in the components, which is called the Metrics interface. The component state interface You can use this type of interface to monitor the basic information of the component. This interface can act as the interface to monitor Keepalive. In addition, the interface of the Placement Driver (PD) can get the details of the entire TiKV cluster.TiDB server The HTTP interface of TiDB is: http://host:port/statusThe default port number is: 10080 which can be set using the --status flag.The interface can be used to get the current TiDB server state and to determine whether the server is alive. The result is returned in the following JSON format:curl http://127.0.0.1:10080/status { connections: 0, version: "5.5.31-TiDB-1.0", git_hash: "b99521846ff6f71f06e2d49a3f98fa1c1d93d91b" } In this example, connection: the current number of clients connected to the TiDB server version: the TiDB version number git_hash: the Git Hash of the current TiDB code PD server The API address of PD is: http://${host}:${port}/pd/api/v1/${api_name}The default port number is: 2379.See PD API doc for detailed information about various API names.The interface can be used to get the state of all the TiKV servers and the information about load balancing. It is the most important and frequently-used interface to get the state information of all the TiKV nodes. See the following example for the the information about a single-node TiKV cluster:curl http://127.0.0.1:2379/pd/api/v1/stores { "count": 1 // the number of the TiKV node "stores": [ // the list of the TiKV node // the detailed information about the single TiKV node { "store": { "id": 1, "address": "127.0.0.1:22161", "state": 0 }, "status": { "store_id": 1, // the ID of the node "capacity": 1968874332160, // the total capacity "available": 1264847716352, // the available capacity "region_count": 1, // the count of Regions in this node "sending_snap_count": 0, "receiving_snap_count": 0, "start_ts": "2016-10-24T19:54:00.110728339+08:00", // the starting timestamp "last_heartbeat_ts": "2016-10-25T10:52:54.973669928+08:00", // the timestamp of the last heartbeat "total_region_count": 1, // the count of the total Regions "leader_region_count": 1, // the count of the Leader Regions "uptime": "14h58m54.862941589s" }, "scores": [ 100, 35 ] } ] } The metrics interface You can use this type of interface to monitor the state and performance of the entire cluster. The metrics data is displayed in Prometheus and Grafana. See Use Prometheus and Grafana for how to set up the monitoring system.You can get the following metrics for each component:TiDB server query processing time to monitor the latency and throughput the DDL process monitoring TiKV client related monitoring PD client related monitoring PD server the total number of times that the command executes the total number of times that a certain command fails the duration that a command succeeds the duration that a command fails the duration that a command finishes and returns result TiKV server Garbage Collection (GC) monitoring the total number of times that the TiKV command executes the duration that Scheduler executes commands the total number of times of the Raft propose command the duration that Raft executes commands the total number of times that Raft commands fail the total number of times that Raft processes the ready state Use Prometheus and Grafana The deployment architecture See the following diagram for the deployment architecture: Note: You must add the Prometheus Pushgateway addresses to the startup parameters of the TiDB, PD and TiKV components. Set up the monitoring system See the following links for your reference: Prometheus Push Gateway: https://github.com/prometheus/pushgateway Prometheus Server: https://github.com/prometheus/prometheus#install Grafana: http://docs.grafana.org Configuration Configure TiDB, PD and TiKV TiDB: Set the two parameters: --metrics-addr and --metrics-interval. Set the Push Gateway address as the --metrics-addr parameter. Set the push frequency as the --metrics-interval parameter. The unit is s, and the default value is 15. PD: update the toml configuration file with the Push Gateway address and the the push frequency:[metric] # prometheus client push interval, set "0s" to disable prometheus. interval = "15s" # prometheus pushgateway address, leaves it empty will disable prometheus. address = "host:port" TiKV: update the toml configuration file with the Push Gateway address and the the push frequency. Set the job field as “tikv”.[metric] # the Prometheus client push interval. Setting the value to 0s stops Prometheus client from pushing. interval = "15s" # the Prometheus pushgateway address. Leaving it empty stops Prometheus client from pushing. address = "host:port" # the Prometheus client push job name. Note: A node id will automatically append, e.g., "tikv_1". job = "tikv" Configure PushServer Generally, it does not need to be configured. You can use the default port: 9091.Configure Prometheus Add the Push Gateway address to the yaml configuration file:scrape_configs: # The job name is added as a label `job=<job_name>` to any timeseries scraped from this config. - job_name: 'TiDB' # Override the global default and scrape targets from this job every 5 seconds. scrape_interval: 5s honor_labels: true static_configs: - targets: ['host:port'] # use the Push Gateway address labels: group: 'production' Configure Grafana Create a Prometheus data source Login the Grafana Web interface. The default address is: http://localhost:3000 The default account name: admin The password for the default account: admin Click the Grafana logo to open the sidebar menu. Click “Data Sources” in the sidebar. Click “Add data source”. Specify the data source information: Specify the name for the data source. For Type, select Prometheus. For Url, specify the Prometheus address. Specify other fields as needed. Click “Add” to save the new data source. Create a Grafana dashboard Click the Grafana logo to open the sidebar menu. On the sidebar menu, click “Dashboards” -> “Import” to open the “Import Dashboard” window. Click “Upload .json File” to upload a JSON file ( Download TiDB Grafana Config ). Click “Save & Open”. A Prometheus dashboard is created. "}, {"url": "https://pingcap.com/tidb-academy/mysql_dbas/monitoring/overview/", "title": "Monitoring", "content": " Monitoring Resources Raft Consensus Transcript In this section we are going to cover two topics which often get grouped together. Monitoring is about detecting problems and anomalies. Observability is about looking into the system and being able to see how it operates. Most systems can be monitored, but not all are necessarily designed to be observed. If we use a microscope as an analogy, observability is the slide.So let’s take a look at monitoring first. With all the components of TiDB being highly available, there is clearly monitoring happening somewhere.For both the PD server and TiKV servers, high availability is provided by Raft consensus. The Raft group uses a minimum of 3 nodes, so that a leader can be elected without a split-vote occurring. I will link to a description of the algorithm in Wikipedia in the resources, but we can say that the cluster components themselves provide high availability.The TiDB server has no state or concept of membership, so it does not require Raft for high availability. Instead, it relies on Kubernetes to provide it with replicas, and a tcp load balancer to route clients to a healthy server. Unhealthy servers can be replaced quickly without moving data around.So the takeaways for monitoring are: Always ensure that there are three or more instances of PD and TiKV. It is also recommended that the number of instances be an odd number so that a split-vote does not occur. In the next video we will talk about instrumentation with Prometheus and Grafana."}, {"url": "https://pingcap.com/tidb-academy/mysql_dbas/mysql-compatibility/overview/", "title": "MySQL Compatibility", "content": " MySQL Compatibility Resources MySQL Compatibility TiDB Roadmap Transcript What does it mean to be compatible with MySQL? First, I think it is important to clarify that MySQL is a moving target, as newer versions are released, new features will be added, and existing features may change slightly. In some specific cases, features may also be removed. For example, in MySQL 8.0, weaker crypto functions like ENCODE/DECODE were removed and this has been previously deprecated.In TiDB’s case, MySQL compatibility means MySQL 5.7, and this is true for both the network protocol and raw SQL syntax. That means that you can connect to TiDB using a MySQL driver (like JDBC, PHP, Python) and your application sees only MySQL. Most of the queries that your application(s) run will also continue to work without requiring any code changes.But there are exceptions, starting with MySQL 5.7 functionality not supported by TiDB. Let’s take a look at the list: Stored procedures and functions Views Triggers Events User-defined functions FOREIGN KEY constraints FULLTEXT indexes SPATIAL indexes Character sets other than utf8 Add primary key Drop primary key SYS schema Optimizer trace If the lack of one of these features impacts your usage of TiDB, I recommend reading the roadmap to find features which are planned to be added.In the next video, let’s go through a case rather than a feature being missing from TiDB, which behaves differently."}, {"url": "https://pingcap.com/docs-cn/sql/literal-value-null-values/", "title": "NULL Values", "content": " NULL Values NULL 代表数据为空,它是大小写不敏感的,与 N(大小写敏感) 同义。需要注意的是 NULL 跟 0 并不一样,跟空字符串 '' 也不一样。"}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/literal-value-null-values/", "title": "NULL Values", "content": " NULL Values NULL 代表数据为空,它是大小写不敏感的,与 N(大小写敏感) 同义。需要注意的是 NULL 跟 0 并不一样,跟空字符串 '' 也不一样。"}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/literal-value-null-values/", "title": "NULL Values", "content": " NULL Values NULL 代表数据为空,它是大小写不敏感的,与 N(大小写敏感) 同义。需要注意的是 NULL 跟 0 并不一样,跟空字符串 '' 也不一样。"}, {"url": "https://pingcap.com/news/", "title": "News", "content": ""}, {"url": "https://pingcap.com/docs/sql/numeric-functions-and-operators/", "title": "Numeric Functions and Operators", "content": " Numeric Functions and Operators This document describes the arithmetic operators and mathematical functions.Arithmetic operators Name Description + Addition operator - Minus operator * Multiplication operator / Division operator DIV Integer division %, MOD Modulo operator - Change the sign of the argument Mathematical functions Name Description POW() Return the argument raised to the specified power POWER() Return the argument raised to the specified power EXP() Raise to the power of SQRT() Return the square root of the argument LN() Return the natural logarithm of the argument LOG() Return the natural logarithm of the first argument LOG2() Return the base-2 logarithm of the argument LOG10() Return the base-10 logarithm of the argument PI() Return the value of pi TAN() Return the tangent of the argument COT() Return the cotangent SIN() Return the sine of the argument COS() Return the cosine ATAN() Return the arc tangent ATAN2(), ATAN() Return the arc tangent of the two arguments ASIN() Return the arc sine ACOS() Return the arc cosine RADIANS() Return argument converted to radians DEGREES() Convert radians to degrees MOD() Return the remainder ABS() Return the absolute value CEIL() Return the smallest integer value not less than the argument CEILING() Return the smallest integer value not less than the argument FLOOR() Return the largest integer value not greater than the argument ROUND() Round the argument RAND() Return a random floating-point value SIGN() Return the sign of the argument CONV() Convert numbers between different number bases TRUNCATE() Truncate to specified number of decimal places CRC32() Compute a cyclic redundancy check value "}, {"url": "https://pingcap.com/docs/v1.0/sql/numeric-functions-and-operators/", "title": "Numeric Functions and Operators", "content": " Numeric Functions and Operators Arithmetic operators Name Description + Addition operator - Minus operator * Multiplication operator / Division operator DIV Integer division %, MOD Modulo operator - Change the sign of the argument Mathematical functions Name Description POW() Return the argument raised to the specified power POWER() Return the argument raised to the specified power EXP() Raise to the power of SQRT() Return the square root of the argument LN() Return the natural logarithm of the argument LOG() Return the natural logarithm of the first argument LOG2() Return the base-2 logarithm of the argument LOG10() Return the base-10 logarithm of the argument PI() Return the value of pi TAN() Return the tangent of the argument COT() Return the cotangent SIN() Return the sine of the argument COS() Return the cosine ATAN() Return the arc tangent ATAN2(), ATAN() Return the arc tangent of the two arguments ASIN() Return the arc sine ACOS() Return the arc cosine RADIANS() Return argument converted to radians DEGREES() Convert radians to degrees MOD() Return the remainder ABS() Return the absolute value CEIL() Return the smallest integer value not less than the argument CEILING() Return the smallest integer value not less than the argument FLOOR() Return the largest integer value not greater than the argument ROUND() Round the argument RAND() Return a random floating-point value SIGN() Return the sign of the argument CONV() Convert numbers between different number bases TRUNCATE() Truncate to specified number of decimal places CRC32() Compute a cyclic redundancy check value "}, {"url": "https://pingcap.com/docs/v2.0/sql/numeric-functions-and-operators/", "title": "Numeric Functions and Operators", "content": " Numeric Functions and Operators This document describes the arithmetic operators and mathematical functions.Arithmetic operators Name Description + Addition operator - Minus operator * Multiplication operator / Division operator DIV Integer division %, MOD Modulo operator - Change the sign of the argument Mathematical functions Name Description POW() Return the argument raised to the specified power POWER() Return the argument raised to the specified power EXP() Raise to the power of SQRT() Return the square root of the argument LN() Return the natural logarithm of the argument LOG() Return the natural logarithm of the first argument LOG2() Return the base-2 logarithm of the argument LOG10() Return the base-10 logarithm of the argument PI() Return the value of pi TAN() Return the tangent of the argument COT() Return the cotangent SIN() Return the sine of the argument COS() Return the cosine ATAN() Return the arc tangent ATAN2(), ATAN() Return the arc tangent of the two arguments ASIN() Return the arc sine ACOS() Return the arc cosine RADIANS() Return argument converted to radians DEGREES() Convert radians to degrees MOD() Return the remainder ABS() Return the absolute value CEIL() Return the smallest integer value not less than the argument CEILING() Return the smallest integer value not less than the argument FLOOR() Return the largest integer value not greater than the argument ROUND() Round the argument RAND() Return a random floating-point value SIGN() Return the sign of the argument CONV() Convert numbers between different number bases TRUNCATE() Truncate to specified number of decimal places CRC32() Compute a cyclic redundancy check value "}, {"url": "https://pingcap.com/docs-cn/sql/literal-value-numeric-literals/", "title": "Numeric Literals", "content": " Numeric Literals 数值字面值包括 integer 跟 Decimal 类型跟浮点数字面值。integer 可以包括 . 作为小数点分隔,数字前可以有 - 或者 + 来表示正数或者负数。精确数值字面值可以表示为如下格式:1, .2, 3.4, -5, -6.78, +9.10.科学记数法也是被允许的,表示为如下格式:1.2E3, 1.2E-3, -1.2E3, -1.2E-3。更多细节"}, {"url": "https://pingcap.com/recruit-cn/engineering/olap-engineer/", "title": "OLAP 引擎研发工程师", "content": " OLAP 引擎研发工程师 岗位职责: 负责分布式数据库底层系统存储系统的设计和开发; (可选)指导新人,进行代码和设计审核; (可选)参与和负责数据库计算层的设计和开发。 任职要求: 三年以上相关领域开发经验,扎实的编程能力,熟悉 C/C++; 对分布式存储系统的架构和原理有比较深入的了解; 熟悉开源分布式文件系统如 Ceph/HDFS/GlusterFS 等,或 NoSQL 数据库如 Kudu/Cassandra/HBase 等其中的至少一个,并阅读过源代码; 熟悉分布式系统的性能分析; 优秀的发现和解决问题能力,良好的沟通能力,具备团队合作精神。 加分项: 拥抱开源,对前沿技术有浓厚的热情和探索欲望,有开源项目经历; 熟悉分布式计算引擎或数据库,例如 Spark/Greenplumn/Clickhouse,并阅读过其中的源码; 熟悉分布式系统性能调优。 待遇:25K - 50K + 期权,13薪 + 奖金,优秀者可面议工作地点:北京,上海,广州,杭州,成都,特别优秀可 Remote"}, {"url": "https://pingcap.com/recruit-cn/campus/campus-2019-ops-engineer/", "title": "OPS Engineer", "content": " 数据库工程师 岗位职责: 负责对客户进行 TiDB 项目实施、技术支持,包括配置管理、升级、扩容、备份、数据迁移等工作; 负责用户 TiDB 集群监控、故障响应、问题跟踪及性能分析处理; 负责与用户进行需求沟通、技术培训,介绍 TiDB 的原理、使用方式、最佳实践等; 研究 TiDB,对某细分方向,如 TiDB 自动化管理、SQL 优化、故障诊断等有持续产出和贡献。 任职要求: 以“折腾” Linux 为乐; 掌握一门基础编程语言,如 C/C++/Go/Rust/…… 等; 熟练掌握一门脚本语言,如 Shell/Python/Perl/…… 等; 高度的责任心、良好的沟通技巧和团队合作精神。 加分项: 拥抱开源,对前沿技术有浓厚的热情和探索欲望,有开源项目经历; 熟悉一种关系型数据库的(如 MySQL )配置、备份、优化、监控、管理; 良好的适应和学习能力对自己不设限,挑战如:数据可视化,监控告警 DevOPS,商业/工具产品设计等方向。 待遇:8K - 15K,14薪 + 奖金,优秀者可面议联系方式:hire@pingcap.com工作地点:北京"}, {"url": "https://pingcap.com/tidb-academy/mysql_dbas/monitoring/observability/", "title": "Observability", "content": " Observability Resources Prometheus Grafana Transcript If you come from a MySQL background, the built-in system for observability is performance_schema. There are some secondary observability commands, but in recent MySQL releases, this has become the gold standard.Performance Schema is implemented as a storage engine inside of MySQL. Recent MySQL servers are very well instrumented with Performance Schema too: any time the server is allocating memory, waiting on locks or performing I/O: you can query that with regular SQL and find out!There are a couple of quick drawbacks to it: Performance Schema uses memory, so metrics collected will be lost after server restart. The history retention is also limited, so on a busy server, some key metrics will be cycled out after a few minutes of activity.TiDB does not use performance_schema, and not withstanding what was just mentioned, the real key reason is because TiDB is a distributed system.Having only a single-server’s metrics in isolation is not always enough to observe the running system. And thus, TiDB servers send their metrics to a centralized database that is specifically designed for metrics collection. I am of course talking about Prometheus.If you are not yet familiar with Prometheus, it is a popular tool that along with Kubernetes and TiKV is part of the Cloud Native Compute Foundation projects. It is often used in combination with Grafana, which adds a layer of dashboards on top.All of the TiDB Platform components support Prometheus integration, and when you deploy the TiDB Platform with TiDB Operator, they will also be installed and configured out of the box. We even provide built-in Grafana charts.So in our lab, we will be logging into Grafana and observing key metrics about our TiDB Platform while we are performing operations."}, {"url": "https://pingcap.com/tidb-academy/mysql_dbas/monitoring/lab/", "title": "Observing TiDB Cluster Metrics", "content": " Observing TiDB Cluster Metrics "}, {"url": "https://pingcap.com/docs/v1.0/op-guide/offline-ansible-deployment/", "title": "Offline Deployment Using Ansible", "content": " Offline Deployment Using Ansible Prepare Before you start, make sure that you have: A download machine The machine must have access to the Internet in order to download TiDB-Ansible, TiDB and related packages. For Linux operating system, it is recommended to install CentOS 7.3 or later. Several target machines and one Control Machine For system requirements and configuration, see Prepare the environment. It is acceptable without access to the Internet. Install Ansible and dependencies in the Control Machine Install Ansible offline on the CentOS 7 system: Download the Ansible offline installation package to the Control Machine. # tar -xzvf ansible-2.4-rpms.el7.tar.gz # cd ansible-2.4-rpms.el7 # rpm -ivh PyYAML*rpm libyaml*rpm python-babel*rpm python-backports*rpm python-backports-ssl_match_hostname*rpm python-cffi*rpm python-enum34*rpm python-httplib2*rpm python-idna*rpm python-ipaddress*rpm python-jinja2*rpm python-markupsafe*rpm python-paramiko*rpm python-passlib*rpm python-ply*rpm python-pycparser*rpm python-setuptools*rpm python-six*rpm python2-cryptography*rpm python2-jmespath*rpm python2-pyasn1*rpm sshpass*rpm # rpm -ivh ansible-2.4.2.0-2.el7.noarch.rpm After Ansible is installed, you can view the version using ansible --version.# ansible --version ansible 2.4.2.0 Download TiDB-Ansible and TiDB packages on the download machine Install Ansible on the download machine.Use the following method to install Ansible online on the download machine installed with the CentOS 7 system. Installing using the EPEL source automatically installs the related Ansible dependencies (such as Jinja2==2.7.2 MarkupSafe==0.11). After Ansible is installed, you can view the version using ansible --version.# yum install epel-release # yum install ansible curl # ansible --version ansible 2.4.2.0 Note: Make sure that the version of Ansible is 2.4 or later, otherwise compatibility problem might occur. Download TiDB-Ansible.Use the following command to download the corresponding version of TiDB-Ansible from the GitHub TiDB-Ansible project. The default folder name is tidb-ansible.Download the 1.0 (GA) version:git clone -b release-1.0 https://github.com/pingcap/tidb-ansible.git ORDownload the master version:git clone https://github.com/pingcap/tidb-ansible.git Note: For production environment, download TiDB-Ansible 1.0 to deploy TiDB. Run the local_prepare.yml playbook, and download TiDB binary online to the download machine.cd tidb-ansible ansible-playbook local_prepare.yml After running the above command, copy the tidb-ansible folder to the /home/tidb directory of the Control Machine. The ownership authority of the file must be the tidb user. Orchestrate the TiDB cluster See Orchestrate the TiDB cluster.Deploy the TiDB cluster See Deploy the TiDB cluster. You do not need to run the ansible-playbook local_prepare.yml playbook again. Test the cluster See Test the cluster."}, {"url": "https://pingcap.com/tidb-academy/mysql_dbas/ddl/lab/", "title": "Online DDL", "content": " Online DDL "}, {"url": "https://pingcap.com/docs/sql/operators/", "title": "Operators", "content": " Operators This document describes the operators precedence, comparison functions and operators, logical operators, and assignment operators. Operator precedence Comparison functions and operators Logical operators Assignment operators Name Description AND, && Logical AND = Assign a value (as part of a SET statement, or as part of the SET clause in an UPDATE statement) := Assign a value BETWEEN … AND … Check whether a value is within a range of values BINARY Cast a string to a binary string & Bitwise AND ~ Bitwise inversion | Bitwise OR 0 Bitwise XOR CASE Case operator DIV Integer division / Division operator = Equal operator <=> NULL-safe equal to operator > Greater than operator >= Greater than or equal operator IS Test a value against a boolean IS NOT Test a value against a boolean IS NOT NULL NOT NULL value test IS NULL NULL value test -> Return value from JSON column after evaluating path; equivalent to JSON_EXTRACT() ->> Return value from JSON column after evaluating path and unquoting the result; equivalent to JSON_UNQUOTE(JSON_EXTRACT()) << Left shift < Less than operator <= Less than or equal operator LIKE Simple pattern matching - Minus operator %, MOD Modulo operator NOT, ! Negates value NOT BETWEEN … AND … Check whether a value is not within a range of values !=, <> Not equal operator NOT LIKE Negation of simple pattern matching NOT REGEXP Negation of REGEXP ||, OR Logical OR + Addition operator REGEXP Pattern matching using regular expressions >> Right shift RLIKE Synonym for REGEXP SOUNDS LIKE Compare sounds * Multiplication operator - Change the sign of the argument XOR Logical XOR Operator precedence Operator precedences are shown in the following list, from highest precedence to the lowest. Operators that are shown together on a line have the same precedence.INTERVAL BINARY, COLLATE ! - (unary minus), ~ (unary bit inversion) ^ *, /, DIV, %, MOD -, + <<, >> & | = (comparison), <=>, >=, >, <=, <, <>, !=, IS, LIKE, REGEXP, IN BETWEEN, CASE, WHEN, THEN, ELSE NOT AND, && XOR OR, || = (assignment), := For details, see here.Comparison functions and operators Name Description BETWEEN … AND … Check whether a value is within a range of values COALESCE() Return the first non-NULL argument = Equal operator <=> NULL-safe equal to operator > Greater than operator >= Greater than or equal operator GREATEST() Return the largest argument IN() Check whether a value is within a set of values INTERVAL() Return the index of the argument that is less than the first argument IS Test a value against a boolean IS NOT Test a value against a boolean IS NOT NULL NOT NULL value test IS NULL NULL value test ISNULL() Test whether the argument is NULL LEAST() Return the smallest argument < Less than operator <= Less than or equal operator LIKE Simple pattern matching NOT BETWEEN … AND … Check whether a value is not within a range of values !=, <> Not equal operator NOT IN() Check whether a value is not within a set of values NOT LIKE Negation of simple pattern matching STRCMP() Compare two strings For details, see here.Logical operators Name Description AND, && Logical AND NOT, ! Negates value ||, OR Logical OR XOR Logical XOR For details, see here.Assignment operators Name Description = Assign a value (as part of a SET statement, or as part of the SET clause in an UPDATE statement) := Assign a value For details, see here."}, {"url": "https://pingcap.com/docs/v2.0/sql/operators/", "title": "Operators", "content": " Operators This document describes the operators precedence, comparison functions and operators, logical operators, and assignment operators. Operator precedence Comparison functions and operators Logical operators Assignment operators Name Description AND, && Logical AND = Assign a value (as part of a SET statement, or as part of the SET clause in an UPDATE statement) := Assign a value BETWEEN … AND … Check whether a value is within a range of values BINARY Cast a string to a binary string & Bitwise AND ~ Bitwise inversion | Bitwise OR 0 Bitwise XOR CASE Case operator DIV Integer division / Division operator = Equal operator <=> NULL-safe equal to operator > Greater than operator >= Greater than or equal operator IS Test a value against a boolean IS NOT Test a value against a boolean IS NOT NULL NOT NULL value test IS NULL NULL value test -> Return value from JSON column after evaluating path; equivalent to JSON_EXTRACT() ->> Return value from JSON column after evaluating path and unquoting the result; equivalent to JSON_UNQUOTE(JSON_EXTRACT()) << Left shift < Less than operator <= Less than or equal operator LIKE Simple pattern matching - Minus operator %, MOD Modulo operator NOT, ! Negates value NOT BETWEEN … AND … Check whether a value is not within a range of values !=, <> Not equal operator NOT LIKE Negation of simple pattern matching NOT REGEXP Negation of REGEXP ||, OR Logical OR + Addition operator REGEXP Pattern matching using regular expressions >> Right shift RLIKE Synonym for REGEXP SOUNDS LIKE Compare sounds * Multiplication operator - Change the sign of the argument XOR Logical XOR Operator precedence Operator precedences are shown in the following list, from highest precedence to the lowest. Operators that are shown together on a line have the same precedence.INTERVAL BINARY, COLLATE ! - (unary minus), ~ (unary bit inversion) ^ *, /, DIV, %, MOD -, + <<, >> & | = (comparison), <=>, >=, >, <=, <, <>, !=, IS, LIKE, REGEXP, IN BETWEEN, CASE, WHEN, THEN, ELSE NOT AND, && XOR OR, || = (assignment), := For details, see here.Comparison functions and operators Name Description BETWEEN … AND … Check whether a value is within a range of values COALESCE() Return the first non-NULL argument = Equal operator <=> NULL-safe equal to operator > Greater than operator >= Greater than or equal operator GREATEST() Return the largest argument IN() Check whether a value is within a set of values INTERVAL() Return the index of the argument that is less than the first argument IS Test a value against a boolean IS NOT Test a value against a boolean IS NOT NULL NOT NULL value test IS NULL NULL value test ISNULL() Test whether the argument is NULL LEAST() Return the smallest argument < Less than operator <= Less than or equal operator LIKE Simple pattern matching NOT BETWEEN … AND … Check whether a value is not within a range of values !=, <> Not equal operator NOT IN() Check whether a value is not within a set of values NOT LIKE Negation of simple pattern matching STRCMP() Compare two strings For details, see here.Logical operators Name Description AND, && Logical AND NOT, ! Negates value ||, OR Logical OR XOR Logical XOR For details, see here.Assignment operators Name Description = Assign a value (as part of a SET statement, or as part of the SET clause in an UPDATE statement) := Assign a value For details, see here."}, {"url": "https://pingcap.com/tidb-academy/mysql_dbas/tidb-overview/optional-components-tispark/", "title": "Optional Components: TiSpark", "content": " Optional Components: TiSpark Transcript In the last video, we talked about the three core components that make up the TiDB Platform: TiKV for distributed storage The TiDB server for SQL processing PD for cluster management There is one additional component to the TiDB Platform which you can considered optional, and that’s TiSpark.TiSpark allows you to bypass the SQL layer and have Apache Spark connect to TiKV directly. Why would you want to do this? You might be running complex OLAP queries or machine learning workloads that are better suited to Spark than they are to the TiDB server.Here we can also see one of the strong benefits of TiDB using a component based architecture: you can access your data between these two systems (Spark and MySQL) without having to move data between the two. You also have a third option, which is to access your data directly with a key-value interface.The moving of data between systems is referred to as ETL, or Extract-Transform-Load. With the TiDB platform, you can run transactions and analytics at the same time, which means that any analytics you need to run on your data can be run immediately with little time delay.In industry parlance, this feature is known as running Hybrid Transaction and Analytics Processing, or HTAP. It is an emerging space, and many analysts believe that over time the convenience of being able to use one system to do both workloads will win over single purpose system (either Online Transaction Processing (OLTP) or Online Analytical Processing (OLAP)).We have a section on HTAP later in this course, where we will try and answer which queries are better suited for TiSpark versus the TiDB Server.In the mean time, to tie this back to MySQL: if you are currently using MySQL plus another system such as Hadoop, HBase or a column store, the benefit of the TiDB Platform is that you can consolidate and simplify your architecture."}, {"url": "https://pingcap.com/docs/tikv/tikv-overview/", "title": "Overview of TiKV", "content": " Overview of TiKV TiKV (The pronunciation is: /‘taɪkeɪvi:/ tai-K-V, etymology: titanium) is a distributed Key-Value database which is based on the design of Google Spanner and HBase, but it is much simpler without dependency on any distributed file system.As the storage layer of TiDB, TiKV can work separately and does not depend on the SQL layer of TiDB. To apply to different scenarios, TiKV provides two types of APIs for developers: the Raw Key-Value API and the Transactional Key-Value API.The key features of TiKV are as follows: Geo-ReplicationTiKV uses Raft and the Placement Driver to support Geo-Replication. Horizontal scalabilityWith Placement Driver and carefully designed Raft groups, TiKV excels in horizontal scalability and can easily scale to 100+ TBs of data. Consistent distributed transactionsSimilar to Google’s Spanner, TiKV supports externally-consistent distributed transactions. Coprocessor supportSimilar to HBase, TiKV implements a Coprocessor framework to support distributed computing. Cooperates with TiDBThanks to the internal optimization, TiKV and TiDB can work together to be a compelling database solution with high horizontal scalability, externally-consistent transactions, and support for RDMBS and NoSQL design patterns. Architecture The TiKV server software stack is as follows: Placement Driver: Placement Driver (PD) is the cluster manager of TiKV. PD periodically checks replication constraints to balance load and data automatically. Store: There is a RocksDB within each Store and it stores data into local disk. Region: Region is the basic unit of Key-Value data movement. Each Region is replicated to multiple Nodes. These multiple replicas form a Raft group. Node: A physical node in the cluster. Within each node, there are one or more Stores. Within each Store, there are many Regions. When a node starts, the metadata of the Node, Store and Region are recorded into PD. The status of each Region and Store is reported to PD regularly.Two types of APIs TiKV provides two types of APIs for developers: The Raw Key-Value APIIf your application scenario does not need distributed transactions or MVCC (Multi-Version Concurrency Control) and only need to guarantee the atomicity towards one key, you can use the Raw Key-Value API. The Transactional Key-Value APIIf your application scenario requires distributed ACID transactions and the atomicity of multiple keys within a transaction, you can use the Transactional Key-Value API. Compared to the Transactional Key-Value API, the Raw Key-Value API is more performant with lower latency and easier to use."}, {"url": "https://pingcap.com/docs/v2.0/tikv/tikv-overview/", "title": "Overview of TiKV", "content": " Overview of TiKV TiKV (The pronunciation is: /‘taɪkeɪvi:/ tai-K-V, etymology: titanium) is a distributed Key-Value database which is based on the design of Google Spanner and HBase, but it is much simpler without dependency on any distributed file system.As the storage layer of TiDB, TiKV can work separately and does not depend on the SQL layer of TiDB. To apply to different scenarios, TiKV provides two types of APIs for developers: the Raw Key-Value API and the Transactional Key-Value API.The key features of TiKV are as follows: Geo-ReplicationTiKV uses Raft and the Placement Driver to support Geo-Replication. Horizontal scalabilityWith Placement Driver and carefully designed Raft groups, TiKV excels in horizontal scalability and can easily scale to 100+ TBs of data. Consistent distributed transactionsSimilar to Google’s Spanner, TiKV supports externally-consistent distributed transactions. Coprocessor supportSimilar to HBase, TiKV implements a Coprocessor framework to support distributed computing. Cooperates with TiDBThanks to the internal optimization, TiKV and TiDB can work together to be a compelling database solution with high horizontal scalability, externally-consistent transactions, and support for RDMBS and NoSQL design patterns. Architecture The TiKV server software stack is as follows: Placement Driver: Placement Driver (PD) is the cluster manager of TiKV. PD periodically checks replication constraints to balance load and data automatically. Store: There is a RocksDB within each Store and it stores data into local disk. Region: Region is the basic unit of Key-Value data movement. Each Region is replicated to multiple Nodes. These multiple replicas form a Raft group. Node: A physical node in the cluster. Within each node, there are one or more Stores. Within each Store, there are many Regions. When a node starts, the metadata of the Node, Store and Region are recorded into PD. The status of each Region and Store is reported to PD regularly.Two types of APIs TiKV provides two types of APIs for developers: The Raw Key-Value APIIf your application scenario does not need distributed transactions or MVCC (Multi-Version Concurrency Control) and only need to guarantee the atomicity towards one key, you can use the Raw Key-Value API. The Transactional Key-Value APIIf your application scenario requires distributed ACID transactions and the atomicity of multiple keys within a transaction, you can use the Transactional Key-Value API. Compared to the Transactional Key-Value API, the Raw Key-Value API is more performant with lower latency and easier to use."}, {"url": "https://pingcap.com/docs/v1.0/op-guide/monitor-overview/", "title": "Overview of the TiDB Monitoring Framework", "content": " Overview of the Monitoring Framework The TiDB monitoring framework adopts two open source projects: Prometheus and Grafana. TiDB uses Prometheus to store the monitoring and performance metrics and Grafana to visualize these metrics.About Prometheus in TiDB As a time series database, Prometheus has a multi-dimensional data model and flexible query language. As one of the most popular open source projects, many companies and organizations have adopted Prometheus, and the project has a very active community. PingCAP is one of the active developers and adoptors of Prometheus for monitoring and alerting in TiDB, TiKV and PD.Prometheus consists of multiple components. Currently, TiDB uses the following of them: The Prometheus Server to scrape and store time series data. The client libraries to customize necessary metrics in the application. A push GateWay to receive the data from Client Push for the Prometheus main server. An AlertManager for the alerting mechanism. The diagram is as follows:About Grafana in TiDB Grafana is an open source project for analysing and visualizing metrics. TiDB uses Grafana to display the performance metrics as follows:"}, {"url": "https://pingcap.com/docs/v2.0/op-guide/monitor-overview/", "title": "Overview of the TiDB Monitoring Framework", "content": " Overview of the Monitoring Framework The TiDB monitoring framework adopts two open source projects: Prometheus and Grafana. TiDB uses Prometheus to store the monitoring and performance metrics and Grafana to visualize these metrics.About Prometheus in TiDB As a time series database, Prometheus has a multi-dimensional data model and flexible query language. As one of the most popular open source projects, many companies and organizations have adopted Prometheus, and the project has a very active community. PingCAP is one of the active developers and adoptors of Prometheus for monitoring and alerting in TiDB, TiKV and PD.Prometheus consists of multiple components. Currently, TiDB uses the following of them: The Prometheus Server to scrape and store time series data. The client libraries to customize necessary metrics in the application. A push GateWay to receive the data from Client Push for the Prometheus main server. An AlertManager for the alerting mechanism. The diagram is as follows:About Grafana in TiDB Grafana is an open source project for analysing and visualizing metrics. TiDB uses Grafana to display the performance metrics as follows:"}, {"url": "https://pingcap.com/docs-cn/op-guide/dashboard-overview-info/", "title": "Overview 重要监控指标详解", "content": " Overview 重要监控指标详解 使用 Ansible 部署 TiDB 集群时,一键部署监控系统 (Prometheus/Grafana),监控架构请看 TiDB 监控框架概述。目前 Grafana Dashboard 整体分为 PD、TiDB、TiKV、Node_exporter、Overview 等。对于日常运维,我们单独挑选出重要的 Metrics 放在 Overview 页面,方便日常运维人员观察集群组件 (PD, TiDB, TiKV) 使用状态以及集群使用状态。以下为 Overview Dashboard 监控说明:Services Port Status Services Online:各服务在线节点数量 Services Offline:各服务 Down 掉节点数量 PD Storage Capacity:TiDB 集群总可用数据库空间大小 Current Storage Size:TiDB 集群目前已用数据库空间大小 Number of Regions:当前集群的 Region 总量 Leader Balance Ratio:Leader 数量最多和最少节点相差的百分比,一般小于 5%,节点重启时会有比较大的波动 Region Balance Ratio:Region 数量最多和最少节点相差的百分比,一般小于 5%,新增/下线节点时相差比较大 Store Status:集群 TiKV 节点的状态 Up Stores:正常运行的 TiKV 节点数量 Disconnect Stores:短时间内通信异常的 TiKV 节点数量 LowSpace Stores:剩余可用空间小于 80% 的 TiKV 节点数量 Down Stores:停止工作的 TiKV 节点数量,如果大于 0,说明有节点不正常 Offline Stores:正在下线的 TiKV 节点数量(正在下线的 TiKV 节点还在提供服务) Tombstone Stores:下线成功的 TiKV 节点数量 99% completed_cmds_duration_seconds:单位时间内,99% 的 pd-server 请求执行时间小于监控曲线的值,一般 <= 5ms handle_requests_duration_seconds:PD 发送请求的网络耗时 TiDB Statement OPS:SQL 执行数量统计(包含 select、insert、update 等) Duration:SQL 执行的时间 QPS By Instance:每个 TiDB 上的 QPS Failed Query OPM:失败 SQL 的统计,例如语法错误、主键冲突等 Connection count:每个 TiDB 的连接数 Heap Memory Usage:每个 TiDB 使用的堆内存大小 Transaction OPS:事务执行数量统计 Transaction Duration:事务执行的时间 KV Cmd OPS:KV 命令执行数量统计 KV Cmd Duration 99:KV 命令执行的时间 PD TSO OPS:TiDB 从 PD 获取 TSO 的数量 PD TSO Wait Duration:TiDB 从 PD 获取 TS 的时间 TiClient Region Error OPS:TiKV 返回 Region 相关错误信息的数量 Lock Resolve OPS:事务冲突相关的数量 Load Schema Duration:TiDB 从 TiKV 获取 Schema 的时间 KV Backoff OPS:TiKV 返回错误信息的数量(事务冲突等) TiKV leader:各个 TiKV 节点上 Leader 的数量分布 region:各个 TiKV 节点上 Region 的数量分布 CPU:各个 TiKV 节点的 CPU 使用率 Memory:各个 TiKV 节点的内存使用量 store size:各个 TiKV 节点存储的数据量 cf size:集群不同 CF 存储的数据量 channel full:正常情况显示 No data,如果有了监控值,说明对应 TiKV 节点的消息处理不过来了 server report failures:正常情况显示 No data,如果出现了 Unreachable,说明 TiKV 之间通信有问题 scheduler pending commands:写入堆积的数量,偶尔出现峰值属于正常现象 coprocessor pending requests:正常情况监控为 0 或者数量很少 coprocessor executor count:不同类型的查询操作数量 coprocessor request duration:TiKV 中查询消耗的时间 raft store CPU:raftstore 线程的 CPU 使用率,目前为单线程,超过 80% 说明使用率很高 Coprocessor CPU:TiKV 查询线程的 CPU 使用率,和业务相关,复杂查询会使用大量的 CPU 资源 System Info Vcores:CPU 核心数量 Memory:内存总大小 CPU Usage:CPU 使用率,最大为 100% Load [1m]:1 分钟的负载情况 Memory Available:剩余内存大小 Network Traffic:网卡流量统计 TCP Retrans:网络监控,TCP 相关信息统计 IO Util:磁盘使用率,最高为 100%,一般到 80% - 90% 就需要考虑加节点 图例 "}, {"url": "https://pingcap.com/docs/tools/pd-control/", "title": "PD Control User Guide", "content": " PD Control User Guide As a command line tool of PD, PD Control obtains the state information of the cluster and tunes the cluster.Source code compiling Go Version 1.9 or later In the root directory of the PD project, use the make command to compile and generate bin/pd-ctl Note: Generally, you don’t need to compile source code as the PD Control tool already exists in the released Binary or Docker. However, dev users can refer to the above instruction for compiling source code. Usage Single-command mode:./pd-ctl store -d -u http://127.0.0.1:2379 Interactive mode:./pd-ctl -u http://127.0.0.1:2379 Use environment variables:export PD_ADDR=http://127.0.0.1:2379 ./pd-ctl Use TLS to encrypt:./pd-ctl -u https://127.0.0.1:2379 --cacert="path/to/ca" --cert="path/to/cert" --key="path/to/key" Command line flags --pd,-u PD address Default address: http://127.0.0.1:2379 Enviroment variable: PD_ADDR --detach,-d Use single command line mode (not entering readline) Default: false –cacert Specify the path to the certificate file of the trusted CA in PEM format Default: “” –cert Specify the path to the certificate of SSL in PEM format Default: “” –key Specify the path to the certificate key file of SSL in PEM format, which is the private key of the certificate specified by --cert Default: “” –version,-V Print the version information and exit Default: false Command cluster Use this command to view the basic information of the cluster.Usage:>> cluster // To show the cluster information { "id": 6493707687106161130, "max_peer_count": 3 } config [show | set <option> <value>] Use this command to view or modify the configuration information.Usage:>> config show // Display the config information of the scheduler { "max-snapshot-count": 3, "max-pending-peer-count": 16, "max-merge-region-size": 50, "max-merge-region-rows": 200000, "split-merge-interval": "1h", "patrol-region-interval": "100ms", "max-store-down-time": "1h0m0s", "leader-schedule-limit": 4, "region-schedule-limit": 4, "replica-schedule-limit":8, "merge-schedule-limit": 8, "tolerant-size-ratio": 5, "low-space-ratio": 0.8, "high-space-ratio": 0.6, "disable-raft-learner": "false", "disable-remove-down-replica": "false", "disable-replace-offline-replica": "false", "disable-make-up-replica": "false", "disable-remove-extra-replica": "false", "disable-location-replacement": "false", "disable-namespace-relocation": "false", "schedulers-v2": [ { "type": "balance-region", "args": null }, { "type": "balance-leader", "args": null }, { "type": "hot-region", "args": null } ] } >> config show all // Display all config information >> config show namespace ts1 // Display the config information of the namespace named ts1 { "leader-schedule-limit": 4, "region-schedule-limit": 4, "replica-schedule-limit": 8, "max-replicas": 3, } >> config show replication // Display the config information of replication { "max-replicas": 3, "location-labels": "" } >> config show cluster-version // Display the current version of the cluster, which is the current minimum version of TiKV nodes in the cluster and does not correspond to the binary version. "2.0.0" max-snapshot-count controls the maximum number of snapshots that a single store receives or sends out at the same time. The scheduler is restricted by this configuration to avoid taking up normal application resources. When you need to improve the speed of adding replicas or balancing, increase this value.>> config set max-snapshort-count 16 // Set the maximum number of snapshots to 16 max-pending-peer-count controls the maximum number of pending peers in a single store. The scheduler is restricted by this configuration to avoid producing a large number of Regions without the latest log in some nodes. When you need to improve the speed of adding replicas or balancing, increase this value. Setting it to 0 indicates no limit.>> config set max-pending-peer-count 64 // Set the maximum number of pending peers to 64 max-merge-region-size controls the upper limit on the size of Region Merge (the unit is M). When regionSize exceeds the specified value, PD does not merge it with the adjacent Region. Setting it to 0 indicates disabling Region Merge.>> config set max-merge-region-size 16 // Set the upper limit on the size of Region Merge to 16M max-merge-region-rows controls the upper limit on the row count of Region Merge. When regionRowCount exceeds the specified value, PD does not merge it with the adjacent Region.>> config set max-merge-region-rows 50000 // Set the the upper limit on rowCount to 50000 split-merge-interval controls the interval between the split and merge operations on a same Region. This means the newly split Region won’t be merged within a period of time.>> config set split-merge-interval 24h // Set the interval between `split` and `merge` to one day patrol-region-interval controls the execution frequency that replicaChecker checks the health status of Regions. A shorter interval indicates a higher execution frequency. Generally, you do not need to adjust it.>> config set patrol-region-interval 10ms // Set the execution frequency of replicaChecker to 10ms max-store-down-time controls the time that PD decides the disconnected store cannot be restored if exceeded. If PD does not receive heartbeats from a store within the specified period of time, PD adds replicas in other nodes.>> config set max-store-down-time 30m // Set the time within which PD receives no heartbeats and after which PD starts to add replicas to 30 minutes leader-schedule-limit controls the number of tasks scheduling the leader at the same time. This value affects the speed of leader balance. A larger value means a higher speed and setting the value to 0 closes the scheduling. Usually the leader scheduling has a small load, and you can increase the value in need.>> config set leader-schedule-limit 4 // 4 tasks of leader scheduling at the same time at most region-schedule-limit controls the number of tasks scheduling the Region at the same time. This value affects the speed of Region balance. A larger value means a higher speed and setting the value to 0 closes the scheduling. Usually the Region scheduling has a large load, so do not set a too large value.>> config set region-schedule-limit 2 // 2 tasks of Region scheduling at the same time at most replica-schedule-limit controls the number of tasks scheduling the replica at the same time. This value affects the scheduling speed when the node is down or removed. A larger value means a higher speed and setting the value to 0 closes the scheduling. Usually the replica scheduling has a large load, so do not set a too large value.>> config set replica-schedule-limit 4 // 4 tasks of replica scheduling at the same time at most merge-schedule-limit controls the number of Region Merge scheduling tasks. Setting the value to 0 closes Region Merge. Usually the Merge scheduling has a large load, so do not set a too large value.>> config set merge-schedule-limit 16 // 16 tasks of Merge scheduling at the same time at most The configuration above is global. You can also tune the configuration by configuring different namespaces. The global configuration is used if the corresponding configuration of the namespace is not set. Note: The configuration of the namespace only supports editing leader-schedule-limit, region-schedule-limit, replica-schedule-limit and …"}, {"url": "https://pingcap.com/docs/v1.0/tools/pd-control/", "title": "PD Control User Guide", "content": " PD Control User Guide As a command line tool of PD, PD Control obtains the state information of the cluster and tunes the cluster.Source code compiling Go Version 1.7 or later In the PD root directory, use the make command to compile and generate bin/pd-ctl Note: Generally, you don’t need to compile source code as the PD Control tool already exists in the released Binary or Docker. However, dev users can refer to the above instruction for compiling source code. Usage Single-command mode:./pd-ctl store -d -u http://127.0.0.1:2379 Interactive mode:./pd-ctl -u http://127.0.0.1:2379 Use environment variables:export PD_ADDR=http://127.0.0.1:2379 ./pd-ctl Use TLS to encrypt:./pd-ctl -u https://127.0.0.1:2379 --cacert="path/to/ca" --cert="path/to/cert" --key="path/to/key" Command line flags --pd,-u PD address Default address: http://127.0.0.1:2379 Enviroment variable: PD_ADDR --detach,-d Use single command line mode (not entering readline) Default: false –cacert Specify the path to the certificate file of the trusted CA in PEM format Default: “” –cert Specify the path to the certificate of SSL in PEM format Default: “” –key Specify the path to the certificate key file of SSL in PEM format, which is the private key of the certificate specified by --cert Default: “” –version,-V Print the version information and exit Default: false Command cluster Use this command to view the basic information of the cluster.Usage:>> cluster // To show the cluster information { "id": 6493707687106161130, "max_peer_count": 3 } config [show | set <option> <value>] Use this command to view or modify the configuration information.Usage:>> config show // Display the config information of the scheduler { "max-snapshot-count": 3, "max-pending-peer-count": 16, "max-store-down-time": "1h0m0s", "leader-schedule-limit": 64, "region-schedule-limit": 16, "replica-schedule-limit": 24, "tolerant-size-ratio": 2.5, "schedulers-v2": [ { "type": "balance-region", "args": null }, { "type": "balance-leader", "args": null }, { "type": "hot-region", "args": null } ] } >> config show all // Display all config information >> config show namespace ts1 // Display the config information of the namespace named ts1 { "leader-schedule-limit": 64, "region-schedule-limit": 16, "replica-schedule-limit": 24, "max-replicas": 3, } >> config show replication // Display the config information of replication { "max-replicas": 3, "location-labels": "" } leader-schedule-limit controls the number of tasks scheduling the leader at the same time. This value affects the speed of leader balance. A larger value means a higher speed and setting the value to 0 closes the scheduling. Usually the leader scheduling has a small load, and you can increase the value in need.>> config set leader-schedule-limit 4 // 4 tasks of leader scheduling at the same time at most region-schedule-limit controls the number of tasks scheduling the region at the same time. This value affects the speed of region balance. A larger value means a higher speed and setting the value to 0 closes the scheduling. Usually the region scheduling has a large load, so do not set a too large value.>> config set region-schedule-limit 2 // 2 tasks of region scheduling at the same time at most replica-schedule-limit controls the number of tasks scheduling the replica at the same time. This value affects the scheduling speed when the node is down or removed. A larger value means a higher speed and setting the value to 0 closes the scheduling. Usually the replica scheduling has a large load, so do not set a too large value.>> config set replica-schedule-limit 4 // 4 tasks of replica scheduling at the same time at most The configuration above is global. You can also tune the configuration by configuring different namespaces. The global configuration is used if the corresponding configuration of the namespace is not set. Note: The configuration of the namespace only supports editing leader-schedule-limit, region-schedule-limit, replica-schedule-limit and max-replicas. ```bash >> config set namespace ts1 leader-schedule-limit 4 // 4 tasks of leader scheduling at the same time at most for the namespace named ts1 >> config set namespace ts2 region-schedule-limit 2 // 2 tasks of region scheduling at the same time at most for the namespace named ts2 ``` config delete namespace <name> [<option>] Use this command to delete the configuration of namespace.Usage:After you configure the namespace, if you want it to continue to use global configuration, delete the configuration information of the namespace using the following command:>> config delete namespace ts1 // Delete the configuration of the namespace named ts1 If you want to use global configuration only for a certain configuration of the namespace, use the following command:>> config delete namespace region-schedule-limit ts2 // Delete the region-schedule-limit configuration of the namespace named ts2 health Use this command to view the health information of the cluster.Usage:>> health // Display the health information {"health": "true"} hot [read | write | store] Use this command to view the hot spot information of the cluster.Usage:>> hot read // Display hot spot for the read operation >> hot write // Display hot spot for the write operation >> hot store // Display hot spot for all the read and write operations label [store] Use this command to view the label information of the cluster.Usage:>> label // Display all labels >> label store zone cn // Display all stores including the "zone":"cn" label member [leader | delete] Use this command to view the PD members or remove a specified member.Usage:>> member // Display the information of all members { "members": [......] } >> member leader show // Display the information of the leader { "name": "pd", "addr": "http://192.168.199.229:2379", "id": 9724873857558226554 } >> member delete name pd2 // Delete "pd2" Success! >> member delete id 1319539429105371180 // Delete a node using id Success! operator [show | add | remove] Use this command to view and control the scheduling operation.Usage:>> operator show // Display all operators >> operator show admin // Display all admin operators >> operator show leader // Display all leader operators >> operator show region // Display all region operators >> operator add add-peer 1 2 // Add a replica of region 1 on store 2 >> operator remove remove-peer 1 2 // Remove a replica of region 1 on store 2 >> operator add transfer-leader 1 2 // Schedule the leader of region 1 to store 2 >> operator add transfer-region 1 2 3 4 // Schedule region 1 to store 2,3,4 >> operator add transfer-peer 1 2 3 // Schedule the replica of region 1 on store 2 to store 3 >> operator remove 1 // Remove the scheduling operation of region 1 ping Use this command to view the time that ping PD takes.Usage:>> ping time: 43.12698ms region <region_id> Use this command to view the region information.Usage:>> region // Display the information of all regions { "count": 1, "regions": [......] } >> region 2 // Display the information of the region with the id of 2 { "region": { "id": 2, ...... } "leader": { ...... } } region key [--format=raw|pb|proto|protobuf] <key> Use this command to query the region that a specific key resides in. It supports the raw and protobuf formats.Raw format …"}, {"url": "https://pingcap.com/docs/v2.0/tools/pd-control/", "title": "PD Control User Guide", "content": " PD Control User Guide As a command line tool of PD, PD Control obtains the state information of the cluster and tunes the cluster.Source code compiling Go Version 1.9 or later In the root directory of the PD project, use the make command to compile and generate bin/pd-ctl Note: Generally, you don’t need to compile source code as the PD Control tool already exists in the released Binary or Docker. However, dev users can refer to the above instruction for compiling source code. Usage Single-command mode:./pd-ctl store -d -u http://127.0.0.1:2379 Interactive mode:./pd-ctl -u http://127.0.0.1:2379 Use environment variables:export PD_ADDR=http://127.0.0.1:2379 ./pd-ctl Use TLS to encrypt:./pd-ctl -u https://127.0.0.1:2379 --cacert="path/to/ca" --cert="path/to/cert" --key="path/to/key" Command line flags --pd,-u PD address Default address: http://127.0.0.1:2379 Enviroment variable: PD_ADDR --detach,-d Use single command line mode (not entering readline) Default: false –cacert Specify the path to the certificate file of the trusted CA in PEM format Default: “” –cert Specify the path to the certificate of SSL in PEM format Default: “” –key Specify the path to the certificate key file of SSL in PEM format, which is the private key of the certificate specified by --cert Default: “” –version,-V Print the version information and exit Default: false Command cluster Use this command to view the basic information of the cluster.Usage:>> cluster // To show the cluster information { "id": 6493707687106161130, "max_peer_count": 3 } config [show | set <option> <value>] Use this command to view or modify the configuration information.Usage:>> config show // Display the config information of the scheduler { "max-snapshot-count": 3, "max-pending-peer-count": 16, "max-merge-region-size": 50, "max-merge-region-rows": 200000, "split-merge-interval": "1h", "patrol-region-interval": "100ms", "max-store-down-time": "1h0m0s", "leader-schedule-limit": 4, "region-schedule-limit": 4, "replica-schedule-limit":8, "merge-schedule-limit": 8, "tolerant-size-ratio": 5, "low-space-ratio": 0.8, "high-space-ratio": 0.6, "disable-raft-learner": "false", "disable-remove-down-replica": "false", "disable-replace-offline-replica": "false", "disable-make-up-replica": "false", "disable-remove-extra-replica": "false", "disable-location-replacement": "false", "disable-namespace-relocation": "false", "schedulers-v2": [ { "type": "balance-region", "args": null }, { "type": "balance-leader", "args": null }, { "type": "hot-region", "args": null } ] } >> config show all // Display all config information >> config show namespace ts1 // Display the config information of the namespace named ts1 { "leader-schedule-limit": 4, "region-schedule-limit": 4, "replica-schedule-limit": 8, "max-replicas": 3, } >> config show replication // Display the config information of replication { "max-replicas": 3, "location-labels": "" } >> config show cluster-version // Display the current version of the cluster, which is the current minimum version of TiKV nodes in the cluster and does not correspond to the binary version. "2.0.0" max-snapshot-count controls the maximum number of snapshots that a single store receives or sends out at the same time. The scheduler is restricted by this configuration to avoid taking up normal application resources. When you need to improve the speed of adding replicas or balancing, increase this value.>> config set max-snapshort-count 16 // Set the maximum number of snapshots to 16 max-pending-peer-count controls the maximum number of pending peers in a single store. The scheduler is restricted by this configuration to avoid producing a large number of Regions without the latest log in some nodes. When you need to improve the speed of adding replicas or balancing, increase this value. Setting it to 0 indicates no limit.>> config set max-pending-peer-count 64 // Set the maximum number of pending peers to 64 max-merge-region-size controls the upper limit on the size of Region Merge (the unit is M). When regionSize exceeds the specified value, PD does not merge it with the adjacent Region. Setting it to 0 indicates disabling Region Merge.>> config set max-merge-region-size 16 // Set the upper limit on the size of Region Merge to 16M max-merge-region-rows controls the upper limit on the row count of Region Merge. When regionRowCount exceeds the specified value, PD does not merge it with the adjacent Region.>> config set max-merge-region-rows 50000 // Set the the upper limit on rowCount to 50000 split-merge-interval controls the interval between the split and merge operations on a same Region. This means the newly split Region won’t be merged within a period of time.>> config set split-merge-interval 24h // Set the interval between `split` and `merge` to one day patrol-region-interval controls the execution frequency that replicaChecker checks the health status of Regions. A shorter interval indicates a higher execution frequency. Generally, you do not need to adjust it.>> config set patrol-region-interval 10ms // Set the execution frequency of replicaChecker to 10ms max-store-down-time controls the time that PD decides the disconnected store cannot be restored if exceeded. If PD does not receive heartbeats from a store within the specified period of time, PD adds replicas in other nodes.>> config set max-store-down-time 30m // Set the time within which PD receives no heartbeats and after which PD starts to add replicas to 30 minutes leader-schedule-limit controls the number of tasks scheduling the leader at the same time. This value affects the speed of leader balance. A larger value means a higher speed and setting the value to 0 closes the scheduling. Usually the leader scheduling has a small load, and you can increase the value in need.>> config set leader-schedule-limit 4 // 4 tasks of leader scheduling at the same time at most region-schedule-limit controls the number of tasks scheduling the Region at the same time. This value affects the speed of Region balance. A larger value means a higher speed and setting the value to 0 closes the scheduling. Usually the Region scheduling has a large load, so do not set a too large value.>> config set region-schedule-limit 2 // 2 tasks of Region scheduling at the same time at most replica-schedule-limit controls the number of tasks scheduling the replica at the same time. This value affects the scheduling speed when the node is down or removed. A larger value means a higher speed and setting the value to 0 closes the scheduling. Usually the replica scheduling has a large load, so do not set a too large value.>> config set replica-schedule-limit 4 // 4 tasks of replica scheduling at the same time at most merge-schedule-limit controls the number of Region Merge scheduling tasks. Setting the value to 0 closes Region Merge. Usually the Merge scheduling has a large load, so do not set a too large value.>> config set merge-schedule-limit 16 // 16 tasks of Merge scheduling at the same time at most The configuration above is global. You can also tune the configuration by configuring different namespaces. The global configuration is used if the corresponding configuration of the namespace is not set. Note: The configuration of the namespace only supports editing leader-schedule-limit, region-schedule-limit, replica-schedule-limit and …"}, {"url": "https://pingcap.com/docs-cn/tools/pd-control/", "title": "PD Control 使用说明", "content": " PD Control 使用说明 PD Control 是 PD 的命令行工具,用于获取集群状态信息和调整集群。源码编译 Go Version 1.9 以上 在 PD 项目根目录使用 make 命令进行编译,生成 bin/pd-ctl 简单例子 单命令模式:./pd-ctl store -d -u http://127.0.0.1:2379 交互模式:./pd-ctl -u http://127.0.0.1:2379 使用环境变量:export PD_ADDR=http://127.0.0.1:2379 ./pd-ctl 使用TLS加密:./pd-ctl -u https://127.0.0.1:2379 --cacert="path/to/ca" --cert="path/to/cert" --key="path/to/key" 命令行参数(flags) --pd,-u 指定 PD 的地址 默认地址: http://127.0.0.1:2379 环境变量: PD_ADDR --detach,-d 使用单命令行模式(不进入 readline) 默认值: false –cacert 指定 PEM 格式的受信任 CA 的证书文件路径 默认值: “” –cert 指定 PEM 格式的 SSL 证书文件路径 默认值: “” –key 指定 PEM 格式的 SSL 证书密钥文件路径,即 --cert 所指定的证书的私钥 默认值: “” –version,-V 打印版本信息并退出 默认值: false 命令(command) cluster 用于显示集群基本信息。示例:>> cluster // 显示 cluster 的信息 { "id": 6493707687106161130, "max_peer_count": 3 } config [show | set ] 用于显示或调整配置信息。示例:>> config show // 显示 scheduler 的相关 config 信息 { "max-snapshot-count": 3, "max-pending-peer-count": 16, "max-merge-region-size": 50, "max-merge-region-rows": 200000, "split-merge-interval": "1h", "patrol-region-interval": "100ms", "max-store-down-time": "1h0m0s", "leader-schedule-limit": 4, "region-schedule-limit": 4, "replica-schedule-limit":8, "merge-schedule-limit": 8, "tolerant-size-ratio": 5, "low-space-ratio": 0.8, "high-space-ratio": 0.6, "disable-raft-learner": "false", "disable-remove-down-replica": "false", "disable-replace-offline-replica": "false", "disable-make-up-replica": "false", "disable-remove-extra-replica": "false", "disable-location-replacement": "false", "disable-namespace-relocation": "false", "schedulers-v2": [ { "type": "balance-region", "args": null }, { "type": "balance-leader", "args": null }, { "type": "hot-region", "args": null } ] } >> config show all // 显示所有的 config 信息 >> config show namespace ts1 // 显示名为 ts1 的 namespace 的相关 config 信息 { "leader-schedule-limit": 4, "region-schedule-limit": 4, "replica-schedule-limit": 8, "max-replicas": 3, } >> config show replication // 显示 replication 的相关 config 信息 { "max-replicas": 3, "location-labels": "" } >> config show cluster-version // 显示目前集群版本,是目前集群 TiKV 节点的最低版本,并不对应 binary 的版本 "2.0.0" max-snapshot-count 控制单个 store 最多同时接收或发送的 snapshot 数量,调度受制于这个配置来防止抢占正常业务的资源。 当需要加快补副本或 balance 速度时可以调大这个值。>> config set max-snapshort-count 16 // 设置最大 snapshot 为 16 max-pending-peer-count 控制单个 store 的 pending peer 上限,调度受制于这个配置来防止在部分节点产生大量日志落后的 Region。 需要加快补副本或 balance 速度可以适当调大这个值,设置为 0 则表示不限制。>> config set max-pending-peer-count 64 // 设置最大 pending peer 数量为 64 max-merge-region-size 控制 Region Merge 的 size 上限(单位是 M)。 当 Region Size 大于指定值时 PD 不会将其与相邻的 Region 合并。设置为 0 表示不开启 Region Merge 功能。>> config set max-merge-region-size 16 // 设置 Region Merge 的 size 上限为 16M max-merge-region-rows 控制 Region Merge 的 rowCount 上限。 当 Region RowCount 大于指定值时 PD 不会将其与相邻的 Region 合并。>> config set max-merge-region-rows 50000 // 设置 Region Merge 的 rowCount 上限为 50k split-merge-interval 控制对同一个 Region 做 split 和 merge 操作的间隔,即对于新 split 的 Region 一段时间内不会被 merge。>> config set split-merge-interval 24h // 设置 `split` 和 `merge` 的间隔为 1 天 patrol-region-interval 控制 replicaChecker 检查 Region 健康状态的运行频率,越短则运行越快,通常状况不需要调整。>> config set patrol-region-interval 10ms // 设置 replicaChecker 的运行频率为 10ms max-store-down-time 为 PD 认为失联 store 无法恢复的时间,当超过指定的时间没有收到 store 的心跳后,PD 会在其他节点补充副本。>> config set max-store-down-time 30m // 设置 store 心跳丢失 30 分钟开始补副本 通过调整 leader-schedule-limit 可以控制同时进行 leader 调度的任务个数。 这个值主要影响 leader balance 的速度,值越大调度得越快,设置为 0 则关闭调度。 Leader 调度的开销较小,需要的时候可以适当调大。>> config set leader-schedule-limit 4 // 最多同时进行 4 个 leader 调度 通过调整 region-schedule-limit 可以控制同时进行 Region 调度的任务个数。 这个值主要影响 Region balance 的速度,值越大调度得越快,设置为 0 则关闭调度。 Region 调度的开销较大,所以这个值不宜调得太大。>> config set region-schedule-limit 2 // 最多同时进行 2 个 Region 调度 通过调整 replica-schedule-limit 可以控制同时进行 replica 调度的任务个数。 这个值主要影响节点挂掉或者下线的时候进行调度的速度,值越大调度得越快,设置为 0 则关闭调度。 Replica 调度的开销较大,所以这个值不宜调得太大。>> config set replica-schedule-limit 4 // 最多同时进行 4 个 replica 调度 merge-schedule-limit 控制同时进行的 Region Merge 调度的任务,设置为 0 则关闭 Region Merge。 Merge 调度的开销较大,所以这个值不宜调得过大。>> config set merge-schedule-limit 16 // 最多同时进行 16 个 merge 调度 以上对配置的修改是全局性的,还可以通过对不同 namespace 的配置,进行细化调整。当 namespace 未设置相应配置时,使用全局配置。注:namespace 的配置只支持对 leader-schedule-limit,region-schedule-limit,replica-schedule-limit,max-replicas 的调整,否则不生效。>> config set namespace ts1 leader-schedule-limit 4 // 设置名为 ts1 的 namespace 最多同时进行 4 个 leader 调度 >> config set namespace ts2 region-schedule-limit 2 // 设置名为 ts2 的 namespace 最多同时进行 2 个 Region 调度 tolerant-size-ratio 控制 balance 缓冲区大小。 当两个 store 的 leader 或 Region 的得分差距小于指定倍数的 Region size 时,PD 会认为此时 balance 达到均衡状态。>> config set tolerant-size-ratio 20 // 设置缓冲区为约 20 倍平均 RegionSize low-space-ratio 用于设置 store 空间不足的阈值。 当节点的空间占用比例超过指定值时,PD 会尽可能避免往对应节点迁移数据,同时主要针对剩余空间大小进行调度,避免对应节点磁盘空间被耗尽。config set low-space-ratio 0.9 // 设置空间不足阈值为 0.9 high-space-ratio 用于设置 store 空间充裕的阈值。 当节点的空间占用比例小于指定值时,PD 调度时会忽略剩余空间这个指标,主要针对实际数据量进行均衡。config set high-space-ratio 0.5 // 设置空间充裕阈值为 0.5 disable-raft-learner 用于关闭 raft learner 功能。 默认配置下 PD 在添加副本时会使用 raft learner 来降低宕机或网络故障带来的不可用风险。config set disable-raft-learner true // 关闭 raft learner 功能 cluster-version 集群的版本,用于控制某些 Feature 是否开启,处理兼容性问题。 通常是集群正常运行的所有 TiKV 节点中的最低版本,需要回滚到更低的版本时才进行手动设置。config set cluster-version 1.0.8 // 设置 cluster version 为 1.0.8 disable-remove-down-replica 用于关闭自动删除 DownReplica 的特性。 当设置为 true 时,PD 不会自动清理宕机状态的副本。disable-replace-offline-replica 用于关闭迁移 OfflineReplica 的特性。 当设置为 true 时,PD 不会迁移下线状态的副本。disable-make-up-replica 用于关闭补充副本的特性。 当设置为 true 时,PD 不会为副本数不足的 Region 补充副本。disable-remove-extra-replica 用于关闭删除多余副本的特性。 当设置为 true 时,PD 不会为副本数过多的 Region 删除多余副本。disable-location-replacement 用于关闭隔离级别检查。 当设置为 true 时,PD 不会通过调度来提升 Region 副本的隔离级别。disable-namespace-relocation 用于关闭 Region 的 namespace 调度。当设置为 true 时,PD 不会把 Region 调度到它所属的 Store 上。config delete namespace [] 用于删除 namespace 的配置信息。示例:在对 namespace 相关配置进行设置后,若想让该 namespace 继续使用全局配置,可删除该 namespace 的配置信息,之后便使用全局配置。>> config delete namespace ts1 // 删除名为 ts1 的 namespace 的相关配置 若只想让 namespace 中的某项配置使用全局配置而不影响其他配置,则可使用如下命令:>> config delete namespace region-schedule-limit ts2 // 删除名为 ts2 的 namespace 的 region-schedule-limit 配置 health 用于显示集群健康信息。示例:>> health // 显示健康信息 [ { "name": "pd", "member_id": 13195394291058371180, "client_urls": [ "http://127.0.0.1:2379" ...... ], "health": true } ...... ] hot [read | write | store] 用于显示集群热点信息。示例:>> hot read // 显示读热点信息 >> hot write // 显示写热点信息 >> hot store // 显示所有 store 的读写信息 label [store ] 用于显示集群标签信息示例:>> label // 显示所有 label >> label store zone cn // 显示所有包含 label 为 "zone":"cn" 的 store member [delete | leader_priority | leader [show | resign | transfer ]] 用于显示 PD 成员信息,删除指定成员,设置成员的 leader 优先级。示例:>> member // 显示所有成员的信息 { "members": [......], "leader": {......}, "etcd_leader": {......}, } >> member delete name pd2 // 下线 "pd2" Success! >> member delete id 1319539429105371180 // 使用 id 下线节点 Success! >> member leader show // 显示 leader 的信息 { "name": "pd", "addr": "http://192.168.199.229:2379", "id": 9724873857558226554 } >> member leader resign // 将 leader 从当前成员移走 ...... >> member leader transfer pd3 // 将 leader 迁移至指定成员 ...... operator [show | add | remove] 用于显示和控制调度操作,或者对 Region 进行分裂或合并。示例:>> operator show // 显示所有的 operators >> operator show admin // 显示所有的 admin operators >> …"}, {"url": "https://pingcap.com/docs-cn/v1.0/tools/pd-control/", "title": "PD Control 使用说明", "content": " PD Control 使用说明 PD Control 是 PD 的命令行工具,用于获取集群状态信息和调整集群。源码编译 Go Version 1.7 以上 在 PD 项目根目录使用 make 命令进行编译,生成 bin/pd-ctl 简单例子 单命令模式:./pd-ctl store -d -u http://127.0.0.1:2379 交互模式:./pd-ctl -u http://127.0.0.1:2379 使用环境变量:export PD_ADDR=http://127.0.0.1:2379 ./pd-ctl 使用TLS加密:./pd-ctl -u https://127.0.0.1:2379 --cacert="path/to/ca" --cert="path/to/cert" --key="path/to/key" 命令行参数(flags) --pd,-u 指定 PD 的地址 默认地址: http://127.0.0.1:2379 环境变量: PD_ADDR --detach,-d 使用单命令行模式(不进入 readline ) 默认值: false –cacert 指定 PEM 格式的受信任 CA 的证书文件路径 默认值: “” –cert 指定 PEM 格式的 SSL 证书文件路径 默认值: “” –key 指定 PEM 格式的 SSL 证书密钥文件路径,即 --cert 所指定的证书的私钥 默认值: “” –version,-V 打印版本信息并退出 默认值: false 命令(command) cluster 用于显示集群基本信息。示例:>> cluster // 显示 cluster 的信息 { "id": 6493707687106161130, "max_peer_count": 3 } config [show | set <option> <value>] 用于显示或调整配置信息。示例:>> config show // 显示 scheduler 的相关 config 信息 { "max-snapshot-count": 3, "max-pending-peer-count": 16, "max-store-down-time": "1h0m0s", "leader-schedule-limit": 64, "region-schedule-limit": 16, "replica-schedule-limit": 24, "tolerant-size-ratio": 2.5, "schedulers-v2": [ { "type": "balance-region", "args": null }, { "type": "balance-leader", "args": null }, { "type": "hot-region", "args": null } ] } >> config show all // 显示所有的 config 信息 >> config show namespace ts1 // 显示名为 ts1 的 namespace 的相关 config 信息 { "leader-schedule-limit": 64, "region-schedule-limit": 16, "replica-schedule-limit": 24, "max-replicas": 3, } >> config show replication // 显示 replication 的相关 config 信息 { "max-replicas": 3, "location-labels": "" } 通过调整 leader-schedule-limit 可以控制同时进行 leader 调度的任务个数。 这个值主要影响 leader balance 的速度,值越大调度得越快,设置为 0 则关闭调度。 Leader 调度的开销较小,需要的时候可以适当调大。>> config set leader-schedule-limit 4 // 最多同时进行 4 个 leader 调度 通过调整 region-schedule-limit 可以控制同时进行 region 调度的任务个数。 这个值主要影响 region balance 的速度,值越大调度得越快,设置为 0 则关闭调度。 Region 调度的开销较大,所以这个值不宜调得太大。>> config set region-schedule-limit 2 // 最多同时进行 2 个 region 调度 通过调整 replica-schedule-limit 可以控制同时进行 replica 调度的任务个数。 这个值主要影响节点挂掉或者下线的时候进行调度的速度,值越大调度得越快,设置为 0 则关闭调度。 Replica 调度的开销较大,所以这个值不宜调得太大。>> config set replica-schedule-limit 4 // 最多同时进行 4 个 replica 调度 以上对配置的修改是全局性的,还可以通过对不同 namespace 的配置,进行细化调整。当 namespace 未设置相应配置时,使用全局配置。注:namespace 的配置只支持对 leader-schedule-limit,region-schedule-limit,replica-schedule-limit,max-replicas 的调整,否则不生效。>> config set namespace ts1 leader-schedule-limit 4 // 设置名为 ts1 的 namespace 最多同时进行 4 个 leader 调度 >> config set namespace ts2 region-schedule-limit 2 // 设置名为 ts2 的 namespace 最多同时进行 2 个 region 调度 config delete namespace <name> [<option>] 用于删除 namespace 的配置信息。示例:在对 namespace 相关配置进行设置后,若想让该 namespace 继续使用全局配置,可删除该 namespace 的配置信息,之后便使用全局配置。>> config delete namespace ts1 // 删除名为 ts1 的 namespace 的相关配置 若只想让 namespace 中的某项配置使用全局配置而不影响其他配置,则可使用如下命令:>> config delete namespace region-schedule-limit ts2 // 删除名为 ts2 的 namespace 的 region-schedule-limit 配置 health 用于显示集群健康信息。示例:>> health // 显示健康信息 {"health": "true"} hot [read | write | store] 用于显示集群热点信息。示例:>> hot read // 显示读热点信息 >> hot write // 显示写热点信息 >> hot store // 显示所有 store 的读写信息 label [store] 用于显示集群标签信息示例:>> label // 显示所有 label >> label store zone cn // 显示所有包含 label 为 "zone":"cn" 的 store member [leader | delete] 用于显示 PD 成员信息或删除指定成员。示例:>> member // 显示所有成员的信息 { "members": [......] } >> member leader show // 显示 leader 的信息 { "name": "pd", "addr": "http://192.168.199.229:2379", "id": 9724873857558226554 } >> member delete name pd2 // 下线 "pd2" Success! >> member delete id 1319539429105371180 // 使用 id 下线节点 Success! operator [show | add | remove] 用于显示和控制调度操作。示例:>> operator show // 显示所有的 operators >> operator show admin // 显示所有的 admin operators >> operator show leader // 显示所有的 leader operators >> operator show region // 显示所有的 region operators >> operator add add-peer 1 2 // 在 store 2 上新增 region 1 的一个副本 >> operator remove remove-peer 1 2 // 移除 store 2 上的 region 1 的一个副本 >> operator add transfer-leader 1 2 // 把 region 1 的 leader 调度到 store 2 >> operator add transfer-region 1 2 3 4 // 把 region 1 调度到 store 2,3,4 >> operator add transfer-peer 1 2 3 // 把 region 1 在 store 2 上的副本调度到 store 3 >> operator remove 1 // 把 region 1 的调度操作删掉 ping 用于显示ping PD 所需要花费的时间示例:>> ping time: 43.12698ms region <region_id> 用于显示 region 信息。示例:>> region // 显示所有 region 信息 { "count": 1, "regions": [......] } >> region 2 // 显示 region id 为 2 的信息 { "region": { "id": 2, ...... } "leader": { ...... } } region key [–format=raw|pb|proto|protobuf] <key> 用于查询某个 key 在哪个 region 上,支持 raw 和 protobuf 格式。Raw 格式(默认)示例:>> region key abc { "region": { "id": 2, ...... } } Protobuf 格式示例:>> region key --format=pb t200000000000000000000377035_r200000000000000377017U320000000000000000372 { "region": { "id": 2, ...... } } scheduler [show | add | remove] 用于显示和控制调度策略。示例:>> scheduler show // 显示所有的 schedulers >> scheduler add grant-leader-scheduler 1 // 把 store 1 上的所有 region 的 leader 调度到 store 1 >> scheduler add evict-leader-scheduler 1 // 把 store 1 上的所有 region 的 leader 从 store 1 调度出去 >> scheduler add shuffle-leader-scheduler // 随机交换不同 store 上的 leader >> scheduler add shuffle-region-scheduler // 随机调度不同 store 上的 region >> scheduler remove grant-leader-scheduler-1 // 把对应的 scheduler 删掉 store [delete | label | weight] <store_id> 用于显示 store 信息或者删除指定 store。示例:>> store // 显示所有 store 信息 { "count": 3, "stores": [...] } >> store 1 // 获取 store id 为 1 的 store ...... >> store delete 1 // 下线 store id 为 1 的 store ...... >> store label 1 zone cn // 设置 store id 为 1 的 store 的键为 "zone" 的 label 的值为 "cn" >> store weight 1 5 10 // 设置 store id 为 1 的 store 的 leader weight 为 5,region weight 为 10 table_ns [create | add | remove | set_store | rm_store | set_meta | rm_meta] 用于显示 table 的 namespace 的相关信息示例:>> table_ns add ts1 1 // 将 table id 为 1 的 table 添加到名为 ts1 的 namespace >> table_ns create ts1 // 添加名为 ts1 的 namespace >> table_ns remove ts1 1 // 将 table id 为 1 的 table 从名为 ts1 的 namespace 中移除 >> table_ns rm_meta ts1 // 将 meta 信息从名为 ts1 的 namespace 中移除 >> table_ns rm_store 1 ts1 // 将 store id 为 1 的 table 从名为 ts1 的 namespace 中移除 >> table_ns set_meta ts1 // 将 meta 信息添加到名为 ts1 的 namespace >> table_ns set_store 1 ts1 // 将 store id 为 1 的 table 添加到名为 ts1 的 namespace tso 用于解析 TSO 到物理时间和逻辑时间示例:>> tso 395181938313123110 // 解析 TSO system: 2017-10-09 05:50:59 +0800 CST logic: 120102"}, {"url": "https://pingcap.com/docs-cn/v2.0/tools/pd-control/", "title": "PD Control 使用说明", "content": " PD Control 使用说明 PD Control 是 PD 的命令行工具,用于获取集群状态信息和调整集群。源码编译 Go Version 1.7 以上 在 PD 项目根目录使用 make 命令进行编译,生成 bin/pd-ctl 简单例子 单命令模式:./pd-ctl store -d -u http://127.0.0.1:2379 交互模式:./pd-ctl -u http://127.0.0.1:2379 使用环境变量:export PD_ADDR=http://127.0.0.1:2379 ./pd-ctl 使用TLS加密:./pd-ctl -u https://127.0.0.1:2379 --cacert="path/to/ca" --cert="path/to/cert" --key="path/to/key" 命令行参数(flags) --pd,-u 指定 PD 的地址 默认地址: http://127.0.0.1:2379 环境变量: PD_ADDR --detach,-d 使用单命令行模式(不进入 readline ) 默认值: false –cacert 指定 PEM 格式的受信任 CA 的证书文件路径 默认值: “” –cert 指定 PEM 格式的 SSL 证书文件路径 默认值: “” –key 指定 PEM 格式的 SSL 证书密钥文件路径,即 --cert 所指定的证书的私钥 默认值: “” –version,-V 打印版本信息并退出 默认值: false 命令(command) cluster 用于显示集群基本信息。示例:>> cluster // 显示 cluster 的信息 { "id": 6493707687106161130, "max_peer_count": 3 } config [show | set <option> <value>] 用于显示或调整配置信息。示例:>> config show // 显示 scheduler 的相关 config 信息 { "max-snapshot-count": 3, "max-pending-peer-count": 16, "max-store-down-time": "1h0m0s", "leader-schedule-limit": 64, "region-schedule-limit": 16, "replica-schedule-limit": 24, "tolerant-size-ratio": 2.5, "schedulers-v2": [ { "type": "balance-region", "args": null }, { "type": "balance-leader", "args": null }, { "type": "hot-region", "args": null } ] } >> config show all // 显示所有的 config 信息 >> config show namespace ts1 // 显示名为 ts1 的 namespace 的相关 config 信息 { "leader-schedule-limit": 64, "region-schedule-limit": 16, "replica-schedule-limit": 24, "max-replicas": 3, } >> config show replication // 显示 replication 的相关 config 信息 { "max-replicas": 3, "location-labels": "" } 通过调整 leader-schedule-limit 可以控制同时进行 leader 调度的任务个数。 这个值主要影响 leader balance 的速度,值越大调度得越快,设置为 0 则关闭调度。 Leader 调度的开销较小,需要的时候可以适当调大。>> config set leader-schedule-limit 4 // 最多同时进行 4 个 leader 调度 通过调整 region-schedule-limit 可以控制同时进行 region 调度的任务个数。 这个值主要影响 region balance 的速度,值越大调度得越快,设置为 0 则关闭调度。 Region 调度的开销较大,所以这个值不宜调得太大。>> config set region-schedule-limit 2 // 最多同时进行 2 个 region 调度 通过调整 replica-schedule-limit 可以控制同时进行 replica 调度的任务个数。 这个值主要影响节点挂掉或者下线的时候进行调度的速度,值越大调度得越快,设置为 0 则关闭调度。 Replica 调度的开销较大,所以这个值不宜调得太大。>> config set replica-schedule-limit 4 // 最多同时进行 4 个 replica 调度 以上对配置的修改是全局性的,还可以通过对不同 namespace 的配置,进行细化调整。当 namespace 未设置相应配置时,使用全局配置。注:namespace 的配置只支持对 leader-schedule-limit,region-schedule-limit,replica-schedule-limit,max-replicas 的调整,否则不生效。>> config set namespace ts1 leader-schedule-limit 4 // 设置名为 ts1 的 namespace 最多同时进行 4 个 leader 调度 >> config set namespace ts2 region-schedule-limit 2 // 设置名为 ts2 的 namespace 最多同时进行 2 个 region 调度 config delete namespace <name> [<option>] 用于删除 namespace 的配置信息。示例:在对 namespace 相关配置进行设置后,若想让该 namespace 继续使用全局配置,可删除该 namespace 的配置信息,之后便使用全局配置。>> config delete namespace ts1 // 删除名为 ts1 的 namespace 的相关配置 若只想让 namespace 中的某项配置使用全局配置而不影响其他配置,则可使用如下命令:>> config delete namespace region-schedule-limit ts2 // 删除名为 ts2 的 namespace 的 region-schedule-limit 配置 health 用于显示集群健康信息。示例:>> health // 显示健康信息 {"health": "true"} hot [read | write | store] 用于显示集群热点信息。示例:>> hot read // 显示读热点信息 >> hot write // 显示写热点信息 >> hot store // 显示所有 store 的读写信息 label [store] 用于显示集群标签信息示例:>> label // 显示所有 label >> label store zone cn // 显示所有包含 label 为 "zone":"cn" 的 store member [leader | delete] 用于显示 PD 成员信息或删除指定成员。示例:>> member // 显示所有成员的信息 { "members": [......] } >> member leader show // 显示 leader 的信息 { "name": "pd", "addr": "http://192.168.199.229:2379", "id": 9724873857558226554 } >> member delete name pd2 // 下线 "pd2" Success! >> member delete id 1319539429105371180 // 使用 id 下线节点 Success! operator [show | add | remove] 用于显示和控制调度操作。示例:>> operator show // 显示所有的 operators >> operator show admin // 显示所有的 admin operators >> operator show leader // 显示所有的 leader operators >> operator show region // 显示所有的 region operators >> operator add add-peer 1 2 // 在 store 2 上新增 region 1 的一个副本 >> operator remove remove-peer 1 2 // 移除 store 2 上的 region 1 的一个副本 >> operator add transfer-leader 1 2 // 把 region 1 的 leader 调度到 store 2 >> operator add transfer-region 1 2 3 4 // 把 region 1 调度到 store 2,3,4 >> operator add transfer-peer 1 2 3 // 把 region 1 在 store 2 上的副本调度到 store 3 >> operator remove 1 // 把 region 1 的调度操作删掉 ping 用于显示ping PD 所需要花费的时间示例:>> ping time: 43.12698ms region <region_id> 用于显示 region 信息。示例:>> region // 显示所有 region 信息 { "count": 1, "regions": [......] } >> region 2 // 显示 region id 为 2 的信息 { "region": { "id": 2, ...... } "leader": { ...... } } region key [–format=raw|pb|proto|protobuf] <key> 用于查询某个 key 在哪个 region 上,支持 raw 和 protobuf 格式。Raw 格式(默认)示例:>> region key abc { "region": { "id": 2, ...... } } Protobuf 格式示例:>> region key --format=pb t200000000000000000000377035_r200000000000000377017U320000000000000000372 { "region": { "id": 2, ...... } } scheduler [show | add | remove] 用于显示和控制调度策略。示例:>> scheduler show // 显示所有的 schedulers >> scheduler add grant-leader-scheduler 1 // 把 store 1 上的所有 region 的 leader 调度到 store 1 >> scheduler add evict-leader-scheduler 1 // 把 store 1 上的所有 region 的 leader 从 store 1 调度出去 >> scheduler add shuffle-leader-scheduler // 随机交换不同 store 上的 leader >> scheduler add shuffle-region-scheduler // 随机调度不同 store 上的 region >> scheduler remove grant-leader-scheduler-1 // 把对应的 scheduler 删掉 store [delete | label | weight] <store_id> 用于显示 store 信息或者删除指定 store。示例:>> store // 显示所有 store 信息 { "count": 3, "stores": [...] } >> store 1 // 获取 store id 为 1 的 store ...... >> store delete 1 // 下线 store id 为 1 的 store ...... >> store label 1 zone cn // 设置 store id 为 1 的 store 的键为 "zone" 的 label 的值为 "cn" >> store weight 1 5 10 // 设置 store id 为 1 的 store 的 leader weight 为 5,region weight 为 10 table_ns [create | add | remove | set_store | rm_store | set_meta | rm_meta] 用于显示 table 的 namespace 的相关信息示例:>> table_ns add ts1 1 // 将 table id 为 1 的 table 添加到名为 ts1 的 namespace >> table_ns create ts1 // 添加名为 ts1 的 namespace >> table_ns remove ts1 1 // 将 table id 为 1 的 table 从名为 ts1 的 namespace 中移除 >> table_ns rm_meta ts1 // 将 meta 信息从名为 ts1 的 namespace 中移除 >> table_ns rm_store 1 ts1 // 将 store id 为 1 的 table 从名为 ts1 的 namespace 中移除 >> table_ns set_meta ts1 // 将 meta 信息添加到名为 ts1 的 namespace >> table_ns set_store 1 ts1 // 将 store id 为 1 的 table 添加到名为 ts1 的 namespace tso 用于解析 TSO 到物理时间和逻辑时间示例:>> tso 395181938313123110 // 解析 TSO system: 2017-10-09 05:50:59 +0800 CST logic: 120102"}, {"url": "https://pingcap.com/docs/tools/pd-recover/", "title": "PD Recover User Guide", "content": " PD Recover User Guide PD Recover is a disaster recovery tool of PD, used to recover the PD cluster which cannot start or provide services normally.Source code compiling Go Version 1.9 or later In the root directory of the PD project, use the make command to compile and generate bin/pd-recover Usage This section describes how to recover a PD cluster which cannot start or provide services normally.Flags description -alloc-id uint Specify a number larger than the allocated ID of the original cluster -cacert string Specify the path to the trusted CA certificate file in PEM format -cert string Specify the path to the SSL certificate file in PEM format -key string Specify the path to the SSL certificate key file in PEM format, which is the private key of the certificate specified by `--cert` -cluster-id uint Specify the Cluster ID of the original cluster -endpoints string Specify the PD address (default: "http://127.0.0.1:2379") Recovery flow Obtain the Cluster ID and the Alloc ID from the current cluster. Obtain the Cluster ID from the PD, TiKV and TiDB log. Obtain the allocated Alloc ID from either the PD log or the Metadata Information in the PD monitoring panel. Specifying alloc-id requires a number larger than the current largest Alloc ID. If you fail to obtain the Alloc ID, you can make an estimate of a larger number according to the number of Regions and Stores in the cluster. Generally, you can specify a number that is several orders of magnitude larger. Stop the whole cluster, clear the PD data directory, and restart the PD cluster. Use PD Recover to recover and make sure that you use the correct cluster-id and appropriate alloc-id. When the recovery success information is prompted, restart the whole cluster. "}, {"url": "https://pingcap.com/docs/v2.0/tools/pd-recover/", "title": "PD Recover User Guide", "content": " PD Recover User Guide PD Recover is a disaster recovery tool of PD, used to recover the PD cluster which cannot start or provide services normally.Source code compiling Go Version 1.9 or later In the root directory of the PD project, use the make command to compile and generate bin/pd-recover Usage This section describes how to recover a PD cluster which cannot start or provide services normally.Flags description -alloc-id uint Specify a number larger than the allocated ID of the original cluster -cacert string Specify the path to the trusted CA certificate file in PEM format -cert string Specify the path to the SSL certificate file in PEM format -key string Specify the path to the SSL certificate key file in PEM format, which is the private key of the certificate specified by `--cert` -cluster-id uint Specify the Cluster ID of the original cluster -endpoints string Specify the PD address (default: "http://127.0.0.1:2379") Recovery flow Obtain the Cluster ID and the Alloc ID from the current cluster. Obtain the Cluster ID from the PD, TiKV and TiDB log. Obtain the allocated Alloc ID from either the PD log or the Metadata Information in the PD monitoring panel. Specifying alloc-id requires a number larger than the current largest Alloc ID. If you fail to obtain the Alloc ID, you can make an estimate of a larger number according to the number of Regions and Stores in the cluster. Generally, you can specify a number that is several orders of magnitude larger. Stop the whole cluster, clear the PD data directory, and restart the PD cluster. Use PD Recover to recover and make sure that you use the correct cluster-id and appropriate alloc-id. When the recovery success information is prompted, restart the whole cluster. "}, {"url": "https://pingcap.com/docs-cn/tools/pd-recover/", "title": "PD Recover 使用文档", "content": " PD Recover 使用文档 PD Recover 是对 PD 进行灾难性恢复的工具,用于恢复无法正常启动或服务的 PD 集群。源码编译 Go Version 1.9 以上 在 PD 项目根目录使用 make 命令进行编译,生成 bin/pd-recover 使用方法 参数说明 -alloc-id uint 指定比原集群已分配过的 ID 更大的数 -cacert string 指定 PEM 格式的受信任 CA 的证书文件路径 -cert string 指定 PEM 格式的 SSL 证书文件路径 -key string 指定 PEM 格式的 SSL 证书密钥文件路径,即 `--cert` 所指定的证书的私钥 -cluster-id uint 指定原集群的 cluster ID -endpoints string 指定 PD 的地址 (default "http://127.0.0.1:2379") 恢复流程 从当前集群中找到集群的 Cluster ID 和 Alloc ID。一般在 PD,TiKV 或 TiDB 的日志中都可以获取 Cluster ID。已经分配过的 Alloc ID 可以从 PD 日志获得。另外也可以从 PD 的监控面板的 Metadata Information 监控项中获得。在指定 alloc-id 时需指定一个比当前最大的 Alloc ID 更大的值。如果没有途径获取 Alloc ID,可以根据集群中的 Region,Store 数预估一个较大的数,一般可取高几个数量级的数。 停止整个集群,清空 PD 数据目录,重启 PD 集群。 使用 PD recover 进行恢复,注意指定正确的 cluster-id 和合适的 alloc-id。 提示恢复成功后,重启整个集群。 "}, {"url": "https://pingcap.com/recruit-cn/engineering/pd-engineer/", "title": "PD 研发工程师", "content": " PD 研发工程师 岗位职责:负责 TiDB 集群中心控制组件 Placement Driver (PD) 的开发工作,包括但不限于: 负责集群全局调度系统的设计,开发,文档撰写; 负责集群模拟器的开发; 负责集群可视化系统的开发。 任职要求: 三年以上相关领域开发经验,扎实的编程能力,熟悉 C/C++/Go/Java/Python 中的一种; 对分布式系统的架构和原理有比较深入的了解; 优秀的发现和解决问题能力,良好的沟通能力,良好的抗压能力,具备团队合作精神。 加分项: 精通 Go 语言,能熟练使用 Go pprof 分析和解决性能问题; 有分布式调度系统相关开发经验; 有开源项目经历,对前沿技术有浓厚的热情; 有 Rust 语言开发经验。 待遇:25K - 50K,13薪 + 奖金,优秀者可面议工作地点:北京,上海,广州,杭州,成都,特别优秀可 Remote"}, {"url": "https://pingcap.com/docs-cn/op-guide/dashboard-pd-info/", "title": "PD 重要监控指标详解", "content": " PD 重要监控指标详解 使用 Ansible 部署 TiDB 集群时,一键部署监控系统 (Prometheus/Grafana),监控架构请看 TiDB 监控框架概述。目前 Grafana Dashboard 整体分为 PD、TiDB、TiKV、Node_exporter、Overview 等。对于日常运维,我们通过观察 PD 面板上的 Metrics,可以了解 PD 当前的状态。以下为 PD Dashboard 监控说明:Cluster PD role:当前 PD 的角色 Storage capacity:TiDB 集群总可用数据库空间大小 Current storage size:TiDB 集群目前已用数据库空间大小 Number of Regions:当前集群的 Region 总量 Leader balance ratio:Leader 数量最多和最少节点相差的百分比,一般小于 5%,节点重启时会有比较大的波动 Region balance ratio:Region 数量最多和最少节点相差的百分比,一般小于 5%,新增/下线节点时相差比较大 Normal stores:处于正常状态的节点数目 Abnormal stores:处于异常状态的节点数目,正常情况应当为 0 Current storage usage:TiDB 集群存储空间的使用率 Current peer count:当前集群 peer 的总量 Metadata information:记录集群 ID,时间戳和生成的 ID Region label isolation level:不同 label 所在的 level 的 Region 数量 Region health:每个 Region 的状态,通常情况下,pending 的 peer 应该少于 100,miss 的 peer 不能一直大于 0 Balance Store capacity:每个 TiKV 实例的总的空间大小 Store available:每个 TiKV 实例的可用空间大小 Store used:每个 TiKV 实例的已使用空间大小 Size amplification:每个 TiKV 实例的空间放大比率 Size available ratio:每个 TiKV 实例的可用空间比率 Store leader score:每个 TiKV 实例的 leader 分数 Store Region score:每个 TiKV 实例的 Region 分数 Store leader size:每个 TiKV 实例上所有 leader 的大小 Store Region size:每个 TiKV 实例上所有 Region 的大小 Store leader count:每个 TiKV 实例上所有 leader 的数量 Store Region count:每个 TiKV 实例上所有 Region 的数量 HotRegion Hot write Region’s leader distribution:每个 TiKV 实例上是写入热点的 leader 的数量 Hot write Region’s peer distribution:每个 TiKV 实例上是写入热点的 peer 的数量 Hot write Region’s leader written bytes:每个 TiKV 实例上热点的 leader 的写入大小 Hot write Region’s peer written bytes:每个 TiKV 实例上热点的 peer 的写入大小 Hot read Region’s leader distribution:每个 TiKV 实例上是读取热点的 leader 的数量 Hot read Region’s peer distribution:每个 TiKV 实例上是读取热点的 peer 的数量 Hot read Region’s leader read bytes:每个 TiKV 实例上热点的 leader 的读取大小 Hot read Region’s peer read bytes:每个 TiKV 实例上热点的 peer 的读取大小 Scheduler Scheduler is running:所有正在运行的 scheduler Balance leader movement:leader 移动的详细情况 Balance Region movement:Region 移动的详细情况 Balance leader event:balance leader 的事件数量 Balance Region event:balance Region 的事件数量 Balance leader scheduler:balance-leader scheduler 的状态 Balance Region scheduler:balance-region scheduler 的状态 Namespace checker:namespace checker 的状态 Replica checker:replica checker 的状态 Region merge checker:merge checker 的状态 Operator Schedule operator create:新创建的不同 operator 的数量 Schedule operator check:已检查的 operator 的数量,主要检查是否当前步骤已经执行完成,如果是,则执行下一个步骤 Schedule operator finish:已完成的 operator 的数量 Schedule operator timeout:已超时的 operator 的数量 Schedule operator replaced or canceled:已取消或者被替换的 operator 的数量 Schedule operators count by state:不同状态的 operator 的数量 99% Operator finish duration:已完成的 operator 中,99% 所需花费的时间 50% Operator finish duration:已完成的 operator 中,50% 所需花费的时间 99% Operator step duration:已完成的 operator 的步骤中,99% 所需花费的时间 50% Operator step duration:已完成的 operator 的步骤中,50% 所需花费的时间 gRPC Completed commands rate:gRPC 命令的完成速率 99% Completed commands duration:99% 的情况下,命令的完成时间 etcd Handle transactions count:etcd 的事务个数 99% Handle transactions duration:99% 的情况下,处理 etcd 事务所需花费的时间 99% WAL fsync duration:99% 的情况下,持久化 WAL 所需花费的时间,这个值通常应该小于 1s 99% Peer round trip time seconds:99% 的情况下,etcd 的网络延时,这个值通常应该小于 1s etcd disk WAL fsync rate:etcd 持久化 WAL 的速率 Raft term:当前 Raft 的 term Raft committed index:最后一次 commit 的 Raft index Raft applied index:最后一次 apply 的 Raft index TiDB Handle requests count:TiDB 的请求数量 Handle requests duration:每个请求所花费的时间,99% 的情况下,应该小于 100ms Heartbeat Region heartbeat report:TiKV 向 PD 发送的心跳个数 Region heartbeat report error:TiKV 向 PD 发送的异常的心跳个数 Region heartbeat report active:TiKV 向 PD 发送的正常的心跳个数 Region schedule push:PD 向 TiKV 发送的调度命令的个数 99% Region heartbeat latency:99% 的情况下,心跳的延迟 "}, {"url": "https://pingcap.com/", "title": "PingCAP Site", "content": ""}, {"url": "https://pingcap.com/tidb-academy/mysql_dbas/scaling/pd/", "title": "Placement Driver", "content": " Placement Driver Resources pd-ctl "}, {"url": "https://pingcap.com/docs/releases/prega/", "title": "Pre-GA release notes", "content": " Pre-GA Release Notes On August 30, 2017, TiDB Pre-GA is released! This release is focused on MySQL compatibility, SQL optimization, stability, and performance.TiDB: The SQL query optimizer: Adjust the cost model Use index scan to handle the where clause with the compare expression which has different types on each side Support the Greedy algorithm based Join Reorder Many enhancements have been introduced to be more compatible with MySQL Support Natural Join Support the JSON type (Experimental), including the query, update and index of the JSON fields Prune the useless data to reduce the consumption of the executor memory Support configuring prioritization in the SQL statements and automatically set the prioritization for some of the statements according to the query type Completed the expression refactor and the speed is increased by about 30% Placement Driver (PD): Support manually changing the leader of the PD cluster TiKV: Use dedicated Rocksdb instance to store Raft log Use DeleteRange to speed up the deleting of replicas Coprocessor now supports more pushdown operators Improve the performance and stability TiDB Connector for Spark Beta Release: Implement the predicates pushdown Implement the aggregation pushdown Implement range pruning Capable of running full set of TPC+H except for one query that needs view support "}, {"url": "https://pingcap.com/docs/v1.0/releases/prega/", "title": "Pre-GA release notes", "content": " Pre-GA Release Notes On August 30, 2017, TiDB Pre-GA is released! This release is focused on MySQL compatibility, SQL optimization, stability, and performance.TiDB: The SQL query optimizer: Adjust the cost model Use index scan to handle the where clause with the compare expression which has different types on each side Support the Greedy algorithm based Join Reorder Many enhancements have been introduced to be more compatible with MySQL Support Natural Join Support the JSON type (Experimental), including the query, update and index of the JSON fields Prune the useless data to reduce the consumption of the executor memory Support configuring prioritization in the SQL statements and automatically set the prioritization for some of the statements according to the query type Completed the expression refactor and the speed is increased by about 30% Placement Driver (PD): Support manually changing the leader of the PD cluster TiKV: Use dedicated Rocksdb instance to store Raft log Use DeleteRange to speed up the deleting of replicas Coprocessor now supports more pushdown operators Improve the performance and stability TiDB Connector for Spark Beta Release: Implement the predicates pushdown Implement the aggregation pushdown Implement range pruning Capable of running full set of TPC+H except for one query that needs view support "}, {"url": "https://pingcap.com/docs/v2.0/releases/prega/", "title": "Pre-GA release notes", "content": " Pre-GA Release Notes On August 30, 2017, TiDB Pre-GA is released! This release is focused on MySQL compatibility, SQL optimization, stability, and performance.TiDB: The SQL query optimizer: Adjust the cost model Use index scan to handle the where clause with the compare expression which has different types on each side Support the Greedy algorithm based Join Reorder Many enhancements have been introduced to be more compatible with MySQL Support Natural Join Support the JSON type (Experimental), including the query, update and index of the JSON fields Prune the useless data to reduce the consumption of the executor memory Support configuring prioritization in the SQL statements and automatically set the prioritization for some of the statements according to the query type Completed the expression refactor and the speed is increased by about 30% Placement Driver (PD): Support manually changing the leader of the PD cluster TiKV: Use dedicated Rocksdb instance to store Raft log Use DeleteRange to speed up the deleting of replicas Coprocessor now supports more pushdown operators Improve the performance and stability TiDB Connector for Spark Beta Release: Implement the predicates pushdown Implement the aggregation pushdown Implement range pruning Capable of running full set of TPC+H except for one query that needs view support "}, {"url": "https://pingcap.com/docs/sql/precision-math/", "title": "Precision Math", "content": " Precision Math The precision math support in TiDB is consistent with MySQL. For more information, see Precision Math in MySQL.Numeric types The scope of precision math for exact-value operations includes the exact-value data types (integer and DECIMAL types) and exact-value numeric literals. Approximate-value data types and numeric literals are handled as floating-point numbers.Exact-value numeric literals have an integer part or fractional part, or both. They may be signed. Examples: 1, .2, 3.4, -5, -6.78, +9.10.Approximate-value numeric literals are represented in scientific notation (power-of-10) with a mantissa and exponent. Either or both parts may be signed. Examples: 1.2E3, 1.2E-3, -1.2E3, -1.2E-3.Two numbers that look similar might be treated differently. For example, 2.34 is an exact-value (fixed-point) number, whereas 2.34E0 is an approximate-value (floating-point) number.The DECIMAL data type is a fixed-point type and the calculations are exact. The FLOAT and DOUBLE data types are floating-point types and calculations are approximate.DECIMAL data type characteristics This section discusses the following topics of the characteristics of the DECIMAL data type (and its synonyms): Maximum number of digits Storage format Storage requirements The declaration syntax for a DECIMAL column is DECIMAL(M,D). The ranges of values for the arguments are as follows: M is the maximum number of digits (the precision). 1<= M <= 65. D is the number of digits to the right of the decimal point (the scale). 1 <= D <= 30 and D must be no larger than M. The maximum value of 65 for M means that calculations on DECIMAL values are accurate up to 65 digits. This limit of 65 digits of precision also applies to exact-value numeric literals.Values for DECIMAL columns are stored using a binary format that packs 9 decimal digits into 4 bytes. The storage requirements for the integer and fractional parts of each value are determined separately. Each multiple of 9 digits requires 4 bytes, and any remaining digits left over require some fraction of 4 bytes. The storage required for remaining digits is given by the following table. Leftover Digits Number of Bytes 0 0 1–2 1 3–4 2 5–6 3 7–9 4 For example, a DECIMAL(18,9) column has 9 digits on each side of the decimal point, so the integer part and the fractional part each require 4 bytes. A DECIMAL(20,6) column has 14 integer digits and 6 fractional digits. The integer digits require 4 bytes for 9 of the digits and 3 bytes for the remaining 5 digits. The 6 fractional digits require 3 bytes.DECIMAL columns do not store a leading + character or - character or leading 0 digits. If you insert +0003.1 into a DECIMAL(5,1) column, it is stored as 3.1. For negative numbers, a literal - character is not stored.DECIMAL columns do not permit values larger than the range implied by the column definition. For example, a DECIMAL(3,0) column supports a range of -999 to 999. A DECIMAL(M,D) column permits at most M - D digits to the left of the decimal point.For more information about the internal format of the DECIMAL values, see mydecimal.go in TiDB souce code.Expression handling For expressions with precision math, TiDB uses the exact-value numbers as given whenever possible. For example, numbers in comparisons are used exactly as given without a change in value. In strict SQL mode, if you add an exact data type into a column, a number is inserted with its exact value if it is within the column range. When retrieved, the value is the same as what is inserted. If strict SQL mode is not enabled, truncation for INSERT is permitted in TiDB.How to handle a numeric expression depends on the values of the expression: If the expression contains any approximate values, the result is approximate. TiDB evaluates the expression using floating-point arithmetic. If the expression contains no approximate values are present, which means only exact values are contained, and if any exact value contains a fractional part, the expression is evaluated using DECIMAL exact arithmetic and has a precision of 65 digits. Otherwise, the expression contains only integer values. The expression is exact. TiDB evaluates the expression using integer arithmetic and has a precision the same as BIGINT (64 bits). If a numeric expression contains strings, the strings are converted to double-precision floating-point values and the result of the expression is approximate.Inserts into numeric columns are affected by the SQL mode. The following discussions mention strict mode and ERROR_FOR_DIVISION_BY_ZERO. To turn on all the restrictions, you can simply use the TRADITIONAL mode, which includes both strict mode values and ERROR_FOR_DIVISION_BY_ZERO:SET sql_mode = 'TRADITIONAL`; If a number is inserted into an exact type column (DECIMAL or integer), it is inserted with its exact value if it is within the column range. For this number: If the value has too many digits in the fractional part, rounding occurs and a warning is generated. If the value has too many digits in the integer part, it is too large and is handled as follows: If strict mode is not enabled, the value is truncated to the nearest legal value and a warning is generated. If strict mode is enabled, an overflow error occurs. To insert strings into numeric columns, TiDB handles the conversion from string to number as follows if the string has nonnumeric contents: In strict mode, a string (including an empty string) that does not begin with a number cannot be used as a number. An error, or a warning occurs. A string that begins with a number can be converted, but the trailing nonnumeric portion is truncated. In strict mode, if the truncated portion contains anything other than spaces, an error, or a warning occurs. By default, the result of the division by 0 is NULL and no warning. By setting the SQL mode appropriately, division by 0 can be restricted. If you enable the ERROR_FOR_DIVISION_BY_ZERO SQL mode, TiDB handles division by 0 differently: In strict mode, inserts and updates are prohibited, and an error occurs. If it’s not in the strict mode, a warning occurs. In the following SQL statement:INSERT INTO t SET i = 1/0; The following results are returned in different SQL modes: sql_mode Value Result “ No warning, no error; i is set to NULL. strict No warning, no error; i is set to NULL. ERROR_FOR_DIVISION_BY_ZERO Warning, no error; i is set to NULL. strict, ERROR_FOR_DIVISION_BY_ZERO Error; no row is inserted. Rounding behavior The result of the ROUND() function depends on whether its argument is exact or approximate: For exact-value numbers, the ROUND() function uses the “round half up” rule. For approximate-value numbers, the results in TiDB differs from that in MySQL:TiDB > SELECT ROUND(2.5), ROUND(25E-1); +------------+--------------+ | ROUND(2.5) | ROUND(25E-1) | +------------+--------------+ | 3 | 3 | +------------+--------------+ 1 row in set (0.00 sec) For inserts into a DECIMAL or integer column, the rounding uses round half away from zero.TiDB > CREATE TABLE t (d DECIMAL(10,0)); Query OK, 0 rows affected (0.01 sec) TiDB > INSERT INTO t VALUES(2.5),(2.5E0); Query OK, 2 rows affected, 2 warnings (0.00 sec) TiDB > SELECT d FROM t; +------+ | d | +------+ | 3 | | 3 | +------+ 2 rows in set (0.00 sec)"}, {"url": "https://pingcap.com/docs/v1.0/sql/precision-math/", "title": "Precision Math", "content": " Precision Math The precision math support in TiDB is consistent with MySQL. For more information, see Precision Math in MySQL.Numeric types The scope of precision math for exact-value operations includes the exact-value data types (integer and DECIMAL types) and exact-value numeric literals. Approximate-value data types and numeric literals are handled as floating-point numbers.Exact-value numeric literals have an integer part or fractional part, or both. They may be signed. Examples: 1, .2, 3.4, -5, -6.78, +9.10.Approximate-value numeric literals are represented in scientific notation (power-of-10) with a mantissa and exponent. Either or both parts may be signed. Examples: 1.2E3, 1.2E-3, -1.2E3, -1.2E-3.Two numbers that look similar might be treated differently. For example, 2.34 is an exact-value (fixed-point) number, whereas 2.34E0 is an approximate-value (floating-point) number.The DECIMAL data type is a fixed-point type and the calculations are exact. The FLOAT and DOUBLE data types are floating-point types and calculations are approximate.DECIMAL data type characteristics This section discusses the following topics of the characteristics of the DECIMAL data type (and its synonyms): Maximum number of digits Storage format Storage requirements The declaration syntax for a DECIMAL column is DECIMAL(M,D). The ranges of values for the arguments are as follows: M is the maximum number of digits (the precision). 1<= M <= 65. D is the number of digits to the right of the decimal point (the scale). 1 <= D <= 30 and D must be no larger than M. The maximum value of 65 for M means that calculations on DECIMAL values are accurate up to 65 digits. This limit of 65 digits of precision also applies to exact-value numeric literals.Values for DECIMAL columns are stored using a binary format that packs 9 decimal digits into 4 bytes. The storage requirements for the integer and fractional parts of each value are determined separately. Each multiple of 9 digits requires 4 bytes, and any remaining digits left over require some fraction of 4 bytes. The storage required for remaining digits is given by the following table. Leftover Digits Number of Bytes 0 0 1–2 1 3–4 2 5–6 3 7–9 4 For example, a DECIMAL(18,9) column has 9 digits on each side of the decimal point, so the integer part and the fractional part each require 4 bytes. A DECIMAL(20,6) column has 14 integer digits and 6 fractional digits. The integer digits require 4 bytes for 9 of the digits and 3 bytes for the remaining 5 digits. The 6 fractional digits require 3 bytes.DECIMAL columns do not store a leading + character or - character or leading 0 digits. If you insert +0003.1 into a DECIMAL(5,1) column, it is stored as 3.1. For negative numbers, a literal - character is not stored.DECIMAL columns do not permit values larger than the range implied by the column definition. For example, a DECIMAL(3,0) column supports a range of -999 to 999. A DECIMAL(M,D) column permits at most M - D digits to the left of the decimal point.For more information about the internal format of the DECIMAL values, see mydecimal.go in TiDB souce code.Expression handling For expressions with precision math, TiDB uses the exact-value numbers as given whenever possible. For example, numbers in comparisons are used exactly as given without a change in value. In strict SQL mode, if you add an exact data type into a column, a number is inserted with its exact value if it is within the column range. When retrieved, the value is the same as what is inserted. If strict SQL mode is not enabled, truncation for INSERT is permitted in TiDB.How to handle a numeric expression depends on the values of the expression: If the expression contains any approximate values, the result is approximate. TiDB evaluates the expression using floating-point arithmetic. If the expression contains no approximate values are present, which means only exact values are contained, and if any exact value contains a fractional part, the expression is evaluated using DECIMAL exact arithmetic and has a precision of 65 digits. Otherwise, the expression contains only integer values. The expression is exact. TiDB evaluates the expression using integer arithmetic and has a precision the same as BIGINT (64 bits). If a numeric expression contains strings, the strings are converted to double-precision floating-point values and the result of the expression is approximate.Inserts into numeric columns are affected by the SQL mode. The following discussions mention strict mode and ERROR_FOR_DIVISION_BY_ZERO. To turn on all the restrictions, you can simply use the TRADITIONAL mode, which includes both strict mode values and ERROR_FOR_DIVISION_BY_ZERO:SET sql_mode = 'TRADITIONAL`; If a number is inserted into an exact type column (DECIMAL or integer), it is inserted with its exact value if it is within the column range. For this number: - If the value has too many digits in the fractional part, rounding occurs and a warning is generated. - If the value has too many digits in the integer part, it is too large and is handled as follows: - If strict mode is not enabled, the value is truncated to the nearest legal value and a warning is generated. - If strict mode is enabled, an overflow error occurs.To insert strings into numeric columns, TiDB handles the conversion from string to number as follows if the string has nonnumeric contents: In strict mode, a string (including an empty string) that does not begin with a number cannot be used as a number. An error, or a warning occurs. A string that begins with a number can be converted, but the trailing nonnumeric portion is truncated. In strict mode, if the truncated portion contains anything other than spaces, an error, or a warning occurs. By default, the result of the division by 0 is NULL and no warning. By setting the SQL mode appropriately, division by 0 can be restricted. If you enable the ERROR_FOR_DIVISION_BY_ZERO SQL mode, TiDB handles division by 0 differently: In strict mode, inserts and updates are prohibited, and an error occurs. If it’s not in the strict mode, a warning occurs. In the following SQL statement:INSERT INTO t SET i = 1/0; The following results are returned in different SQL modes: sql_mode Value Result “ No warning, no error; i is set to NULL. strict No warning, no error; i is set to NULL. ERROR_FOR_DIVISION_BY_ZERO Warning, no error; i is set to NULL. strict, ERROR_FOR_DIVISION_BY_ZERO Error; no row is inserted. Rounding behavior The result of the ROUND() function depends on whether its argument is exact or approximate: For exact-value numbers, the ROUND() function uses the “round half up” rule. For approximate-value numbers, the results in TiDB differs from that in MySQL:TiDB > SELECT ROUND(2.5), ROUND(25E-1); +------------+--------------+ | ROUND(2.5) | ROUND(25E-1) | +------------+--------------+ | 3 | 3 | +------------+--------------+ 1 row in set (0.00 sec) For inserts into a DECIMAL or integer column, the rounding uses round half away from zero.TiDB > CREATE TABLE t (d DECIMAL(10,0)); Query OK, 0 rows affected (0.01 sec) TiDB > INSERT INTO t VALUES(2.5),(2.5E0); Query OK, 2 rows affected, 2 warnings (0.00 sec) TiDB > SELECT d FROM t; +------+ | d | +------+ | 3 | | 3 | +------+ 2 rows in set (0.00 sec)"}, {"url": "https://pingcap.com/docs/v2.0/sql/precision-math/", "title": "Precision Math", "content": " Precision Math The precision math support in TiDB is consistent with MySQL. For more information, see Precision Math in MySQL.Numeric types The scope of precision math for exact-value operations includes the exact-value data types (integer and DECIMAL types) and exact-value numeric literals. Approximate-value data types and numeric literals are handled as floating-point numbers.Exact-value numeric literals have an integer part or fractional part, or both. They may be signed. Examples: 1, .2, 3.4, -5, -6.78, +9.10.Approximate-value numeric literals are represented in scientific notation (power-of-10) with a mantissa and exponent. Either or both parts may be signed. Examples: 1.2E3, 1.2E-3, -1.2E3, -1.2E-3.Two numbers that look similar might be treated differently. For example, 2.34 is an exact-value (fixed-point) number, whereas 2.34E0 is an approximate-value (floating-point) number.The DECIMAL data type is a fixed-point type and the calculations are exact. The FLOAT and DOUBLE data types are floating-point types and calculations are approximate.DECIMAL data type characteristics This section discusses the following topics of the characteristics of the DECIMAL data type (and its synonyms): Maximum number of digits Storage format Storage requirements The declaration syntax for a DECIMAL column is DECIMAL(M,D). The ranges of values for the arguments are as follows: M is the maximum number of digits (the precision). 1<= M <= 65. D is the number of digits to the right of the decimal point (the scale). 1 <= D <= 30 and D must be no larger than M. The maximum value of 65 for M means that calculations on DECIMAL values are accurate up to 65 digits. This limit of 65 digits of precision also applies to exact-value numeric literals.Values for DECIMAL columns are stored using a binary format that packs 9 decimal digits into 4 bytes. The storage requirements for the integer and fractional parts of each value are determined separately. Each multiple of 9 digits requires 4 bytes, and any remaining digits left over require some fraction of 4 bytes. The storage required for remaining digits is given by the following table. Leftover Digits Number of Bytes 0 0 1–2 1 3–4 2 5–6 3 7–9 4 For example, a DECIMAL(18,9) column has 9 digits on each side of the decimal point, so the integer part and the fractional part each require 4 bytes. A DECIMAL(20,6) column has 14 integer digits and 6 fractional digits. The integer digits require 4 bytes for 9 of the digits and 3 bytes for the remaining 5 digits. The 6 fractional digits require 3 bytes.DECIMAL columns do not store a leading + character or - character or leading 0 digits. If you insert +0003.1 into a DECIMAL(5,1) column, it is stored as 3.1. For negative numbers, a literal - character is not stored.DECIMAL columns do not permit values larger than the range implied by the column definition. For example, a DECIMAL(3,0) column supports a range of -999 to 999. A DECIMAL(M,D) column permits at most M - D digits to the left of the decimal point.For more information about the internal format of the DECIMAL values, see mydecimal.go in TiDB souce code.Expression handling For expressions with precision math, TiDB uses the exact-value numbers as given whenever possible. For example, numbers in comparisons are used exactly as given without a change in value. In strict SQL mode, if you add an exact data type into a column, a number is inserted with its exact value if it is within the column range. When retrieved, the value is the same as what is inserted. If strict SQL mode is not enabled, truncation for INSERT is permitted in TiDB.How to handle a numeric expression depends on the values of the expression: If the expression contains any approximate values, the result is approximate. TiDB evaluates the expression using floating-point arithmetic. If the expression contains no approximate values are present, which means only exact values are contained, and if any exact value contains a fractional part, the expression is evaluated using DECIMAL exact arithmetic and has a precision of 65 digits. Otherwise, the expression contains only integer values. The expression is exact. TiDB evaluates the expression using integer arithmetic and has a precision the same as BIGINT (64 bits). If a numeric expression contains strings, the strings are converted to double-precision floating-point values and the result of the expression is approximate.Inserts into numeric columns are affected by the SQL mode. The following discussions mention strict mode and ERROR_FOR_DIVISION_BY_ZERO. To turn on all the restrictions, you can simply use the TRADITIONAL mode, which includes both strict mode values and ERROR_FOR_DIVISION_BY_ZERO:SET sql_mode = 'TRADITIONAL`; If a number is inserted into an exact type column (DECIMAL or integer), it is inserted with its exact value if it is within the column range. For this number: - If the value has too many digits in the fractional part, rounding occurs and a warning is generated. - If the value has too many digits in the integer part, it is too large and is handled as follows: - If strict mode is not enabled, the value is truncated to the nearest legal value and a warning is generated. - If strict mode is enabled, an overflow error occurs.To insert strings into numeric columns, TiDB handles the conversion from string to number as follows if the string has nonnumeric contents: In strict mode, a string (including an empty string) that does not begin with a number cannot be used as a number. An error, or a warning occurs. A string that begins with a number can be converted, but the trailing nonnumeric portion is truncated. In strict mode, if the truncated portion contains anything other than spaces, an error, or a warning occurs. By default, the result of the division by 0 is NULL and no warning. By setting the SQL mode appropriately, division by 0 can be restricted. If you enable the ERROR_FOR_DIVISION_BY_ZERO SQL mode, TiDB handles division by 0 differently: In strict mode, inserts and updates are prohibited, and an error occurs. If it’s not in the strict mode, a warning occurs. In the following SQL statement:INSERT INTO t SET i = 1/0; The following results are returned in different SQL modes: sql_mode Value Result “ No warning, no error; i is set to NULL. strict No warning, no error; i is set to NULL. ERROR_FOR_DIVISION_BY_ZERO Warning, no error; i is set to NULL. strict, ERROR_FOR_DIVISION_BY_ZERO Error; no row is inserted. Rounding behavior The result of the ROUND() function depends on whether its argument is exact or approximate: For exact-value numbers, the ROUND() function uses the “round half up” rule. For approximate-value numbers, the results in TiDB differs from that in MySQL:TiDB > SELECT ROUND(2.5), ROUND(25E-1); +------------+--------------+ | ROUND(2.5) | ROUND(25E-1) | +------------+--------------+ | 3 | 3 | +------------+--------------+ 1 row in set (0.00 sec) For inserts into a DECIMAL or integer column, the rounding uses round half away from zero.TiDB > CREATE TABLE t (d DECIMAL(10,0)); Query OK, 0 rows affected (0.01 sec) TiDB > INSERT INTO t VALUES(2.5),(2.5E0); Query OK, 2 rows affected, 2 warnings (0.00 sec) TiDB > SELECT d FROM t; +------+ | d | +------+ | 3 | | 3 | +------+ 2 rows in set (0.00 sec)"}, {"url": "https://pingcap.com/docs/sql/prepare/", "title": "Prepared SQL Statement Syntax", "content": " Prepared SQL Statement Syntax TiDB supports server-side Prepared statements, which can reduce the load of statement parsing and query optimization and improve execution efficiency. You can use Prepared statements in two ways: application programs and SQL statements.Use application programs Most MySQL Drivers support Prepared statements, such as MySQL Connector/C. You can call the Prepared statement API directly through the Binary protocol.Use SQL statements You can also implement Prepared statements using PREPARE, EXECUTE and DEALLOCATE PREPARE. This approach is not as efficient as the application programs, but you do not need to write a program.PREPARE statement PREPARE stmt_name FROM preparable_stmt The PREPARE statement preprocesses preparable_stmt (syntax parsing, semantic check and query optimization) and names the result as stmt_name. The following operations can refer to it using stmt_name. Processed statements can be executed using the EXECUTE statement or released using the DEALLOCATE PREPARE statement.EXECUTE statement EXECUTE stmt_name [USING @var_name [, @var_name] ...] The EXECUTE statement executes the prepared statements named as stmt_name. If parameters exist in the prepared statements, use the User Variable list in the USING clause to assign values to parameters.DEALLOCATE PREPARE statement {DEALLOCATE | DROP} PREPARE stmt_name The DEALLOCATE PREPARE statement is used to delete the result of the prepared statements returned by PREPARE.For more information, see MySQL Prepared Statement Syntax."}, {"url": "https://pingcap.com/docs/v1.0/sql/prepare/", "title": "Prepared SQL Statement Syntax", "content": " Prepared SQL Statement Syntax TiDB supports server-side Prepared statements, which can reduce the load of statement parsing and query optimization and improve execution efficiency. You can use Prepared statements in two ways: application programs and SQL statements.Use application programs Most MySQL Drivers support Prepared statements, such as MySQL Connector/C. You can call the Prepared statement API directly through the Binary protocol.Use SQL statements You can also implement Prepared statements using PREPARE, EXECUTE and DEALLOCATE PREPARE. This approach is not as efficient as the application programs, but you do not need to write a program.PREPARE statement PREPARE stmt_name FROM preparable_stmt The PREPARE statement preprocesses preparable_stmt (syntax parsing, semantic check and query optimization) and names the result as stmt_name. The following operations can refer to it using stmt_name. Processed statements can be executed using the EXECUTE statement or released using the DEALLOCATE PREPARE statement.EXECUTE statement EXECUTE stmt_name [USING @var_name [, @var_name] ...] The EXECUTE statement executes the prepared statements named as stmt_name. If parameters exist in the prepared statements, use the User Variable list in the USING clause to assign values to parameters.DEALLOCATE PREPARE statement {DEALLOCATE | DROP} PREPARE stmt_name The DEALLOCATE PREPARE statement is used to delete the result of the prepared statements returned by PREPARE.For more information, see MySQL Prepared Statement Syntax."}, {"url": "https://pingcap.com/docs/v2.0/sql/prepare/", "title": "Prepared SQL Statement Syntax", "content": " Prepared SQL Statement Syntax TiDB supports server-side Prepared statements, which can reduce the load of statement parsing and query optimization and improve execution efficiency. You can use Prepared statements in two ways: application programs and SQL statements.Use application programs Most MySQL Drivers support Prepared statements, such as MySQL Connector/C. You can call the Prepared statement API directly through the Binary protocol.Use SQL statements You can also implement Prepared statements using PREPARE, EXECUTE and DEALLOCATE PREPARE. This approach is not as efficient as the application programs, but you do not need to write a program.PREPARE statement PREPARE stmt_name FROM preparable_stmt The PREPARE statement preprocesses preparable_stmt (syntax parsing, semantic check and query optimization) and names the result as stmt_name. The following operations can refer to it using stmt_name. Processed statements can be executed using the EXECUTE statement or released using the DEALLOCATE PREPARE statement.EXECUTE statement EXECUTE stmt_name [USING @var_name [, @var_name] ...] The EXECUTE statement executes the prepared statements named as stmt_name. If parameters exist in the prepared statements, use the User Variable list in the USING clause to assign values to parameters.DEALLOCATE PREPARE statement {DEALLOCATE | DROP} PREPARE stmt_name The DEALLOCATE PREPARE statement is used to delete the result of the prepared statements returned by PREPARE.For more information, see MySQL Prepared Statement Syntax."}, {"url": "https://pingcap.com/docs-cn/sql/prepare/", "title": "Prepared SQL 语句语法", "content": " Prepared SQL 语句语法 TiDB 支持服务器端的 Prepared 语句,这种方式可以降低语句解析以及查询优化的开销,提高执行效率。有两种方式可以使用 Prepared 语句:通过应用程序 大多数 MySQL Driver 都支持 Prepared 语句,比如 MySQL Connector/C。这种方式可以通过 Binary 协议直接调用 Prepared 语句 API。通过 SQL 语句 通过 PREPARE,EXECUTE 以及 DEALLOCATE PREPARE 这三个语句也可以实现 Prepared 语句,这种方式不如第一种方式效率高,但是不需要写程序即可使用。PREPARE 语句 PREPARE stmt_name FROM preparable_stmt PREPARE 语句对 preparable_stmt 做预处理(语法解析、语义检查、查询优化)并将其处理结果命名为 stmt_name,后面的操作可以通过 stmt_name 来引用。处理好的语句可以通过 EXECUTE 语句执行或者是通过 DEALLOCATE PREPARE 语句释放。EXECUTE 语句 EXECUTE stmt_name [USING @var_name [, @var_name] ...] EXECUTE 语句执行名字为 stmt_name 的预处理语句。如果预处理语句中有参数,则可以通过 USING 子句中的 User Variable 列表给参数赋值。DEALLOCATE PREPARE 语句 {DEALLOCATE | DROP} PREPARE stmt_name DEALLOCATE PREPARE 语句删除 PREPARE 产生的预处理语句结果。更多信息请参考 MySQL Prepared Statement Syntax。"}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/prepare/", "title": "Prepared SQL 语句语法", "content": " Prepared SQL 语句语法 TiDB 支持服务器端的 Prepared 语句,这种方式可以降低语句解析以及查询优化的开销,提高执行效率。有两种方式可以使用 Prepared 语句:通过应用程序 大多数 MySQL Driver 都支持 Prepared 语句,比如 MySQL Connector/C。这种方式可以通过 Binary 协议直接调用 Prepared 语句 API。通过 SQL 语句 通过 PREPARE,EXECUTE 以及 DEALLOCATE PREPARE 这三个语句也可以实现 Prepared 语句,这种方式不如第一种方式效率高,但是不需要写程序即可使用。PREPARE 语句 PREPARE stmt_name FROM preparable_stmt PREPARE 语句对 preparable_stmt 做预处理(语法解析、语义检查、查询优化)并将其处理结果命名为 stmt_name,后面的操作可以通过 stmt_name 来引用。处理好的语句可以通过 EXECUTE 语句执行或者是通过 DEALLOCATE PREPARE 语句释放。EXECUTE 语句 EXECUTE stmt_name [USING @var_name [, @var_name] ...] EXECUTE 语句执行名字为 stmt_name 的预处理语句。如果预处理语句中有参数,则可以通过 USING 子句中的 User Variable 列表给参数赋值。DEALLOCATE PREPARE 语句 {DEALLOCATE | DROP} PREPARE stmt_name DEALLOCATE PREPARE 语句删除 PREPARE 产生的预处理语句结果。更多信息请参考 MySQL Prepared Statement Syntax。"}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/prepare/", "title": "Prepared SQL 语句语法", "content": " Prepared SQL 语句语法 TiDB 支持服务器端的 Prepared 语句,这种方式可以降低语句解析以及查询优化的开销,提高执行效率。有两种方式可以使用 Prepared 语句:通过应用程序 大多数 MySQL Driver 都支持 Prepared 语句,比如 MySQL Connector/C。这种方式可以通过 Binary 协议直接调用 Prepared 语句 API。通过 SQL 语句 通过 PREPARE,EXECUTE 以及 DEALLOCATE PREPARE 这三个语句也可以实现 Prepared 语句,这种方式不如第一种方式效率高,但是不需要写程序即可使用。PREPARE 语句 PREPARE stmt_name FROM preparable_stmt PREPARE 语句对 preparable_stmt 做预处理(语法解析、语义检查、查询优化)并将其处理结果命名为 stmt_name,后面的操作可以通过 stmt_name 来引用。处理好的语句可以通过 EXECUTE 语句执行或者是通过 DEALLOCATE PREPARE 语句释放。EXECUTE 语句 EXECUTE stmt_name [USING @var_name [, @var_name] ...] EXECUTE 语句执行名字为 stmt_name 的预处理语句。如果预处理语句中有参数,则可以通过 USING 子句中的 User Variable 列表给参数赋值。DEALLOCATE PREPARE 语句 {DEALLOCATE | DROP} PREPARE stmt_name DEALLOCATE PREPARE 语句删除 PREPARE 产生的预处理语句结果。更多信息请参考 MySQL Prepared Statement Syntax。"}, {"url": "https://pingcap.com/privacy-policy/", "title": "Privacy Policy", "content": " PINGCAP PRIVACY POLICY Effective Date: October 10, 2018PingCAP obtains and uses personal information about individuals to enhance our ability to deliver the highest level of service, but we also recognize that you expect us to treat this information appropriately. This privacy policy explains how PingCAP uses, shares and protects personal information that it collects on pingcap.com and any related mobile applications and websites operated by PingCAP (“Site”).By visiting the Site or purchasing, enrolling in or using our product and services, you agree to this Privacy Policy, as it may be amended from time to time. This Privacy Policy is incorporated into the Terms of Service.The Sources of Information PingCAP collects personal information from you in various ways, including when you visit the Site, create an account with us, purchase, enroll in and use our programs, participate in our social media communities, such as on Twitter, and when you send us feedback.The personal information we collect about you personally may include: Your name and contact details; Company name; Course and training module enrollments, course access dates/times and course completion data; Your stated and inferred interests; Credit card details; Your activity on the Site, both in terms of transactions (such as order history) and in terms of otherwise interacting with the Site (e.g., behavioral patterns such as your consumption of content, purchase of products/services available through the Site, and other data and analytics) Cookies and Automatic Collection of Data “Cookies” are small text files that may be placed on your web browser when you visit our Site. You can, of course, disable cookies and web beacons on your computer by indicating this in the preferences or options menus in your browser. If you opt not to accept cookies, you may not be able to benefit from the full features of our site. Some of the cookies we use are automatically deleted from your hard drive after the end of the browser session (session cookies). We also use cookies that remain on your hard drive for a certain period of time (between one day and five years, depending on the cookie) after the browser session. When you revisit our site, it may automatically recall the country and language you selected at your last visit to our Site. These “persistent cookies” are stored on your hard drive and will be deleted by the browser after the given time.We may also use web beacons, and other technologies, to help track whether our communications are reaching you, to measure their effectiveness, or to collect certain non-personal information about your computer, device, or browser in order to allow us to better design future communications to you. “Clickstream” data (e.g., information regarding which of our Web pages you access, the frequency of such access, and your product and service preferences) may be collected by PingCAP itself, or by our service providers, using cookies, Web beacons, page tags, or similar tools that are set when you visit our Site or when you view an advertisement we have placed on another website. Clickstream data and similar information may be used: for administrative purposes; to assess the usage, value and performance of our online products and services; to provide you with information concerning products and services offered by PingCAP; to improve your experience with our Site; and as otherwise permitted by applicable law or regulation. If you are a PingCAP client, this information helps us suggest products or service offerings that may be of interest to you. This information may be processed by us for the purposes described above, or on our behalf by third parties, solely in accordance with our instructions.When you visit this site, your browser may be momentarily directed to the website of an ad server or other third party service provider. This re-direction process will not be apparent to you. These third party websites automatically receive your IP address when this happens, and they may also collect information from your interaction with our Site including computer and connection information, standard web log information, and ad information. Such information does not identify you individually.Some web browsers and devices permit you to broadcast a preference that you not be “tracked” online. We do not modify your online experience based upon whether such a signal is broadcast.Our Use of Your Personal Information We may use your personal information for multiple internal and external purposes, including but not limited to: Administering, facilitating and managing your relationship and/or account with PingCAP. Providing the service or product requested; Analyzing and reporting on your and other participants’ performance; Providing you with information about related products and services, based on the preferences you have indicated; Improving our Site; Developing new products and services; Administering PingCAP’s systems and troubleshooting purposes; and Facilitating our internal business operations, including assessing and managing risk and fulfilling our legal and regulatory requirements. If your relationship with PingCAP ends, PingCAP will continue to treat your personal information, to the extent we retain it, as described in this policy.For United States residents, we undertake marketing only in compliance with the CAN-SPAM Act, the Telephone Consumer Protection Act, and other applicable law. For European Union residents, we undertake marketing only with your express affirmative consent and in compliance with applicable data privacy laws. EU residents will not be added to the marketing lists unless they have already provided express affirmative consent consistent with applicable data protection laws.Disclosures of Your Personal Information to Third Parties PingCAP does not share personal information with unaffiliated third parties for those third parties’ own purposes. PingCAP may, however, share personal information with our third party service providers, agents, contractors, or partners in connection with services that these individuals or entities perform for, or with PingCAP.Third Parties that assist PingCAP in providing services to you are required to maintain the confidentiality of such information to the extent they receive it and to use your personal information only in the course of providing such services to PingCAP and only for the purposes that PingCAP dictates.PingCAP may also disclose your personal information to investigate, establish, and protect PingCAP’s legal rights and interests or pursuant to your express consent. Under limited circumstances, your personal information may be disclosed to third parties as permitted by, or to comply with, applicable laws and regulations; for instance, when responding to a subpoena or similar legal process, to protect against fraud and to otherwise cooperate with law enforcement or regulatory authorities.We may transfer or share a copy of personal information about you in the event that PingCAP or one of its assets, affiliates, or subsidiaries goes through a business transition, such as a merger, being acquired by another company, being reorganized or liquidated, or by selling a portion of its assets. Nothing in this Privacy Policy is intended to interfere with the ability of PingCAP to transfer all or part of its business and/or assets to an affiliate or independent third party at any time, for any purpose, without any limitation whatsoever. PingCAP specifically reserves the right to transfer or share a copy of personally identifiable information collected from its Site to the buyer of that portion of its business relating to that information during any diligence process.Data Quality, Storage, and Access While we make every effort to ensure that all information we hold about you is accurate, complete and up to date, you can help us by promptly notifying us if there are …"}, {"url": "https://pingcap.com/docs/sql/privilege/", "title": "Privilege Management", "content": " Privilege Management TiDB’s privilege management system is implemented according to the privilege management system in MySQL. It supports most of the syntaxes and privilege types in MySQL. If you find any inconsistency with MySQL, feel free to open an issue.Examples User account operation TiDB user account names consist of a user name and a host name. The account name syntax is 'user_name'@'host_name'. The user_name is case sensitive. The host_name can be a host name or an IP address. The % and _ wildcard characters are permitted in host name or IP address values. For example, a host value of '%' matches any host name and '192.168.1.%' matches every host on a subnet. Create user The CREATE USER statement creates new MySQL accounts.CREATE USER 'test'@'127.0.0.1' IDENTIFIED BY 'xxx'; If the host name is not specified, you can log in from any IP address. If the password is not specified, it is empty by default:CREATE USER 'test'; Equals:CREATE USER 'test'@'%' IDENTIFIED BY ''; Required Privilege: To use CREATE USER, you must have the global CREATE USER privilege.Change the password You can use the SET PASSWORD syntax to assign or modify a password to a user account.SET PASSWORD FOR 'root'@'%' = 'xxx'; Required Privilege: Operations that assign or modify passwords are permitted only to users with the CREATE USER privilege.Drop user The DROP USER statement removes one or more MySQL accounts and their privileges. It removes the user record entries in the mysql.user table and the privilege rows for the account from all grant tables.DROP USER 'test'@'%'; Required Privilege: To use DROP USER, you must have the global CREATE USER privilege.Reset the root password If you forget the root password, you can skip the privilege system and use the root privilege to reset the password.To reset the root password, Start TiDB with a special startup option (root privilege required):sudo ./tidb-server -skip-grant-table=true Use the root account to log in and reset the password:mysql -h 127.0.0.1 -P 4000 -u root Privilege-related operations Grant privileges The GRANT statement grants privileges to the user accounts.For example, use the following statement to grant the xxx user the privilege to read the test database.GRANT SELECT ON test.* TO 'xxx'@'%'; Use the following statement to grant the xxx user all privileges on all databases:GRANT ALL PRIVILEGES ON *.* TO 'xxx'@'%'; If the granted user does not exist, TiDB will automatically create a user.mysql> SELECT * FROM mysql.user WHERE user='xxxx'; Empty set (0.00 sec) mysql> GRANT ALL PRIVILEGES ON test.* TO 'xxxx'@'%' IDENTIFIED BY 'yyyyy'; Query OK, 0 rows affected (0.00 sec) mysql> SELECT user,host FROM mysql.user WHERE user='xxxx'; +------|------+ | user | host | +------|------+ | xxxx | % | +------|------+ 1 row in set (0.00 sec) In this example, xxxx@% is the user that is automatically created. Note: Granting privileges to a database or table does not check if the database or table exists. mysql> SELECT * FROM test.xxxx; ERROR 1146 (42S02): Table 'test.xxxx' doesn't exist mysql> GRANT ALL PRIVILEGES ON test.xxxx TO xxxx; Query OK, 0 rows affected (0.00 sec) mysql> SELECT user,host FROM mysql.tables_priv WHERE user='xxxx'; +------|------+ | user | host | +------|------+ | xxxx | % | +------|------+ 1 row in set (0.00 sec) You can use fuzzy matching to grant privileges to databases and tables.mysql> GRANT ALL PRIVILEGES ON `te%`.* TO genius; Query OK, 0 rows affected (0.00 sec) mysql> SELECT user,host,db FROM mysql.db WHERE user='genius'; +--------|------|-----+ | user | host | db | +--------|------|-----+ | genius | % | te% | +--------|------|-----+ 1 row in set (0.00 sec) In this example, because of the % in te%, all the databases starting with te are granted the privilege.Revoke privileges The REVOKE statement enables system administrators to revoke privileges from the user accounts.The REVOKE statement corresponds with the REVOKE statement:REVOKE ALL PRIVILEGES ON `test`.* FROM 'genius'@'localhost'; Note: To revoke privileges, you need the exact match. If the matching result cannot be found, an error will be displayed: mysql> REVOKE ALL PRIVILEGES ON `te%`.* FROM 'genius'@'%'; ERROR 1141 (42000): There is no such grant defined for user 'genius' on host '%' About fuzzy matching, escape, string and identifier:mysql> GRANT ALL PRIVILEGES ON `te%`.* TO 'genius'@'localhost'; Query OK, 0 rows affected (0.00 sec) This example uses exact match to find the database named te%. Note that the % uses the escape character so that % is not considered as a wildcard.A string is enclosed in single quotation marks(“), while an identifier is enclosed in backticks (``). See the differences below:mysql> GRANT ALL PRIVILEGES ON 'test'.* TO 'genius'@'localhost'; ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''test'.* to 'genius'@'localhost'' at line 1 mysql> GRANT ALL PRIVILEGES ON `test`.* TO 'genius'@'localhost'; Query OK, 0 rows affected (0.00 sec) If you want to use special keywords as table names, enclose them in backticks (``). For example:mysql> CREATE TABLE `select` (id int); Query OK, 0 rows affected (0.27 sec) Check privileges granted to user You can use the SHOW GRANTS statement to see what privileges are granted to a user. For example:SHOW GRANTS; -- show grants for the current user SHOW GRANTS FOR 'root'@'%'; -- show grants for a specific user To be more precise, you can check the privilege information in the Grant table. For example, you can use the following steps to check if the test@% user has the Insert privilege on db1.t: Check if test@% has global Insert privilege:SELECT Insert_priv FROM mysql.user WHERE user='test' AND host='%'; If not, check if test@% has database-level Insert privilege at db1:SELECT Insert_priv FROM mysql.db WHERE user='test' AND host='%'; If the result is still empty, check whether test@% has table-level Insert privilege at db1.t:SELECT table_priv FROM mysql.tables_priv WHERE user='test' AND host='%' AND db='db1'; Implementation of the privilege system Grant table The following system tables are special because all the privilege-related data is stored in them: mysql.user (user account, global privilege) mysql.db (database-level privilege) mysql.tables_priv (table-level privilege) mysql.columns_priv (column-level privilege; not currently supported) These tables contain the effective range and privilege information of the data. For example, in the mysql.user table:mysql> SELECT User,Host,Select_priv,Insert_priv FROM mysql.user LIMIT 1; +------|------|-------------|-------------+ | User | Host | Select_priv | Insert_priv | +------|------|-------------|-------------+ | root | % | Y | Y | +------|------|-------------|-------------+ 1 row in set (0.00 sec) In this record, Host and User determine that the connection request sent by the root user from any host (%) can be accepted. Select_priv and Insert_priv mean that the user has global Select and Insert privilege. The effective range in the mysql.user table is global.Host and User in mysql.db determine which databases users can access. The effective range is the database.In theory, all privilege-related operations can be done directly by the CRUD operations on the grant table.On the implementation level, only a layer of syntactic sugar is added. For example, you can use the following command to remove a user:DELETE FROM mysql.user WHERE user='test'; However, the recommended usage is …"}, {"url": "https://pingcap.com/docs/v1.0/sql/privilege/", "title": "Privilege Management", "content": " Privilege Management Privilege management overview TiDB’s privilege management system is implemented according to the privilege management system in MySQL. It supports most of the syntaxes and privilege types in MySQL. If you find any inconsistency with MySQL, feel free to open an issue.Examples User account operation TiDB user account names consist of a user name and a host name. The account name syntax is 'user_name'@'host_name'. The user_name is case sensitive. The host_name can be a host name or an IP address. The % and _ wildcard characters are permitted in host name or IP address values. For example, a host value of '%' matches any host name and '192.168.1.%' matches every host on a subnet. Create user The CREATE USER statement creates new MySQL accounts.create user 'test'@'127.0.0.1' identified by 'xxx'; If the host name is not specified, you can log in from any IP address. If the password is not specified, it is empty by default:create user 'test'; Equals:create user 'test'@'%' identified by ''; Required Privilege: To use CREATE USER, you must have the global CREATE USER privilege.Change the password You can use the SET PASSWORD syntax to assign or modify a password to a user account.set password for 'root'@'%' = 'xxx'; Required Privilege: Operations that assign or modify passwords are permitted only to users with the CREATE USER privilege.Drop user The DROP USER statement removes one or more MySQL accounts and their privileges. It removes the user record entries in the mysql.user table and the privilege rows for the account from all grant tables.drop user 'test'@'%'; Required Privilege: To use DROP USER, you must have the global CREATE USER privilege.Reset the root password If you forget the root password, you can skip the privilege system and use the root privilege to reset the password.To reset the root password, Start TiDB with a special startup option (root privilege required):sudo ./tidb-server -skip-grant-table=true Use the root account to log in and reset the password:mysql -h 127.0.0.1 -P 4000 -u root Privilege-related operations Grant privileges The GRANT statement grants privileges to the user accounts.For example, use the following statement to grant the xxx user the privilege to read the test database.grant Select on test.* to 'xxx'@'%'; Use the following statement to grant the xxx user all privileges on all databases:grant all privileges on *.* to 'xxx'@'%'; If the granted user does not exist, TiDB will automatically create a user.mysql> select * from mysql.user where user='xxxx'; Empty set (0.00 sec) mysql> grant all privileges on test.* to 'xxxx'@'%' identified by 'yyyyy'; Query OK, 0 rows affected (0.00 sec) mysql> select user,host from mysql.user where user='xxxx'; +------|------+ | user | host | +------|------+ | xxxx | % | +------|------+ 1 row in set (0.00 sec) In this example, xxxx@% is the user that is automatically created. Note: Granting privileges to a database or table does not check if the database or table exists. mysql> select * from test.xxxx; ERROR 1146 (42S02): Table 'test.xxxx' doesn't exist mysql> grant all privileges on test.xxxx to xxxx; Query OK, 0 rows affected (0.00 sec) mysql> select user,host from mysql.tables_priv where user='xxxx'; +------|------+ | user | host | +------|------+ | xxxx | % | +------|------+ 1 row in set (0.00 sec) You can use fuzzy matching to grant privileges to databases and tables.mysql> grant all privileges on `te%`.* to genius; Query OK, 0 rows affected (0.00 sec) mysql> select user,host,db from mysql.db where user='genius'; +--------|------|-----+ | user | host | db | +--------|------|-----+ | genius | % | te% | +--------|------|-----+ 1 row in set (0.00 sec) In this example, because of the % in te%, all the databases starting with te are granted the privilege.Revoke privileges The REVOKE statement enables system administrators to revoke privileges from the user accounts.The REVOKE statement corresponds with the REVOKE statement:revoke all privileges on `test`.* from 'genius'@'localhost'; Note: To revoke privileges, you need the exact match. If the matching result cannot be found, an error will be displayed: ``` mysql> revoke all privileges on `te%`.* from 'genius'@'%'; ERROR 1141 (42000): There is no such grant defined for user 'genius' on host '%' ``` About fuzzy matching, escape, string and identifier:mysql> grant all privileges on `te%`.* to 'genius'@'localhost'; Query OK, 0 rows affected (0.00 sec) This example uses exact match to find the database named te%. Note that the % uses the escape character so that % is not considered as a wildcard.A string is enclosed in single quotation marks(“), while an identifier is enclosed in backticks (``). See the differences below:mysql> grant all privileges on 'test'.* to 'genius'@'localhost'; ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''test'.* to 'genius'@'localhost'' at line 1 mysql> grant all privileges on `test`.* to 'genius'@'localhost'; Query OK, 0 rows affected (0.00 sec) If you want to use special keywords as table names, enclose them in backticks (``). For example:mysql> create table `select` (id int); Query OK, 0 rows affected (0.27 sec) Check privileges granted to user You can use the show grant statement to see what privileges are granted to a user.show grants for 'root'@'%'; To be more precise, you can check the privilege information in the Grant table. For example, you can use the following steps to check if the test@% user has the Insert privilege on db1.t: Check if test@% has global Insert privilege:select Insert from mysql.user where user='test' and host='%'; If not, check if test@% has database-level Insert privilege at db1:select Insert from mysql.db where user='test' and host='%'; If the result is still empty, check whether test@% has table-level Insert privilege at db1.t:select tables_priv from mysql.tables_priv where user='test' and host='%' and db='db1'; Implementation of the privilege system Grant table The following system tables are special because all the privilege-related data is stored in them: mysql.user (user account, global privilege) mysql.db (database-level privilege) mysql.tables_priv (table-level privilege) mysql.columns_priv (column-level privilege) These tables contain the effective range and privilege information of the data. For example, in the mysql.user table:mysql> select User,Host,Select_priv,Insert_priv from mysql.user limit 1; +------|------|-------------|-------------+ | User | Host | Select_priv | Insert_priv | +------|------|-------------|-------------+ | root | % | Y | Y | +------|------|-------------|-------------+ 1 row in set (0.00 sec) In this record, Host and User determine that the connection request sent by the root user from any host (%) can be accepted. Select_priv and Insert_priv mean that the user has global Select and Insert privilege. The effective range in the mysql.user table is global.Host and User in mysql.db determine which databases users can access. The effective range is the database.In theory, all privilege-related operations can be done directly by the CRUD operations on the grant table.On the implementation level, only a layer of syntactic sugar is added. For example, you can use the following command to remove a user:delete from mysql.user where user='test'; However, it’s not recommended to manually modify the grant table.Connection verification When the client sends a connection …"}, {"url": "https://pingcap.com/docs/v2.0/sql/privilege/", "title": "Privilege Management", "content": " Privilege Management TiDB’s privilege management system is implemented according to the privilege management system in MySQL. It supports most of the syntaxes and privilege types in MySQL. If you find any inconsistency with MySQL, feel free to open an issue.Examples User account operation TiDB user account names consist of a user name and a host name. The account name syntax is 'user_name'@'host_name'. The user_name is case sensitive. The host_name can be a host name or an IP address. The % and _ wildcard characters are permitted in host name or IP address values. For example, a host value of '%' matches any host name and '192.168.1.%' matches every host on a subnet. Create user The CREATE USER statement creates new MySQL accounts.create user 'test'@'127.0.0.1' identified by 'xxx'; If the host name is not specified, you can log in from any IP address. If the password is not specified, it is empty by default:create user 'test'; Equals:create user 'test'@'%' identified by ''; Required Privilege: To use CREATE USER, you must have the global CREATE USER privilege.Change the password You can use the SET PASSWORD syntax to assign or modify a password to a user account.set password for 'root'@'%' = 'xxx'; Required Privilege: Operations that assign or modify passwords are permitted only to users with the CREATE USER privilege.Drop user The DROP USER statement removes one or more MySQL accounts and their privileges. It removes the user record entries in the mysql.user table and the privilege rows for the account from all grant tables.drop user 'test'@'%'; Required Privilege: To use DROP USER, you must have the global CREATE USER privilege.Reset the root password If you forget the root password, you can skip the privilege system and use the root privilege to reset the password.To reset the root password, Start TiDB with a special startup option (root privilege required):sudo ./tidb-server -skip-grant-table=true Use the root account to log in and reset the password:mysql -h 127.0.0.1 -P 4000 -u root Privilege-related operations Grant privileges The GRANT statement grants privileges to the user accounts.For example, use the following statement to grant the xxx user the privilege to read the test database.grant Select on test.* to 'xxx'@'%'; Use the following statement to grant the xxx user all privileges on all databases:grant all privileges on *.* to 'xxx'@'%'; If the granted user does not exist, TiDB will automatically create a user.mysql> select * from mysql.user where user='xxxx'; Empty set (0.00 sec) mysql> grant all privileges on test.* to 'xxxx'@'%' identified by 'yyyyy'; Query OK, 0 rows affected (0.00 sec) mysql> select user,host from mysql.user where user='xxxx'; +------|------+ | user | host | +------|------+ | xxxx | % | +------|------+ 1 row in set (0.00 sec) In this example, xxxx@% is the user that is automatically created. Note: Granting privileges to a database or table does not check if the database or table exists. mysql> select * from test.xxxx; ERROR 1146 (42S02): Table 'test.xxxx' doesn't exist mysql> grant all privileges on test.xxxx to xxxx; Query OK, 0 rows affected (0.00 sec) mysql> select user,host from mysql.tables_priv where user='xxxx'; +------|------+ | user | host | +------|------+ | xxxx | % | +------|------+ 1 row in set (0.00 sec) You can use fuzzy matching to grant privileges to databases and tables.mysql> grant all privileges on `te%`.* to genius; Query OK, 0 rows affected (0.00 sec) mysql> select user,host,db from mysql.db where user='genius'; +--------|------|-----+ | user | host | db | +--------|------|-----+ | genius | % | te% | +--------|------|-----+ 1 row in set (0.00 sec) In this example, because of the % in te%, all the databases starting with te are granted the privilege.Revoke privileges The REVOKE statement enables system administrators to revoke privileges from the user accounts.The REVOKE statement corresponds with the REVOKE statement:revoke all privileges on `test`.* from 'genius'@'localhost'; Note: To revoke privileges, you need the exact match. If the matching result cannot be found, an error will be displayed: ``` mysql> revoke all privileges on `te%`.* from 'genius'@'%'; ERROR 1141 (42000): There is no such grant defined for user 'genius' on host '%' ``` About fuzzy matching, escape, string and identifier:mysql> grant all privileges on `te%`.* to 'genius'@'localhost'; Query OK, 0 rows affected (0.00 sec) This example uses exact match to find the database named te%. Note that the % uses the escape character so that % is not considered as a wildcard.A string is enclosed in single quotation marks(“), while an identifier is enclosed in backticks (``). See the differences below:mysql> grant all privileges on 'test'.* to 'genius'@'localhost'; ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''test'.* to 'genius'@'localhost'' at line 1 mysql> grant all privileges on `test`.* to 'genius'@'localhost'; Query OK, 0 rows affected (0.00 sec) If you want to use special keywords as table names, enclose them in backticks (``). For example:mysql> create table `select` (id int); Query OK, 0 rows affected (0.27 sec) Check privileges granted to user You can use the show grant statement to see what privileges are granted to a user.show grants for 'root'@'%'; To be more precise, you can check the privilege information in the Grant table. For example, you can use the following steps to check if the test@% user has the Insert privilege on db1.t: Check if test@% has global Insert privilege:select Insert_priv from mysql.user where user='test' and host='%'; If not, check if test@% has database-level Insert privilege at db1:select Insert_priv from mysql.db where user='test' and host='%'; If the result is still empty, check whether test@% has table-level Insert privilege at db1.t:select table_priv from mysql.tables_priv where user='test' and host='%' and db='db1'; Implementation of the privilege system Grant table The following system tables are special because all the privilege-related data is stored in them: mysql.user (user account, global privilege) mysql.db (database-level privilege) mysql.tables_priv (table-level privilege) mysql.columns_priv (column-level privilege) These tables contain the effective range and privilege information of the data. For example, in the mysql.user table:mysql> select User,Host,Select_priv,Insert_priv from mysql.user limit 1; +------|------|-------------|-------------+ | User | Host | Select_priv | Insert_priv | +------|------|-------------|-------------+ | root | % | Y | Y | +------|------|-------------|-------------+ 1 row in set (0.00 sec) In this record, Host and User determine that the connection request sent by the root user from any host (%) can be accepted. Select_priv and Insert_priv mean that the user has global Select and Insert privilege. The effective range in the mysql.user table is global.Host and User in mysql.db determine which databases users can access. The effective range is the database.In theory, all privilege-related operations can be done directly by the CRUD operations on the grant table.On the implementation level, only a layer of syntactic sugar is added. For example, you can use the following command to remove a user:delete from mysql.user where user='test'; However, it’s not recommended to manually modify the grant table.Connection verification When the client sends a connection request, TiDB server will …"}, {"url": "https://pingcap.com/tidb-academy/mysql_dbas/query-optimization/lab/", "title": "Query Optimization", "content": " Query Optimization "}, {"url": "https://pingcap.com/tidb-academy/mysql_dbas/query-optimization/overview/", "title": "Query Optimization", "content": " Query Optimization Transcript When you look at a query, such as SELECT * FROM trips WHERE bike_id = 'x', you can’t actually tell if it executes efficiently. This is because SQL is declarative and it defines what the result or the output should look like. It is not procedural or a set of steps on how to produce that result. For example, do x, then do y, then combine the two.In many ways, an SQL query is like a physical address that you type into GPS navigation. The GPS navigator figures out the procedure or set of navigation steps. You are just defining the final location. And a good navigation system takes you on the most efficient route. We expect very similar properties between these two systems: GPS navigation and query optimization.But where this analogy breaks down a little, is that with a database management system, we can add our own highways and effectively lay the data out in such a way that the query can be more efficient. I am of course talking about features like indexes and table partitioning.But we will build up to that. Query optimization all starts with asking the database management system to explain to you how it plans to execute a particular query.And on that note let‘s take a tour of the EXPLAIN command…"}, {"url": "https://pingcap.com/docs/op-guide/history-read/", "title": "Reading Data from History Versions", "content": " Reading Data From History Versions This document describes how TiDB reads data from the history versions, how TiDB manages the data versions, as well as an example to show how to use the feature.Feature description TiDB implements a feature to read history data using the standard SQL interface directly without special clients or drivers. By using this feature: Even when data is updated or removed, its history versions can be read using the SQL interface. Even if the table structure changes after the data is updated, TiDB can use the old structure to read the history data. How TiDB reads data from history versions The tidb_snapshot system variable is introduced to support reading history data. About the tidb_snapshot variable: The variable is valid in the Session scope. Its value can be modified using the Set statement. The data type for the variable is text. The variable accepts TSO (Timestamp Oracle) and datetime. TSO is a globally unique time service, which is obtained from PD. The acceptable datetime format is “2016-10-08 16:45:26.999”. Generally, the datetime can be set using second precision, for example “2016-10-08 16:45:26”. When the variable is set, TiDB creates a Snapshot using its value as the timestamp, just for the data structure and there is no any overhead. After that, all the Select operations will read data from this Snapshot. Note: Because the timestamp in TiDB transactions is allocated by Placement Driver (PD), the version of the stored data is also marked based on the timestamp allocated by PD. When a Snapshot is created, the version number is based on the value of the tidb_snapshot variable. If there is a large difference between the local time of the TiDB server and the PD server, use the time of the PD server. After reading data from history versions, you can read data from the latest version by ending the current Session or using the Set statement to set the value of the tidb_snapshot variable to “” (empty string).How TiDB manages the data versions TiDB implements Multi-Version Concurrency Control (MVCC) to manage data versions. The history versions of data are kept because each update/removal creates a new version of the data object instead of updating/removing the data object in-place. But not all the versions are kept. If the versions are older than a specific time, they will be removed completely to reduce the storage occupancy and the performance overhead caused by too many history versions.In TiDB, Garbage Collection (GC) runs periodically to remove the obsolete data versions. For GC details, see TiDB Garbage Collection (GC)Pay special attention to the following two variables: tikv_gc_life_time: It is used to configure the retention time of the history version. You can modify it manually. tikv_gc_safe_point: It records the current safePoint. You can safely create the snapshot to read the history data using the timestamp that is later than safePoint. safePoint automatically updates every time GC runs. Example At the initial stage, create a table and insert several rows of data:mysql> create table t (c int); Query OK, 0 rows affected (0.01 sec) mysql> insert into t values (1), (2), (3); Query OK, 3 rows affected (0.00 sec) View the data in the table:mysql> select * from t; +------+ | c | +------+ | 1 | | 2 | | 3 | +------+ 3 rows in set (0.00 sec) View the timestamp of the table:mysql> select now(); +---------------------+ | now() | +---------------------+ | 2016-10-08 16:45:26 | +---------------------+ 1 row in set (0.00 sec) Update the data in one row:mysql> update t set c=22 where c=2; Query OK, 1 row affected (0.00 sec) Make sure the data is updated:mysql> select * from t; +------+ | c | +------+ | 1 | | 22 | | 3 | +------+ 3 rows in set (0.00 sec) Set the tidb_snapshot variable whose scope is Session. The variable is set so that the latest version before the value can be read. Note: In this example, the value is set to be the time before the update operation. mysql> set @@tidb_snapshot="2016-10-08 16:45:26"; Query OK, 0 rows affected (0.00 sec) Note: You should use @@ instead of @ before tidb_snapshot because @@ is used to denote the system variable while @ is used to denote the user variable. Result: The read from the following statement is the data before the update operation, which is the history data.mysql> select * from t; +------+ | c | +------+ | 1 | | 2 | | 3 | +------+ 3 rows in set (0.00 sec) Set the tidb_snapshot variable to be “” (empty string) and you can read the data from the latest version:mysql> set @@tidb_snapshot=""; Query OK, 0 rows affected (0.00 sec)mysql> select * from t; +------+ | c | +------+ | 1 | | 22 | | 3 | +------+ 3 rows in set (0.00 sec) Note: You should use @@ instead of @ before tidb_snapshot because @@ is used to denote the system variable while @ is used to denote the user variable. "}, {"url": "https://pingcap.com/docs/v1.0/op-guide/history-read/", "title": "Reading Data from History Versions", "content": " Reading Data From History Versions This document describes how TiDB reads data from the history versions, how TiDB manages the data versions, as well as an example to show how to use the feature.Feature description TiDB implements a feature to read history data using the standard SQL interface directly without special clients or drivers. By using this feature, - Even when data is updated or removed, its history versions can be read using the SQL interface. - Even if the table structure changes after the data is updated, TiDB can use the old structure to read the history data.How TiDB reads data from history versions The tidb_snapshot system variable is introduced to support reading history data. About the tidb_snapshot variable: The variable is valid in the Session scope. Its value can be modified using the Set statement. The data type for the variable is text. The variable is to record time in the following format: “2016-10-08 16:45:26.999”. Generally, the time can be set to seconds like in “2016-10-08 16:45:26”. When the variable is set, TiDB creates a Snapshot using its value as the timestamp, just for the data structure and there is no any overhead. After that, all the Select operations will read data from this Snapshot. Note: Because the timestamp in TiDB transactions is allocated by Placement Driver (PD), the version of the stored data is also marked based on the timestamp allocated by PD. When a Snapshot is created, the version number is based on the value of the tidb_snapshot variable. If there is a large difference between the local time of the TiDB server and the PD server, use the time of the PD server. After reading data from history versions, you can read data from the latest version by ending the current Session or using the Set statement to set the value of the tidb_snapshot variable to “” (empty string).How TiDB manages the data versions TiDB implements Multi-Version Concurrency Control (MVCC) to manage data versions. The history versions of data are kept because each update / removal creates a new version of the data object instead of updating / removing the data object in-place. But not all the versions are kept. If the versions are older than a specific time, they will be removed completely to reduce the storage occupancy and the performance overhead caused by too many history versions.In TiDB, Garbage Collection (GC) runs periodically to remove the obsolete data versions. GC is triggered in the following way: There is a gc_worker goroutine running in the background of each TiDB server. In a cluster with multiple TiDB servers, one of the gc_worker goroutines will be automatically selected to be the leader. The leader is responsible for maintaining the GC state and sends GC commands to each TiKV region leader.The running record of GC is recorded in the system table of mysql.tidb as follows and can be monitored and configured using the SQL statements:mysql> select variable_name, variable_value from mysql.tidb; +-----------------------+----------------------------+ | variable_name | variable_value | +-----------------------+----------------------------+ | bootstrapped | True | | tikv_gc_leader_uuid | 55daa0dfc9c0006 | | tikv_gc_leader_desc | host:pingcap-pc5 pid:10549 | | tikv_gc_leader_lease | 20160927-13:18:28 +0800 CST| | tikv_gc_run_interval | 10m0s | | tikv_gc_life_time | 10m0s | | tikv_gc_last_run_time | 20160927-13:13:28 +0800 CST| | tikv_gc_safe_point | 20160927-13:03:28 +0800 CST| +-----------------------+----------------------------+ 7 rows in set (0.00 sec) Pay special attention to the following two rows: tikv_gc_life_time: This row is to configure the retention time of the history version and its default value is 10m. You can use SQL statements to configure it. For example, if you want all the data within one day to be readable, set this row to 24h by using the update mysql.tidb set variable_value='24h' where variable_name='tikv_gc_life_time' statement. The format is: “24h”, “2h30m”, “2.5h”. The unit of time can be: “h”, “m”, “s”. Note: If your data is updated very frequently, the following issues might occur if the value of the tikv_gc_life_time is set to be too large like in days or months: The more versions of the data, the more disk storage is occupied. A large amount of the history versions might slow down the query, especially the range queries like select count(*) from t. If the value of the tikv_gc_life_time variable is suddenly changed to be smaller while the database is running, it might lead to the removal of large amounts of history data and cause huge I/O burden. tikv_gc_safe_point: This row records the current safePoint. You can safely create the Snapshot to read the history data using the timestamp that is later than the safePoint. The safePoint automatically updates every time GC runs. Example At the initial stage, create a table and insert several rows of data:mysql> create table t (c int); Query OK, 0 rows affected (0.01 sec) mysql> insert into t values (1), (2), (3); Query OK, 3 rows affected (0.00 sec) View the data in the table:mysql> select * from t; +------+ | c | +------+ | 1 | | 2 | | 3 | +------+ 3 rows in set (0.00 sec) View the timestamp of the table:mysql> select now(); +---------------------+ | now() | +---------------------+ | 2016-10-08 16:45:26 | +---------------------+ 1 row in set (0.00 sec) Update the data in one row:mysql> update t set c=22 where c=2; Query OK, 1 row affected (0.00 sec) Make sure the data is updated:mysql> select * from t; +------+ | c | +------+ | 1 | | 22 | | 3 | +------+ 3 rows in set (0.00 sec) Set the tidb_snapshot variable whose scope is Session. The variable is set so that the latest version before the value can be read. Note: In this example, the value is set to be the time before the update operation. mysql> set @@tidb_snapshot="2016-10-08 16:45:26"; Query OK, 0 rows affected (0.00 sec) Result: The read from the following statement is the data before the update operation, which is the history data.mysql> select * from t; +------+ | c | +------+ | 1 | | 2 | | 3 | +------+ 3 rows in set (0.00 sec) Set the tidb_snapshot variable to be “” (empty string) and you can read the data from the latest version:mysql> set @@tidb_snapshot=""; Query OK, 0 rows affected (0.00 sec)mysql> select * from t; +------+ | c | +------+ | 1 | | 22 | | 3 | +------+ 3 rows in set (0.00 sec) "}, {"url": "https://pingcap.com/docs/v2.0/op-guide/history-read/", "title": "Reading Data from History Versions", "content": " Reading Data From History Versions This document describes how TiDB reads data from the history versions, how TiDB manages the data versions, as well as an example to show how to use the feature.Feature description TiDB implements a feature to read history data using the standard SQL interface directly without special clients or drivers. By using this feature, - Even when data is updated or removed, its history versions can be read using the SQL interface. - Even if the table structure changes after the data is updated, TiDB can use the old structure to read the history data.How TiDB reads data from history versions The tidb_snapshot system variable is introduced to support reading history data. About the tidb_snapshot variable: The variable is valid in the Session scope. Its value can be modified using the Set statement. The data type for the variable is text. The variable accepts TSO (Timestamp Oracle) and datetime. TSO is a globally unique time service, which is obtained from PD. The acceptable datetime format is “2016-10-08 16:45:26.999”. Generally, the datetime can be set using second precision, for example “2016-10-08 16:45:26”. When the variable is set, TiDB creates a Snapshot using its value as the timestamp, just for the data structure and there is no any overhead. After that, all the Select operations will read data from this Snapshot. Note: Because the timestamp in TiDB transactions is allocated by Placement Driver (PD), the version of the stored data is also marked based on the timestamp allocated by PD. When a Snapshot is created, the version number is based on the value of the tidb_snapshot variable. If there is a large difference between the local time of the TiDB server and the PD server, use the time of the PD server. After reading data from history versions, you can read data from the latest version by ending the current Session or using the Set statement to set the value of the tidb_snapshot variable to “” (empty string).How TiDB manages the data versions TiDB implements Multi-Version Concurrency Control (MVCC) to manage data versions. The history versions of data are kept because each update/removal creates a new version of the data object instead of updating/removing the data object in-place. But not all the versions are kept. If the versions are older than a specific time, they will be removed completely to reduce the storage occupancy and the performance overhead caused by too many history versions.In TiDB, Garbage Collection (GC) runs periodically to remove the obsolete data versions. For GC details, see TiDB Garbage Collection (GC)Pay special attention to the following two variables: tikv_gc_life_time: It is used to configure the retention time of the history version. You can modify it manually. tikv_gc_safe_point: It records the current safePoint. You can safely create the snapshot to read the history data using the timestamp that is later than safePoint. safePoint automatically updates every time GC runs. Example At the initial stage, create a table and insert several rows of data:mysql> create table t (c int); Query OK, 0 rows affected (0.01 sec) mysql> insert into t values (1), (2), (3); Query OK, 3 rows affected (0.00 sec) View the data in the table:mysql> select * from t; +------+ | c | +------+ | 1 | | 2 | | 3 | +------+ 3 rows in set (0.00 sec) View the timestamp of the table:mysql> select now(); +---------------------+ | now() | +---------------------+ | 2016-10-08 16:45:26 | +---------------------+ 1 row in set (0.00 sec) Update the data in one row:mysql> update t set c=22 where c=2; Query OK, 1 row affected (0.00 sec) Make sure the data is updated:mysql> select * from t; +------+ | c | +------+ | 1 | | 22 | | 3 | +------+ 3 rows in set (0.00 sec) Set the tidb_snapshot variable whose scope is Session. The variable is set so that the latest version before the value can be read. Note: In this example, the value is set to be the time before the update operation. mysql> set @@tidb_snapshot="2016-10-08 16:45:26"; Query OK, 0 rows affected (0.00 sec) Note: You should use @@ instead of @ before tidb_snapshot because @@ is used to denote the system variable while @ is used to denote the user variable. Result: The read from the following statement is the data before the update operation, which is the history data.mysql> select * from t; +------+ | c | +------+ | 1 | | 2 | | 3 | +------+ 3 rows in set (0.00 sec) Set the tidb_snapshot variable to be “” (empty string) and you can read the data from the latest version:mysql> set @@tidb_snapshot=""; Query OK, 0 rows affected (0.00 sec)mysql> select * from t; +------+ | c | +------+ | 1 | | 22 | | 3 | +------+ 3 rows in set (0.00 sec) Note: You should use @@ instead of @ before tidb_snapshot because @@ is used to denote the system variable while @ is used to denote the user variable. "}, {"url": "https://pingcap.com/tidb-academy/mysql_dbas/backup/backup-and-restore-lab-recap/", "title": "Recap: Backup and Restore", "content": " Recap: Backup and Restore "}, {"url": "https://pingcap.com/tidb-academy/mysql_dbas/htap/lab-recap/", "title": "Recap: HTAP", "content": " Recap: HTAP "}, {"url": "https://pingcap.com/tidb-academy/mysql_dbas/mysql-compatibility/lab-recap/", "title": "Recap: Load Sample Data Lab", "content": " Recap: Load Sample Data Lab "}, {"url": "https://pingcap.com/tidb-academy/mysql_dbas/monitoring/lab-recap/", "title": "Recap: Prometheus and Grafana", "content": " Recap: Prometheus and Grafana "}, {"url": "https://pingcap.com/tidb-academy/mysql_dbas/backup/restore-from-accidental-delete-lab-recap/", "title": "Recap: Restore from Accidental Delete", "content": " Recap: Restore from Accidental Delete "}, {"url": "https://pingcap.com/tidb-academy/mysql_dbas/scaling/lab-recap/", "title": "Recap: Scaling", "content": " Recap: Scaling "}, {"url": "https://pingcap.com/tidb-academy/mysql_dbas/ddl/lab-recap/", "title": "Recap: Schema Changes", "content": " Recap: Schema Changes "}, {"url": "https://pingcap.com/tidb-academy/mysql_dbas/backup/backup-and-restore-lab/", "title": "Recover from Disaster", "content": " Recover from Disaster "}, {"url": "https://pingcap.com/docs/releases/rn/", "title": "Release Notes", "content": " TiDB Release Notes 2.0.11 2.1.2 2.0.10 2.1.1 2.1 GA 2.0.9 2.1 RC5 2.1 RC4 2.0.8 2.1 RC3 2.1 RC2 2.0.7 2.1 RC1 2.0.6 2.0.5 2.1 Beta 2.0.4 2.0.3 2.0.2 2.0.1 2.0 2.0 RC5 2.0 RC4 2.0 RC3 2.0 RC1 1.1 Beta 1.0.8 1.0.7 1.1 Alpha 1.0.6 1.0.5 1.0.4 1.0.3 1.0.2 1.0.1 1.0 Pre-GA RC4 RC3 RC2 RC1 "}, {"url": "https://pingcap.com/docs/v1.0/releases/rn/", "title": "Release Notes", "content": " TiDB Release Notes 2.0 RC1 1.1 Beta 1.0.8 1.0.7 1.1 Alpha 1.0.6 1.0.5 1.0.4 1.0.3 1.0.2 1.0.1 1.0 Pre-GA RC4 RC3 RC2 RC1 "}, {"url": "https://pingcap.com/docs/v2.0/releases/rn/", "title": "Release Notes", "content": " TiDB Release Notes 2.1 RC1 2.0.6 2.0.5 2.1 Beta 2.0.4 2.0.3 2.0.2 2.0.1 2.0 2.0 RC5 2.0 RC4 2.0 RC3 2.0 RC1 1.1 Beta 1.0.8 1.0.7 1.1 Alpha 1.0.6 1.0.5 1.0.4 1.0.3 1.0.2 1.0.1 1.0 Pre-GA RC4 RC3 RC2 RC1 "}, {"url": "https://pingcap.com/tidb-planet/release-notes/", "title": "Release Notes", "content": ""}, {"url": "https://pingcap.com/docs/tools/reparo/", "title": "Reparo User Guide", "content": " Reparo User Guide Reparo is a TiDB-Binlog tool, used to recover the incremental data. To back up the incremental data, you can use Drainer of TiDB-Binlog to output the binlog data in the protobuf format to files. To restore the incremental data, you can use Reparo to parse the binlog data in the files and apply the binlog in TiDB/MySQL.Download Reparo via reparo-latest-linux-amd64.tar.gzReparo usage Description of command line parameters Usage of Reparo: -L string The level of the output information of logs Value: "debug"/"info"/"warn"/"error"/"fatal" ("info" by default) -V Prints the version. -config string The path of the configuration file If the configuration file is specified, Reparo reads the configuration data in this file. If the configuration data also exists in the command line parameters, Reparo uses the configuration data in the command line parameters to cover that in the configuration file. -data-dir string The storage directory for the binlog file in the protobuf format that Drainer outputs ("data.drainer" by default) -dest-type string The downstream service type Value: "print"/"mysql" ("print" by default) If it is set to "print", the data is parsed and printed to standard output while the SQL statement is not executed. If it is set to "mysql", you need to configure the "host", "port", "user" and "password" information in the configuration file. -log-file string The path of the log file -log-rotate string The switch frequency of log files Value: "hour"/"day" -start-datetime string Specifies the time point for starting recovery. Format: "2006-01-02 15:04:05" If it is not set, the recovery process starts from the earliest binlog file. -stop-datetime string Specifies the time point of finishing the recovery process. Format: "2006-01-02 15:04:05" If it is not set, the recovery process ends up with the last binlog file. Description of the configuration file # The storage directory for the binlog file in the protobuf format that Drainer outputs data-dir = "./data.drainer" # Uses the index file to locate `ts`. Set this parameter if `start-ts` is set. The file # directory is {data-dir}/{index-name}. # index-name = "binlog.index" # log-file = "" # log-rotate = "hour" # The level of the output information of logs # Value: "debug"/"info"/"warn"/"error"/"fatal" ("info" by default) log-level = "info" # Uses `start-datetime` and `stop-datetime` to specify the time range in which # the binlog files are to be recovered. # Format: "2006-01-02 15:04:05" # start-datetime = "" # stop-datetime = "" # Correspond to `start-datetime` and `stop-datetime` respectively. # They are used to specify the time range in which the binlog files are to be recovered. # If `start-datetime` and `stop-datetime` are set, there is no need to set `start-tso` and `stop-tso`. # start-tso = 0 # stop-tso = 0 # The downstream service type # Value: "print"/"mysql" ("print" by default) # If it is set to "print", the data is parsed and printed to standard output # while the SQL statement is not executed. # If it is set to "mysql", you need to configure `host`, `port`, `user` and `password` in [dest-db]. dest-type = "mysql" # `replicate-do-db` and `replicate-do-table` specify the database and table to be recovered. # `replicate-do-db` has priority over `replicate-do-table`. # You can use a regular expression for configuration. The regular expression should start with "~". # The configuration method for `replicate-do-db` and `replicate-do-table` is # the same with that for `replicate-do-db` and `replicate-do-table` of Drainer. # replicate-do-db = ["~^b.*","s1"] # [[replicate-do-table]] # db-name ="test" # tbl-name = "log" # [[replicate-do-table]] # db-name ="test" # tbl-name = "~^a.*" # If `dest-type` is set to `mysql`, `dest-db` needs to be configured. [dest-db] host = "127.0.0.1" port = 3309 user = "root" password = "" Start example ./bin/reparo -config reparo.toml Note data-dir specifies the directory for the binlog file that Drainer outputs. Both start-datatime and start-tso are used to specify the time point for starting recovery, but they are different in the time format. If they are not set, the recovery process starts from the earliest binlog file by default. Both stop-datetime and stop-tso are used to specify the time point for finishing recovery, but they are different in the time format. If they are not set, the recovery process ends up with the last binlog file by default. dest-type specifies the destination type. Its value can be “mysql” and “print.” When it is set to`mysql`, the data can be recovered to MySQL or TiDB that uses or is compatible with the MySQL protocol. In this case, you need to specify the database information in [dest-db] of the configuration information. When it is set to `print`, only the binlog information is printed. It is generally used for debugging and checking the binlog information. In this case, there is no need to specify [dest-db]. replicate-do-db specifies the database for recovery. If it is not set, all the databases are to be recovered. replicate-do-table specifies the table fo recovery. If it is not set, all the tables are to be recovered. "}, {"url": "https://pingcap.com/docs-cn/tools/reparo/", "title": "Reparo 使用文档", "content": " Reparo 使用文档 Reparo 是 TiDB-Binlog 的一个配套工具,用于增量的恢复。使用 TiDB-Binlog 中的 Drainer 将 binlog 按照 protobuf 格式输出到文件,通过这种方式来备份增量数据。当需要恢复增量数据时,使用 Reparo 解析文件中的 binlog,并将其应用到 TiDB/MySQL 中。下载链接:reparo-latest-linux-amd64.tar.gzReparo 使用 命令行参数说明 Usage of Reparo: -L string 日志输出信息等级设置:debug, info, warn, error, fatal (默认值:info)。 -V 打印版本信息。 -config string 配置文件路径,如果指定了配置文件,Reparo 会首先读取配置文件的配置;如果对应的配置在命令行参数里面也存在,Reparo 就会使用命令行参数的配置来覆盖配置文件里面的。 -data-dir string Drainer 输出的 protobuf 格式 binlog 文件的存储路径 (默认值: data.drainer)。 -dest-type string 下游服务类型。 取值为 print, mysql(默认值:print)。当值为 print 时,只做解析打印到标准输出,不执行 SQL;如果为 mysql,则需要在配置文件内配置 host、port、user、password 等信息。 -log-file string log 文件路径。 -log-rotate string log 文件切换频率,取值为 hour、day。 -start-datetime string 用于指定开始恢复的时间点,格式为 “2006-01-02 15:04:05”。如果不设置该参数则从最早的 binlog 文件开始恢复。 -stop-datetime string 用于指定结束恢复的时间点,格式同上。如果不设置该参数则恢复到最后一个 binlog 文件。 配置文件说明 # Drainer 输出的 protobuf 格式 binlog 文件的存储路径。 data-dir = "./data.drainer" # 使用索引文件来搜索 ts 的位置,当设置了 `start-ts` 时设置该参数,文件的路径为 {data-dir}/{index-name}。 # index-name = "binlog.index" # log-file = "" # log-rotate = "hour" # 日志输出信息等级设置:debug, info, warn, error, fatal (默认值:info)。 log-level = "info" # 使用 start-datetime 和 stop-datetime 来选择恢复指定时间范围内的 binlog,格式为 “2006-01-02 15:04:05”。 # start-datetime = "" # stop-datetime = "" # start-tso、stop-tso 分别对应 start-datetime 和 stop-datetime,也是用于恢复指定时间范围内的 binlog,用 tso 的值来设置。如果已经设置了 start-datetime 和 stop-datetime,就不需要再设置 start-tso 和 stop-tso。 # start-tso = 0 # stop-tso = 0 # 下游服务类型。 取值为 print, mysql(默认值:print)。当值为 print 时,只做解析打印到标准输出,不执行 SQL;如果为 mysql,则需要在 [dest-db] 中配置 host、port、user、password 等信息。 dest-type = "mysql" # replicate-do-db 和 replicate-do-table 用于指定恢复的库和表,replicate-do-db 的优先级高于 replicate-do-table。支持使用正则表达式来配置,需要以 '~' 开始声明使用正则表达式。 # 注:replicate-do-db 和 replicate-do-table 使用方式与 Drainer 的使用方式一致。 # replicate-do-db = ["~^b.*","s1"] # [[replicate-do-table]] # db-name ="test" # tbl-name = "log" # [[replicate-do-table]] # db-name ="test" # tbl-name = "~^a.*" # 如果 dest-type 设置为 mysql, 需要配置 dest-db。 [dest-db] host = "127.0.0.1" port = 3309 user = "root" password = "" 启动示例 ./bin/reparo -config reparo.toml 注意 data-dir 用于指定 Drainer 输出的 binlog 文件目录。 start-datatime 和 start-tso 效果一样,只是时间格式上的区别,用于指定开始恢复的时间点;如果不指定,则默认在第一个 binlog 文件开始恢复。 stop-datetime 和 stop-tso 效果一样,只是时间格式上的区别,用于指定结束恢复的时间点;如果不指定,则恢复到最后一个 binlog 文件的结尾。 dest-type 指定目标类型,取值为 `mysql`, `print`。 当值为 `mysql` 时,可以恢复到 MySQL/TiDB 等使用或兼容 MySQL 协议的数据库,需要在配置下面的 [dest-db] 填写数据库信息;当取值为 `print` 的时候,只是打印 binlog 信息,通常用于 debug,以及查看 binlog 的内容,此时不需要填写 [dest-db] 。 replicate-do-db 用于指定恢复的库,不指定的话,则全部都恢复。 replicate-do-table 用于指定要恢复的表,不指定的话,则全部都恢复。 "}, {"url": "https://pingcap.com/tidb-academy/mysql_dbas/backup/restore-from-accidental-delete-lab/", "title": "Restore from Accidental Delete", "content": " Restore from Accidental Delete "}, {"url": "https://pingcap.com/tidb-academy/mysql_dbas/rocksdb/overview/", "title": "RocksDB", "content": " RocksDB Transcript As I mentioned in our first introduction to TiKV, the storage is based on RocksDB. In fact, you could consider TiKV to be the equivalent to be “distributed RocksDB with built-in replication”.So what is RocksDB? RocksDB is the MySQL equivalent of InnoDB. It is an embedded database library developed by the team at Facebook, who forked an earlier database named LevelDB (developed by Google).In MySQL you can choose between various storage engine options, such as InnoDB or MyISAM. As a point of comparison, this is also possible in TiDB (the API that it uses to speak to TiKV could be implemented by another technology in future). In practical terms though, unless you are a TiDB developer, the storage engine you will use is TiKV.So the next logical question is how does RocksDB differ from InnoDB? I’m glad you asked.In Facebook’s case, they are large users of RocksDB and have moved systems from InnoDB (developing their own MySQL storage engine called MyRocks). Let’s look at their primary motivations: They are predominately space constrained. Their existing InnoDB-based systems support higher QPS than they currently require. How much data can be stored on a server is limited by flash capacities. RocksDB has efficient compression, which helps increase the density of each server, and they have the ability to trade off CPU to do so. Flash durability is limited by write cycles. A simplified comparison of RocksDB versus InnoDB, is that InnoDB is optimized for read operations and RocksDB is optimized for write operations. The lifetime durability of flash is limited in the number of writes cycles (not reads), so having data structures that are more efficient for writing helps increase the lifetime of the hardware. So while this describes some of Facebook’s motivations - let me also describe our motivations at PingCAP. Storage Engines, similar to filesystems, can take a long time to mature. By selecting from the best of existing technologies, we are able to go to market with technology faster. What was true with compression for Facebook is also true for many of PingCAP’s customers. But as well as compressing well, another nice feature of RocksDB is that the degradation to performance can be much smaller than InnoDB for cases where indexes no longer fit in memory. This helps make TiDB suitable for very large data-sets. Hopefully this helps provide some background context. In the next video we’ll look into the structure in more detail."}, {"url": "https://pingcap.com/tidb-academy/mysql_dbas/rocksdb/configuration/", "title": "RocksDB Configuration", "content": " RocksDB Configuration Resources Tune TiKV Transcript Under the hood, it is worth noting that each TiKV server instance uses two instances of RocksDB. The default instance is storing your used data, with the second storing the Raft logs (used for distributed consensus between TiKV servers).Data is organized into Column Families, which in MySQL terminology you can think of as similar to Table Partition, with the exception that instead of a table being partitioned horizontally by rows, it is being partitioned and grouped into sets of columns. The default RocksDB instance stores KV data in the default, write and lock CFs. The default CF stores the actual data. This corresponds to the [rocksdb.defaultcf] section of the configuration file. The write CF stores the version information in Multi-Version Concurrency Control (MVCC) and index-related data. The corresponding parameters are in [rocksdb.writecf]. The lock CF stores the lock information. The system uses the default parameters. The Raft RocksDB (RaftDB) instance stores Raft logs. The default CF stores the Raft log. The corresponding parameters are in [raftdb.defaultcf]. Each CF has a separate block cache to cache data blocks to accelerate the data reading speed in RocksDB. You can configure the size of the block cache by setting the block-cache-size parameter. The bigger the block-cache-size, the more hot data can be cached, and the easier to read data, in the meantime, the more system memory will be occupied.Each CF also has a separate write buffer. You can configure the size by setting the write-buffer-size parameter.Parameter specification # Log level: trace, debug, info, warn, error, off. log-level = "info" [server] # Set listening address # addr = "127.0.0.1:20160" # It is recommended to use the default value. # notify-capacity = 40960 # messages-per-tick = 4096 # Size of thread pool for gRPC # grpc-concurrency = 4 # The number of gRPC connections between each TiKV instance # grpc-raft-conn-num = 10 # Most read requests from TiDB are sent to the coprocessor of TiKV. This parameter is used to set the number of threads # of the coprocessor. If many read requests exist, add the number of threads and keep the number within that of the # system CPU cores. For example, for a 32-core machine deployed with TiKV, you can even set this parameter to 30 in # repeatable read scenarios. If this parameter is not set, TiKV automatically sets it to CPU cores * 0.8. # end-point-concurrency = 8 # Tag the TiKV instances to schedule replicas. # labels = {zone = "cn-east-1", host = "118", disk = "ssd"} [storage] # The data directory # data-dir = "/tmp/tikv/store" # In most cases, you can use the default value. When importing data, it is recommended to set the parameter to 1024000. # scheduler-concurrency = 102400 # This parameter controls the number of write threads. When write operations occur frequently, set this parameter value # higher. Run `top -H -p tikv-pid` and if the threads named `sched-worker-pool` are busy, set the value of parameter # `scheduler-worker-pool-size` higher and increase the number of write threads. # scheduler-worker-pool-size = 4 [pd] # PD address # endpoints = ["127.0.0.1:2379","127.0.0.2:2379","127.0.0.3:2379"] [metric] # The interval of pushing metrics to Prometheus Pushgateway interval = "15s" # Prometheus Pushgateway address address = "" job = "tikv" [raftstore] # The default value is true, which means writing the data on the disk compulsorily. If it is not in a business scenario # of the financial security level, it is recommended to set the value to false to achieve better performance. sync-log = true # Raft RocksDB directory. The default value is Raft subdirectory of [storage.data-dir]. # If there are multiple disks on the machine, store the data of Raft RocksDB on different disks to improve TiKV performance. # raftdb-dir = "/tmp/tikv/store/raft" region-max-size = "384MB" # The threshold value of Region split region-split-size = "256MB" # When the data size in a Region is larger than the threshold value, TiKV checks whether this Region needs split. # To reduce the costs of scanning data in the checking process, set the value to 32MB during checking and set it to # the default value in normal operation. region-split-check-diff = "32MB" [rocksdb] # The maximum number of threads of RocksDB background tasks. The background tasks include compaction and flush. # For detailed information why RocksDB needs to implement compaction, see RocksDB-related materials. When write # traffic (like the importing data size) is big, it is recommended to enable more threads. But set the number of the enabled # threads smaller than that of CPU cores. For example, when importing data, for a machine with a 32-core CPU, # set the value to 28. # max-background-jobs = 8 # The maximum number of file handles RocksDB can open # max-open-files = 40960 # The file size limit of RocksDB MANIFEST. For more details, see https://github.com/facebook/rocksdb/wiki/MANIFEST max-manifest-file-size = "20MB" # The directory of RocksDB write-ahead logs. If there are two disks on the machine, store the RocksDB data and WAL logs # on different disks to improve TiKV performance. # wal-dir = "/tmp/tikv/store" # Use the following two parameters to deal with RocksDB archiving WAL. # For more details, see https://github.com/facebook/rocksdb/wiki/How-to-persist-in-memory-RocksDB-database%3F # wal-ttl-seconds = 0 # wal-size-limit = 0 # In most cases, set the maximum total size of RocksDB WAL logs to the default value. # max-total-wal-size = "4GB" # Use this parameter to enable or disable the statistics of RocksDB. # enable-statistics = true # Use this parameter to enable the readahead feature during RocksDB compaction. If you are using mechanical disks, it is recommended to set the value to 2MB at least. # compaction-readahead-size = "2MB" [rocksdb.defaultcf] # The data block size. RocksDB compresses data based on the unit of block. # Similar to page in other databases, block is the smallest unit cached in block-cache. block-size = "64KB" # The compaction mode of each layer of RocksDB data. The optional values include no, snappy, zlib, # bzip2, lz4, lz4hc, and zstd. # "no:no:lz4:lz4:lz4:zstd:zstd" indicates there is no compaction of level0 and level1; lz4 compaction algorithm is used # from level2 to level4; zstd compaction algorithm is used from level5 to level6. # "no" means no compaction. "lz4" is a compaction algorithm with moderate speed and compaction ratio. The # compaction ratio of zlib is high. It is friendly to the storage space, but its compaction speed is slow. This # compaction occupies many CPU resources. Different machines deploy compaction modes according to CPU and I/O resources. # For example, if you use the compaction mode of "no:no:lz4:lz4:lz4:zstd:zstd" and find much I/O pressure of the # system (run the iostat command to find %util lasts 100%, or run the top command to find many iowaits) when writing # (importing) a lot of data while the CPU resources are adequate, you can compress level0 and level1 and exchange CPU # resources for I/O resources. If you use the compaction mode of "no:no:lz4:lz4:lz4:zstd:zstd" and you find the I/O # pressure of the system is not big when writing a lot of data, but CPU resources are inadequate. Then run the top # command and choose the -H option. If you find a lot of bg threads (namely the compaction thread of RocksDB) are # running, you can exchange I/O resources for CPU resources and change the compaction mode to "no:no:no:lz4:lz4:zstd:zstd". # In a word, it aims at making full use of the existing resources of the system and improving TiKV performance # in terms of the current resources. compression-per-level = ["no", "no", "lz4", …"}, {"url": "https://pingcap.com/docs/sql/sql-optimizer-overview/", "title": "SQL Optimization Process", "content": " SQL Optimization Process In TiDB, the process of SQL optimization consists of two phases: logical optimization and physical optimization. This document describes the logical and physical optimization to help you understand the whole process.Logical optimization Based on rules, logical optimization applies some optimization rules to the input logical execution plan in order, to make the whole logical execution plan better. The optimization rules include: Column pruning Eliminate projection Decorrelate correlated subqueries Eliminate Max/Min Push down predicates Partition pruning Push down TopN and Limit Physical optimization Based on cost, physical optimization makes the physical execution plan for the logical execution plan generated in the previous phase.In this phase, the optimizer selects the specific physical implementation for each operator in the logical execution plan. Different physical implementations of logical operators differ in time complexity, resource consumption, physical properties, and so on. During this process, the optimizer determines the cost of different physical implementations according to data statistics, and selects the physical execution plan with the minimum whole cost.The logical execution plan is a tree structure and each node corresponds to a logical operator in SQL. Similarly, the physical execution plan is also a tree structure, and each node corresponds to a physical operator in SQL.The logical operator only describes the function of an operator, while the physical operator describes the concrete algorithm that implements this function. A single logical operator might have multiple physical operator implementations. For example, to implement LogicalAggregate, you can use either HashAggregate the of the hash algorithm, or StreamAggregate of the stream type.Different physical operators have different physical properties, and have different requirements on the physical properties of their subnodes. The physical properties include the data’s order, distribution, and so on. Currently, only the data order is considered in TiDB."}, {"url": "https://pingcap.com/docs-cn/sql/sql-optimizer-overview/", "title": "SQL 优化流程简介", "content": " SQL 优化流程简介 在 TiDB 中,SQL 优化过程分为逻辑优化和物理优化两个阶段。逻辑优化简介 逻辑优化是基于规则的优化,对输入的逻辑执行计划按顺序应用一些优化规则,从而使整个逻辑执行计划变得更好。这些优化规则包括: 列裁剪 投影消除 关联子查询去关联 Max/Min 消除 谓词下推 分区裁剪 TopN 和 Limit 下推 物理优化简介 物理优化是基于代价的优化,为上一阶段产生的逻辑执行计划制定物理执行计划。这一阶段中,优化器会为逻辑执行计划中的每个算子选择具体的物理实现。逻辑算子的不同物理实现有着不同的时间复杂度、资源消耗和物理属性等。在这个过程中,优化器会根据数据的统计信息来确定不同物理实现的代价,并选择整体代价最小的物理执行计划。逻辑执行计划是一个树形结构,每个节点对应 SQL 中的一个逻辑算子。同样的,物理执行计划也是一个树形结构,每个节点对应 SQL 中的一个物理算子。逻辑算子只描述这个算子的功能,而物理算子则描述了完成这个功能的具体算法。对于同一个逻辑算子,可能有多个物理算子实现,比如 LogicalAggregate,它的实现可以是采用哈希算法的 HashAggregate,也可以是流式的 StreamAggregate。不同的物理算子具有不同的物理属性,也对其子节点有着不同的物理属性的要求。物理属性包括数据的顺序和分布等。TiDB 中现在只考虑了数据的顺序。"}, {"url": "https://pingcap.com/docs/op-guide/horizontal-scale/", "title": "Scale a TiDB cluster", "content": " Scale a TiDB cluster Overview The capacity of a TiDB cluster can be increased or reduced without affecting online services. Note: If your TiDB cluster is deployed using Ansible, see Scale the TiDB Cluster Using TiDB-Ansible. The following part shows you how to add or delete PD, TiKV or TiDB nodes.About pd-ctl usage, refer to PD Control User Guide.PD Assume we have three PD servers with the following details: Name ClientUrls PeerUrls pd1 http://host1:2379 http://host1:2380 pd2 http://host2:2379 http://host2:2380 pd3 http://host3:2379 http://host3:2380 Get the information about the existing PD nodes through pd-ctl:./pd-ctl -u http://host1:2379 >> member Add a node dynamically Add a new PD server to the current PD cluster by using the parameter join. To add pd4, you just need to specify the client url of any PD server in the PD cluster in the parameter --join, like:./bin/pd-server --name=pd4 --client-urls="http://host4:2379" --peer-urls="http://host4:2380" --join="http://host1:2379" Delete a node dynamically Delete pd4 through pd-ctl:./pd-ctl -u http://host1:2379 >> member delete name pd4 Migrate a node dynamically If you want to migrate a node to a new machine, you need to, first of all, add a node on the new machine and then delete the node on the old machine. As you can just migrate one node at a time, if you want to migrate multiple nodes, you need to repeat the above steps until you have migrated all nodes. After completing each step, you can verify the process by checking the information of all nodes.TiKV Get the information about the existing TiKV nodes through pd-ctl:./pd-ctl -u http://host1:2379 >> store Add a node dynamically It is very easy to add a new TiKV server dynamically. You just need to start a TiKV server on the new machine. The newly started TiKV server will automatically register in the existing PD of the cluster. To reduce the pressure of the existing TiKV servers, PD loads balance automatically, which means PD gradually migrates some data to the new TiKV server.Delete a node dynamically To delete (make it offline) a TiKV server safely, you need to inform PD in advance. After that, PD is able to migrate the data on this TiKV server to other TiKV servers, ensuring that data have enough replicas.Assume that you need to delete the TiKV server with a store id 1, you can complete this through pd-ctl:./pd-ctl -u http://host1:2379 >> store delete 1 Then you can check the state of this TiKV:./pd-ctl -u http://host1:2379 >> store 1 { "store": { "id": 1, "address": "127.0.0.1:21060", "state": 1, "state_name": "Offline" }, "status": { ... } } You can verify the state of this store using state_name: Up: This store is in service. Disconnected: The heartbeats of this store cannot be detected currently, which might be caused by a failure or network interruption. Down: PD does not receive heartbeats from the TiKV store for more than an hour (the time can be configured using max-down-time). At this time, PD adds a replica for the data on this store. Offline: The store is in the process of transferring its Regions to other nodes. The state name is misleading: the store is available and even continuing to lead some of its Regions. Tombstone: This store is shut down and has no data on it, so the instance can be deleted. Migrate a node dynamically To migrate TiKV servers to a new machine, you also need to add nodes on the new machine and then make all nodes on the old machine offline. In the process of migration, you can add all machines in the new cluster to the existing cluster, then make old nodes offline one by one. To verify whether a node has been made offline, you can check the state information of the node in process. After verifying, you can make the next node offline.TiDB TiDB is a stateless server, which means it can be added or deleted directly. It should be noted that if you deploy a proxy (such as HAProxy) in front of TiDB, you need to update the proxy configuration and reload it."}, {"url": "https://pingcap.com/docs/v1.0/op-guide/horizontal-scale/", "title": "Scale a TiDB cluster", "content": " Scale a TiDB cluster Overview The capacity of a TiDB cluster can be increased or reduced without affecting online services.The following part shows you how to add or delete PD, TiKV or TiDB nodes.About pd-ctl usage, please refer to PD Control User Guide.PD Assume we have three PD servers with the following details: Name ClientUrls PeerUrls pd1 http://host1:2379 http://host1:2380 pd2 http://host2:2379 http://host2:2380 pd3 http://host3:2379 http://host3:2380 Get the information about the existing PD nodes through pd-ctl:./pd-ctl -u http://host1:2379 >> member Add a node dynamically Add a new PD server to the current PD cluster by using the parameter join. To add pd4, you just need to specify the client url of any PD server in the PD cluster in the parameter --join, like:./bin/pd-server --name=pd4 --client-urls="http://host4:2379" --peer-urls="http://host4:2380" --join="http://host1:2379" Delete a node dynamically Delete pd4 through pd-ctl:./pd-ctl -u http://host1:2379 >> member delete pd4 Migrate a node dynamically If you want to migrate a node to a new machine, you need to, first of all, add a node on the new machine and then delete the node on the old machine. As you can just migrate one node at a time, if you want to migrate multiple nodes, you need to repeat the above steps until you have migrated all nodes. After completing each step, you can verify the process by checking the information of all nodes.TiKV Get the information about the existing TiKV nodes through pd-ctl:./pd-ctl -u http://host1:2379 >> store Add a node dynamically It is very easy to add a new TiKV server dynamically. You just need to start a TiKV server on the new machine. The newly started TiKV server will automatically register in the existing PD of the cluster. To reduce the pressure of the existing TiKV servers, PD loads balance automatically, which means PD gradually migrates some data to the new TiKV server.Delete a node dynamically To delete (make it offline) a TiKV server safely, you need to inform PD in advance. After that, PD is able to migrate the data on this TiKV server to other TiKV servers, ensuring that data have enough replicas.Assume that you need to delete the TiKV server with a store id 1, you can complete this through pd-ctl:./pd-ctl -u http://host1:2379 >> store delete 1 Then you can check the state of this TiKV:./pd-ctl -u http://host1:2379 >> store 1 { "store": { "id": 1, "address": "127.0.0.1:21060", "state": 1, "state_name": "Offline" }, "status": { ... } } You can verify the state of this store using state_name: state_name=Up: This store is in service. state_name=Disconnected: The heartbeats of this store cannot be detected currently, which might be caused by a failure or network interruption. state_name=Down: PD does not receive heartbeats from the TiKV store for more than an hour (the time can be configured using max-down-time). At this time, PD adds a replica for the data on this store. state_name=Offline: This store is shutting down, but the store is still in service. state_name=Tombstone: This store is shut down and has no data on it, so the instance can be deleted. Migrate a node dynamically To migrate TiKV servers to a new machine, you also need to add nodes on the new machine and then make all nodes on the old machine offline. In the process of migration, you can add all machines in the new cluster to the existing cluster, then make old nodes offline one by one. To verify whether a node has been made offline, you can check the state information of the node in process. After verifying, you can make the next node offline.TiDB TiDB is a stateless server, which means it can be added or deleted directly. It should be noted that if you deploy a proxy (such as HAProxy) in front of TiDB, you need to update the proxy configuration and reload it."}, {"url": "https://pingcap.com/docs/v2.0/op-guide/horizontal-scale/", "title": "Scale a TiDB cluster", "content": " Scale a TiDB cluster Overview The capacity of a TiDB cluster can be increased or reduced without affecting online services. Note: If your TiDB cluster is deployed using Ansible, see Scale the TiDB Cluster Using TiDB-Ansible. The following part shows you how to add or delete PD, TiKV or TiDB nodes.About pd-ctl usage, refer to PD Control User Guide.PD Assume we have three PD servers with the following details: Name ClientUrls PeerUrls pd1 http://host1:2379 http://host1:2380 pd2 http://host2:2379 http://host2:2380 pd3 http://host3:2379 http://host3:2380 Get the information about the existing PD nodes through pd-ctl:./pd-ctl -u http://host1:2379 >> member Add a node dynamically Add a new PD server to the current PD cluster by using the parameter join. To add pd4, you just need to specify the client url of any PD server in the PD cluster in the parameter --join, like:./bin/pd-server --name=pd4 --client-urls="http://host4:2379" --peer-urls="http://host4:2380" --join="http://host1:2379" Delete a node dynamically Delete pd4 through pd-ctl:./pd-ctl -u http://host1:2379 >> member delete pd4 Migrate a node dynamically If you want to migrate a node to a new machine, you need to, first of all, add a node on the new machine and then delete the node on the old machine. As you can just migrate one node at a time, if you want to migrate multiple nodes, you need to repeat the above steps until you have migrated all nodes. After completing each step, you can verify the process by checking the information of all nodes.TiKV Get the information about the existing TiKV nodes through pd-ctl:./pd-ctl -u http://host1:2379 >> store Add a node dynamically It is very easy to add a new TiKV server dynamically. You just need to start a TiKV server on the new machine. The newly started TiKV server will automatically register in the existing PD of the cluster. To reduce the pressure of the existing TiKV servers, PD loads balance automatically, which means PD gradually migrates some data to the new TiKV server.Delete a node dynamically To delete (make it offline) a TiKV server safely, you need to inform PD in advance. After that, PD is able to migrate the data on this TiKV server to other TiKV servers, ensuring that data have enough replicas.Assume that you need to delete the TiKV server with a store id 1, you can complete this through pd-ctl:./pd-ctl -u http://host1:2379 >> store delete 1 Then you can check the state of this TiKV:./pd-ctl -u http://host1:2379 >> store 1 { "store": { "id": 1, "address": "127.0.0.1:21060", "state": 1, "state_name": "Offline" }, "status": { ... } } You can verify the state of this store using state_name: state_name=Up: This store is in service. state_name=Disconnected: The heartbeats of this store cannot be detected currently, which might be caused by a failure or network interruption. state_name=Down: PD does not receive heartbeats from the TiKV store for more than an hour (the time can be configured using max-down-time). At this time, PD adds a replica for the data on this store. state_name=Offline: This store is shutting down, but the store is still in service. state_name=Tombstone: This store is shut down and has no data on it, so the instance can be deleted. Migrate a node dynamically To migrate TiKV servers to a new machine, you also need to add nodes on the new machine and then make all nodes on the old machine offline. In the process of migration, you can add all machines in the new cluster to the existing cluster, then make old nodes offline one by one. To verify whether a node has been made offline, you can check the state information of the node in process. After verifying, you can make the next node offline.TiDB TiDB is a stateless server, which means it can be added or deleted directly. It should be noted that if you deploy a proxy (such as HAProxy) in front of TiDB, you need to update the proxy configuration and reload it."}, {"url": "https://pingcap.com/docs/op-guide/ansible-deployment-scale/", "title": "Scale the TiDB Cluster Using TiDB-Ansible", "content": " Scale the TiDB Cluster Using TiDB-Ansible The capacity of a TiDB cluster can be increased or decreased without affecting the online services. Warning: In decreasing the capacity, if your cluster has a mixed deployment of other services, do not perform the following procedures. The following examples assume that the removed nodes have no mixed deployment of other services. Assume that the topology is as follows: Name Host IP Services node1 172.16.10.1 PD1 node2 172.16.10.2 PD2 node3 172.16.10.3 PD3, Monitor node4 172.16.10.4 TiDB1 node5 172.16.10.5 TiDB2 node6 172.16.10.6 TiKV1 node7 172.16.10.7 TiKV2 node8 172.16.10.8 TiKV3 node9 172.16.10.9 TiKV4 Increase the capacity of a TiDB/TiKV node For example, if you want to add two TiDB nodes (node101, node102) with the IP addresses 172.16.10.101 and 172.16.10.102, take the following steps: Edit the inventory.ini file and append the node information:[tidb_servers] 172.16.10.4 172.16.10.5 172.16.10.101 172.16.10.102 [pd_servers] 172.16.10.1 172.16.10.2 172.16.10.3 [tikv_servers] 172.16.10.6 172.16.10.7 172.16.10.8 172.16.10.9 [monitored_servers] 172.16.10.1 172.16.10.2 172.16.10.3 172.16.10.4 172.16.10.5 172.16.10.6 172.16.10.7 172.16.10.8 172.16.10.9 172.16.10.101 172.16.10.102 [monitoring_servers] 172.16.10.3 [grafana_servers] 172.16.10.3 Now the topology is as follows: Name Host IP Services node1 172.16.10.1 PD1 node2 172.16.10.2 PD2 node3 172.16.10.3 PD3, Monitor node4 172.16.10.4 TiDB1 node5 172.16.10.5 TiDB2 node101 172.16.10.101 TiDB3 node102 172.16.10.102 TiDB4 node6 172.16.10.6 TiKV1 node7 172.16.10.7 TiKV2 node8 172.16.10.8 TiKV3 node9 172.16.10.9 TiKV4 Initialize the newly added node:ansible-playbook bootstrap.yml -l 172.16.10.101,172.16.10.102 Note: If an alias is configured in the inventory.ini file, for example, node101 ansible_host=172.16.10.101, use -l to specify the alias when executing ansible-playbook. For example, ansible-playbook bootstrap.yml -l node101,node102. This also applies to the following steps. Deploy the newly added node:ansible-playbook deploy.yml -l 172.16.10.101,172.16.10.102 Start the newly added node:ansible-playbook start.yml -l 172.16.10.101,172.16.10.102 Update the Prometheus configuration and restart the cluster:ansible-playbook rolling_update_monitor.yml --tags=prometheus Monitor the status of the entire cluster and the newly added node by opening a browser to access the monitoring platform: http://172.16.10.3:3000. You can use the same procedure to add a TiKV node. But to add a PD node, some configuration files need to be manually updated.Increase the capacity of a PD node For example, if you want to add a PD node (node103) with the IP address 172.16.10.103, take the following steps: Edit the inventory.ini file and append the node information to the end of the [pd_servers] group:[tidb_servers] 172.16.10.4 172.16.10.5 [pd_servers] 172.16.10.1 172.16.10.2 172.16.10.3 172.16.10.103 [tikv_servers] 172.16.10.6 172.16.10.7 172.16.10.8 172.16.10.9 [monitored_servers] 172.16.10.4 172.16.10.5 172.16.10.1 172.16.10.2 172.16.10.3 172.16.10.103 172.16.10.6 172.16.10.7 172.16.10.8 172.16.10.9 [monitoring_servers] 172.16.10.3 [grafana_servers] 172.16.10.3 Now the topology is as follows: Name Host IP Services node1 172.16.10.1 PD1 node2 172.16.10.2 PD2 node3 172.16.10.3 PD3, Monitor node103 172.16.10.103 PD4 node4 172.16.10.4 TiDB1 node5 172.16.10.5 TiDB2 node6 172.16.10.6 TiKV1 node7 172.16.10.7 TiKV2 node8 172.16.10.8 TiKV3 node9 172.16.10.9 TiKV4 Initialize the newly added node:ansible-playbook bootstrap.yml -l 172.16.10.103 Deploy the newly added node:ansible-playbook deploy.yml -l 172.16.10.103 Login the newly added PD node and edit the starting script:{deploy_dir}/scripts/run_pd.sh Remove the --initial-cluster="xxxx" configuration. Add --join="http://172.16.10.1:2379" . The IP address (172.16.10.1) can be any of the existing PD IP address in the cluster. Manually start the PD service in the newly added PD node:{deploy_dir}/scripts/start_pd.sh Use pd-ctl to check whether the new node is added successfully:./pd-ctl -u "http://172.16.10.1:2379" Note: pd-ctl is a command used to check the number of PD nodes. Apply a rolling update to the entire cluster:ansible-playbook rolling_update.yml Update the Prometheus configuration and restart the cluster:ansible-playbook rolling_update_monitor.yml --tags=prometheus Monitor the status of the entire cluster and the newly added node by opening a browser to access the monitoring platform: http://172.16.10.3:3000. Decrease the capacity of a TiDB node For example, if you want to remove a TiDB node (node5) with the IP address 172.16.10.5, take the following steps: Stop all services on node5:ansible-playbook stop.yml -l 172.16.10.5 Edit the inventory.ini file and remove the node information:[tidb_servers] 172.16.10.4 #172.16.10.5 # the removed node [pd_servers] 172.16.10.1 172.16.10.2 172.16.10.3 [tikv_servers] 172.16.10.6 172.16.10.7 172.16.10.8 172.16.10.9 [monitored_servers] 172.16.10.4 #172.16.10.5 # the removed node 172.16.10.1 172.16.10.2 172.16.10.3 172.16.10.6 172.16.10.7 172.16.10.8 172.16.10.9 [monitoring_servers] 172.16.10.3 [grafana_servers] 172.16.10.3 Now the topology is as follows: Name Host IP Services node1 172.16.10.1 PD1 node2 172.16.10.2 PD2 node3 172.16.10.3 PD3, Monitor node4 172.16.10.4 TiDB1 node5 172.16.10.5 TiDB2 removed node6 172.16.10.6 TiKV1 node7 172.16.10.7 TiKV2 node8 172.16.10.8 TiKV3 node9 172.16.10.9 TiKV4 Update the Prometheus configuration and restart the cluster:ansible-playbook rolling_update_monitor.yml --tags=prometheus Monitor the status of the entire cluster by opening a browser to access the monitoring platform: http://172.16.10.3:3000. Decrease the capacity of a TiKV node For example, if you want to remove a TiKV node (node9) with the IP address 172.16.10.9, take the following steps: Remove the node from the cluster using pd-ctl: View the store ID of node9:./pd-ctl -u "http://172.16.10.1:2379" -d store Remove node9 from the cluster, assuming that the store ID is 10:./pd-ctl -u "http://172.16.10.1:2379" -d store delete 10 Use Grafana or pd-ctl to check whether the node is successfully removed:./pd-ctl -u "http://172.16.10.1:2379" -d store 10 Note: It takes some time to remove the node. If the status of the node you remove becomes Tombstone, then this node is successfully removed. After the node is successfully removed, stop the services on node9:ansible-playbook stop.yml -l 172.16.10.9 Edit the inventory.ini file and remove the node information:[tidb_servers] 172.16.10.4 172.16.10.5 [pd_servers] 172.16.10.1 172.16.10.2 172.16.10.3 [tikv_servers] 172.16.10.6 172.16.10.7 172.16.10.8 #172.16.10.9 # the removed node [monitored_servers] 172.16.10.4 172.16.10.5 172.16.10.1 172.16.10.2 172.16.10.3 172.16.10.6 172.16.10.7 172.16.10.8 #172.16.10.9 # the removed node [monitoring_servers] 172.16.10.3 [grafana_servers] 172.16.10.3 Now the topology is as follows: Name Host IP Services node1 172.16.10.1 PD1 node2 172.16.10.2 PD2 node3 172.16.10.3 PD3, Monitor node4 172.16.10.4 TiDB1 node5 172.16.10.5 TiDB2 node6 172.16.10.6 TiKV1 node7 172.16.10.7 TiKV2 node8 172.16.10.8 TiKV3 node9 172.16.10.9 TiKV4 removed Update the Prometheus configuration and restart the cluster:ansible-playbook rolling_update_monitor.yml --tags=prometheus Monitor the status of the entire cluster by opening a browser to access the monitoring platform: http://172.16.10.3:3000. Decrease the capacity of a PD node For example, if you want to remove a PD node (node2) with the IP address 172.16.10.2, take the following steps: Remove the node from the cluster using pd-ctl: View the name of node2:./pd-ctl -u "http://172.16.10.1:2379" -d member Remove node2 from the cluster, assuming that the name is pd2:./pd-ctl -u "http://172.16.10.1:2379" -d …"}, {"url": "https://pingcap.com/docs/v2.0/op-guide/ansible-deployment-scale/", "title": "Scale the TiDB Cluster Using TiDB-Ansible", "content": " Scale the TiDB Cluster Using TiDB-Ansible The capacity of a TiDB cluster can be increased or decreased without affecting the online services. Warning: In decreasing the capacity, if your cluster has a mixed deployment of other services, do not perform the following procedures. The following examples assume that the removed nodes have no mixed deployment of other services. Assume that the topology is as follows: Name Host IP Services node1 172.16.10.1 PD1 node2 172.16.10.2 PD2 node3 172.16.10.3 PD3, Monitor node4 172.16.10.4 TiDB1 node5 172.16.10.5 TiDB2 node6 172.16.10.6 TiKV1 node7 172.16.10.7 TiKV2 node8 172.16.10.8 TiKV3 node9 172.16.10.9 TiKV4 Increase the capacity of a TiDB/TiKV node For example, if you want to add two TiDB nodes (node101, node102) with the IP addresses 172.16.10.101 and 172.16.10.102, take the following steps: Edit the inventory.ini file and append the node information:[tidb_servers] 172.16.10.4 172.16.10.5 172.16.10.101 172.16.10.102 [pd_servers] 172.16.10.1 172.16.10.2 172.16.10.3 [tikv_servers] 172.16.10.6 172.16.10.7 172.16.10.8 172.16.10.9 [monitored_servers] 172.16.10.1 172.16.10.2 172.16.10.3 172.16.10.4 172.16.10.5 172.16.10.6 172.16.10.7 172.16.10.8 172.16.10.9 172.16.10.101 172.16.10.102 [monitoring_servers] 172.16.10.3 [grafana_servers] 172.16.10.3 Now the topology is as follows: Name Host IP Services node1 172.16.10.1 PD1 node2 172.16.10.2 PD2 node3 172.16.10.3 PD3, Monitor node4 172.16.10.4 TiDB1 node5 172.16.10.5 TiDB2 node101 172.16.10.101 TiDB3 node102 172.16.10.102 TiDB4 node6 172.16.10.6 TiKV1 node7 172.16.10.7 TiKV2 node8 172.16.10.8 TiKV3 node9 172.16.10.9 TiKV4 Initialize the newly added node:ansible-playbook bootstrap.yml -l 172.16.10.101,172.16.10.102 Note: If an alias is configured in the inventory.ini file, for example, node101 ansible_host=172.16.10.101, use -1 to specify the alias when executing ansible-playbook. For example, ansible-playbook bootstrap.yml -l node101,node102. This also applies to the following steps. Deploy the newly added node:ansible-playbook deploy.yml -l 172.16.10.101,172.16.10.102 Start the newly added node:ansible-playbook start.yml -l 172.16.10.101,172.16.10.102 Update the Prometheus configuration and restart the cluster:ansible-playbook rolling_update_monitor.yml --tags=prometheus Monitor the status of the entire cluster and the newly added node by opening a browser to access the monitoring platform: http://172.16.10.3:3000. You can use the same procedure to add a TiKV node. But to add a PD node, some configuration files need to be manually updated.Increase the capacity of a PD node For example, if you want to add a PD node (node103) with the IP address 172.16.10.103, take the following steps: Edit the inventory.ini file and append the node information:[tidb_servers] 172.16.10.4 172.16.10.5 [pd_servers] 172.16.10.1 172.16.10.2 172.16.10.3 172.16.10.103 [tikv_servers] 172.16.10.6 172.16.10.7 172.16.10.8 172.16.10.9 [monitored_servers] 172.16.10.4 172.16.10.5 172.16.10.1 172.16.10.2 172.16.10.3 172.16.10.103 172.16.10.6 172.16.10.7 172.16.10.8 172.16.10.9 [monitoring_servers] 172.16.10.3 [grafana_servers] 172.16.10.3 Now the topology is as follows: Name Host IP Services node1 172.16.10.1 PD1 node2 172.16.10.2 PD2 node3 172.16.10.3 PD3, Monitor node103 172.16.10.103 PD4 node4 172.16.10.4 TiDB1 node5 172.16.10.5 TiDB2 node6 172.16.10.6 TiKV1 node7 172.16.10.7 TiKV2 node8 172.16.10.8 TiKV3 node9 172.16.10.9 TiKV4 Initialize the newly added node:ansible-playbook bootstrap.yml -l 172.16.10.103 Deploy the newly added node:ansible-playbook deploy.yml -l 172.16.10.103 Login the newly added PD node and edit the starting script:{deploy_dir}/scripts/run_pd.sh Remove the --initial-cluster="xxxx" configuration. Add --join="http://172.16.10.1:2379" . The IP address (172.16.10.1) can be any of the existing PD IP address in the cluster. Manually start the PD service in the newly added PD node:{deploy_dir}/scripts/start_pd.sh Use pd-ctl to check whether the new node is added successfully:./pd-ctl -u "http://172.16.10.1:2379" Note: pd-ctl is a command used to check the number of PD nodes. Apply a rolling update to the entire cluster:ansible-playbook rolling_update.yml Update the Prometheus configuration and restart the cluster:ansible-playbook rolling_update_monitor.yml --tags=prometheus Monitor the status of the entire cluster and the newly added node by opening a browser to access the monitoring platform: http://172.16.10.3:3000. Decrease the capacity of a TiDB node For example, if you want to remove a TiDB node (node5) with the IP address 172.16.10.5, take the following steps: Stop all services on node5:ansible-playbook stop.yml -l 172.16.10.5 Edit the inventory.ini file and remove the node information:[tidb_servers] 172.16.10.4 #172.16.10.5 # the removed node [pd_servers] 172.16.10.1 172.16.10.2 172.16.10.3 [tikv_servers] 172.16.10.6 172.16.10.7 172.16.10.8 172.16.10.9 [monitored_servers] 172.16.10.4 #172.16.10.5 # the removed node 172.16.10.1 172.16.10.2 172.16.10.3 172.16.10.6 172.16.10.7 172.16.10.8 172.16.10.9 [monitoring_servers] 172.16.10.3 [grafana_servers] 172.16.10.3 Now the topology is as follows: Name Host IP Services node1 172.16.10.1 PD1 node2 172.16.10.2 PD2 node3 172.16.10.3 PD3, Monitor node4 172.16.10.4 TiDB1 node5 172.16.10.5 TiDB2 removed node6 172.16.10.6 TiKV1 node7 172.16.10.7 TiKV2 node8 172.16.10.8 TiKV3 node9 172.16.10.9 TiKV4 Update the Prometheus configuration and restart the cluster:ansible-playbook rolling_update_monitor.yml --tags=prometheus Monitor the status of the entire cluster by opening a browser to access the monitoring platform: http://172.16.10.3:3000. Decrease the capacity of a TiKV node For example, if you want to remove a TiKV node (node9) with the IP address 172.16.10.9, take the following steps: Remove the node from the cluster using pd-ctl: View the store ID of node9:./pd-ctl -u "http://172.16.10.1:2379" -d store Remove node9 from the cluster, assuming that the store ID is 10:./pd-ctl -u "http://172.16.10.1:2379" -d store delete 10 Use Grafana or pd-ctl to check whether the node is successfully removed:./pd-ctl -u "http://172.16.10.1:2379" -d store 10 Note: It takes some time to remove the node. If the status of the node you remove becomes Tombstone, then this node is successfully removed. After the node is successfully removed, stop the services on node9:ansible-playbook stop.yml -l 172.16.10.9 Edit the inventory.ini file and remove the node information:[tidb_servers] 172.16.10.4 172.16.10.5 [pd_servers] 172.16.10.1 172.16.10.2 172.16.10.3 [tikv_servers] 172.16.10.6 172.16.10.7 172.16.10.8 #172.16.10.9 # the removed node [monitored_servers] 172.16.10.4 172.16.10.5 172.16.10.1 172.16.10.2 172.16.10.3 172.16.10.6 172.16.10.7 172.16.10.8 #172.16.10.9 # the removed node [monitoring_servers] 172.16.10.3 [grafana_servers] 172.16.10.3 Now the topology is as follows: Name Host IP Services node1 172.16.10.1 PD1 node2 172.16.10.2 PD2 node3 172.16.10.3 PD3, Monitor node4 172.16.10.4 TiDB1 node5 172.16.10.5 TiDB2 node6 172.16.10.6 TiKV1 node7 172.16.10.7 TiKV2 node8 172.16.10.8 TiKV3 node9 172.16.10.9 TiKV4 removed Update the Prometheus configuration and restart the cluster:ansible-playbook rolling_update_monitor.yml --tags=prometheus Monitor the status of the entire cluster by opening a browser to access the monitoring platform: http://172.16.10.3:3000. Decrease the capacity of a PD node For example, if you want to remove a PD node (node2) with the IP address 172.16.10.2, take the following steps: Remove the node from the cluster using pd-ctl: View the name of node2:./pd-ctl -u "http://172.16.10.1:2379" -d member Remove node2 from the cluster, assuming that the name is pd2:./pd-ctl -u "http://172.16.10.1:2379" -d member delete name pd2 Use Grafana …"}, {"url": "https://pingcap.com/tidb-academy/mysql_dbas/scaling/patterns/", "title": "Scaling Patterns", "content": " Scaling Patterns Transcript So in just a second, we will have a lab where we will scale out both TiDB and TiKV, but before we get there, I wanted to cover at a higher level when you would scale one over the other, as well as other performance considerations.So let’s go over some scenarios: TiDB servers are stateless. They make heavy use of CPUs and memory, and if you notice you are constrained on either, it might be time to scale out and add additional servers. This is the most likely reason you would scale out TiDB, but there could be another reason.You might have a scenario where you have too much variation in query execution time. Since one of the advantages of TiDB is that it is able to run HTAP queries (the Hybrid of Transactional and Analytics Processing), you may choose to add servers to reduce the latency of query execution. Usually in this scenario, you have more tolerance to variation with the Analytics queries, so one small tweak you can make to architecture is to have some of your TiDB servers responsible for OLTP queries and some responsible for OLAP. Again, because TiDB servers are stateless, you can manage them as they are a single pool, but have some of the servers behind one load balancer, and some behind another.To further reduce the variance introduced by potentially expensive analytics queries, you can also optionally configure the Analytics Processing servers to be low-priority. This priority setting is propagated to TiKV as well, so that OLTP queries will always take priority. TiKV servers are usually constrained by the density of fast storage. It means that they do use some portion of memory and CPU, but often for large data sets the motivation to add additional TiKV servers is to expand the storage for the TiDB Platform.This is however workload dependent: there are cases where a data set may be smaller, but is actively queried proportionately higher. When you consider that TiKV’s coprocessor also handles parts of query execution, there may be cases where you also expand, or change the server’s specifications to accommodate these requirements. In our deployment pattern (the KOST stack), we currently have 3 virtual machine instances in one Region which host our containers (or pods in Kubernetes parlance): 2x TiDB servers 3x TiKB servers 3x PD servers PD servers are mostly responsible for cluster management, and do not require scaling with cluster growth. There are 3 PD servers only for high availability reasons. At some point after increasing the number of pods, we will also need to increase the size of our Kubernetes cluster. So in the following lab, we are going to be testing multiple types of scaling: Scaling Kubernetes to 4 nodes Scaling TiDB out to 5 pods Scaling TiKV out to 4 pods Scaling TiKV back in to 3 pods Sound good? Let’s proceed forward."}, {"url": "https://pingcap.com/tidb-academy/mysql_dbas/scaling/lab/", "title": "Scaling TiDB", "content": " Scaling "}, {"url": "https://pingcap.com/tidb-academy/mysql_dbas/ddl/overview/", "title": "Schema Changes", "content": " Schema Changes Transcript Welcome back.Recent versions of MySQL have improved support for making schema changes, or DDL. For example, you can add indexes online, which means that while the index is being added, other users of the system can still read and write to the table. There are some limitations to this - for example, not all DDL changes are online. If you wanted to change a column from an integer to a bigint, that would require the table to be locked so that no write operations can occur during this operation.Third party tools exist to address this limitation of MySQL DDL not being online. One of the most popular is gh-ost by GitHub.But if we ignore for a second that not all changes are online, a second issue exists with DDL when you are using a sharded MySQL system, or MySQL with read replicas, and that is that the DDL change does not propagate everywhere at the same time. Each MySQL server could take a different length of time to make the change, and thus your application will need to correctly understand multiple versions of the schema. What we are describing here is a synchronization problem.So now that we’ve talked about DDL in MySQL, you may remember that I mentioned earlier DDL is a major advantage of TiDB. In the next video, I will describe how and why TiDB is able to solve both of these two requirements for DDL. That is to say that in TiDB:1) All DDL changes are online 2) Despite being distributed, all DDL changes appear everywhere at the same time"}, {"url": "https://pingcap.com/docs-cn/sql/schema-object-names/", "title": "Schema Object Names", "content": " Schema Object Names 在 TiDB 中,包括 database,table,index,column,alias 等等都被认为是 identifier (标识符,之后阐述用英文).在 TiDB 中,identifier可以被反引号 (`) 包裹,为了阐述方便,我们叫这种情况为 被引用。identifier 也可以不被 ` 包裹。但是如果一个 identifier 存在一个特殊符号或者是一个保留关键字,那么你必须要 引用 它。mysql> SELECT * FROM `table` WHERE `table`.id = 20; 如果ANSI_QUOTES sql mode 被设置了,那么我们认为被双引号 " 包裹的字符串为 identifier。mysql> CREATE TABLE "test" (a varchar(10)); ERROR 1105 (HY000): line 0 column 19 near " (a varchar(10))" (total length 35) mysql> SET SESSION sql_mode='ANSI_QUOTES'; Query OK, 0 rows affected (0.00 sec) mysql> CREATE TABLE "test" (a varchar(10)); Query OK, 0 rows affected (0.09 sec) 如果你需要在被引用的 identifier 中使用反引号这个字符,那你需要重复两次,例如你需要创建一个表为 a`b:mysql> CREATE TABLE `a``b` (a int); 在 select 语句中,alias 语句可以用 identifier 或者字符串:mysql> SELECT 1 AS `identifier`, 2 AS 'string'; +------------+--------+ | identifier | string | +------------+--------+ | 1 | 2 | +------------+--------+ 1 row in set (0.00 sec) 更多细节Identifier Qualifiers Object Names (对象名字) 可以被限定也可以不用。例如你可以在创建表的时候不指定 database names:CREATE TABLE t (i int); 但是如果你之前没有设定过默认的数据库,会报 ERROR 1046 (3D000): No database selected 错误。当然你也可以指定数据库限定名:CREATE TABLE test.t (i int); 对于 . 左右两端可以出现空格,table_name.col_name 等于 table_name . col_name。如果你要引用这个 identifier,那么请使用:`table_name`.`col_name` 而不是:`table_name.col_name` 更多细节"}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/schema-object-names/", "title": "Schema Object Names", "content": " Schema Object Names 在 TiDB 中,包括 database,table,index,column,alias 等等都被认为是 identifier (标识符,之后阐述用英文).在 TiDB 中,identifier可以被反引号 (`) 包裹,为了阐述方便,我们叫这种情况为 被引用。identifier 也可以不被 ` 包裹。 但是如果一个 identifier 存在一个特殊符号或者是一个保留关键字,那么你必须要 引用 它。mysql> SELECT * FROM `table` WHERE `table`.id = 20; 如果ANSI_QUOTES sql mode 被设置了,那么我们认为被双引号 " 包裹的字符串为 identifier。mysql> CREATE TABLE "test" (a varchar(10)); ERROR 1105 (HY000): line 0 column 19 near " (a varchar(10))" (total length 35) mysql> SET SESSION sql_mode='ANSI_QUOTES'; Query OK, 0 rows affected (0.00 sec) mysql> CREATE TABLE "test" (a varchar(10)); Query OK, 0 rows affected (0.09 sec) 如果你需要在被引用的 identifier 中使用反引号这个字符,那你需要重复两次,例如你需要创建一个表为 a`b:mysql> CREATE TABLE `a``b` (a int); 在 select 语句中,alias 语句可以用 identifier 或者字符串:mysql> SELECT 1 AS `identifier`, 2 AS 'string'; +------------+--------+ | identifier | string | +------------+--------+ | 1 | 2 | +------------+--------+ 1 row in set (0.00 sec) 更多细节Identifier Qualifiers Object Names (对象名字) 可以被限定也可以不用。例如你可以在创建表的时候不指定 database names:CREATE TABLE t (i int); 但是如果你之前没有设定过默认的数据库,会报 ERROR 1046 (3D000): No database selected 错误。当然你也可以指定数据库限定名:CREATE TABLE test.t (i int); 对于 . 左右两端可以出现空格,table_name.col_name 等于 table_name . col_name。如果你要引用这个 identifier,那么请使用:`table_name`.`col_name` 而不是:`table_name.col_name` 更多细节"}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/schema-object-names/", "title": "Schema Object Names", "content": " Schema Object Names 在 TiDB 中,包括 database,table,index,column,alias 等等都被认为是 identifier (标识符,之后阐述用英文).在 TiDB 中,identifier可以被反引号 (`) 包裹,为了阐述方便,我们叫这种情况为 被引用。identifier 也可以不被 ` 包裹。 但是如果一个 identifier 存在一个特殊符号或者是一个保留关键字,那么你必须要 引用 它。mysql> SELECT * FROM `table` WHERE `table`.id = 20; 如果ANSI_QUOTES sql mode 被设置了,那么我们认为被双引号 " 包裹的字符串为 identifier。mysql> CREATE TABLE "test" (a varchar(10)); ERROR 1105 (HY000): line 0 column 19 near " (a varchar(10))" (total length 35) mysql> SET SESSION sql_mode='ANSI_QUOTES'; Query OK, 0 rows affected (0.00 sec) mysql> CREATE TABLE "test" (a varchar(10)); Query OK, 0 rows affected (0.09 sec) 如果你需要在被引用的 identifier 中使用反引号这个字符,那你需要重复两次,例如你需要创建一个表为 a`b:mysql> CREATE TABLE `a``b` (a int); 在 select 语句中,alias 语句可以用 identifier 或者字符串:mysql> SELECT 1 AS `identifier`, 2 AS 'string'; +------------+--------+ | identifier | string | +------------+--------+ | 1 | 2 | +------------+--------+ 1 row in set (0.00 sec) 更多细节Identifier Qualifiers Object Names (对象名字) 可以被限定也可以不用。例如你可以在创建表的时候不指定 database names:CREATE TABLE t (i int); 但是如果你之前没有设定过默认的数据库,会报 ERROR 1046 (3D000): No database selected 错误。当然你也可以指定数据库限定名:CREATE TABLE test.t (i int); 对于 . 左右两端可以出现空格,table_name.col_name 等于 table_name . col_name。如果你要引用这个 identifier,那么请使用:`table_name`.`col_name` 而不是:`table_name.col_name` 更多细节"}, {"url": "https://pingcap.com/docs/sql/schema-object-names/", "title": "Schema Object Names", "content": " Schema Object Names Some objects names in TiDB, including database, table, index, column, alias, etc., are known as identifiers.In TiDB, you can quote or unquote an identifier. If an identifier contains special characters or is a reserved word, you must quote it whenever you refer to it. To quote, use the backtick (`) to wrap the identifier. For example:mysql> SELECT * FROM `table` WHERE `table`.id = 20; If the ANSI_QUOTES SQL mode is enabled, you can also quote identifiers within double quotation marks(“):mysql> CREATE TABLE "test" (a varchar(10)); ERROR 1105 (HY000): line 0 column 19 near " (a varchar(10))" (total length 35) mysql> SET SESSION sql_mode='ANSI_QUOTES'; Query OK, 0 rows affected (0.00 sec) mysql> CREATE TABLE "test" (a varchar(10)); Query OK, 0 rows affected (0.09 sec) The quote characters can be included within an identifier. Double the character if the character to be included within the identifier is the same as that used to quote the identifier itself. For example, the following statement creates a table named a`b:mysql> CREATE TABLE `a``b` (a int); In a SELECT statement, a quoted column alias can be specified using an identifier or a string quoting characters:mysql> SELECT 1 AS `identifier`, 2 AS 'string'; +------------+--------+ | identifier | string | +------------+--------+ | 1 | 2 | +------------+--------+ 1 row in set (0.00 sec) For more information, see MySQL Schema Object Names.Identifier qualifiers Object names can be unqualified or qualified. For example, the following statement creates a table using the unqualified name t:CREATE TABLE t (i int); If there is no default database, the ERROR 1046 (3D000): No database selected is displayed. You can also use the qualified name test.t:CREATE TABLE test.t (i int); The qualifier character is a separate token and need not be contiguous with the associated identifiers. For example, there can be white spaces around ., and table_name.col_name and table_name . col_name are equivalent.To quote this identifier, use:`table_name`.`col_name` Instead of`table_name.col_name` For more information, see MySQL Identifier Qualifiers."}, {"url": "https://pingcap.com/docs/v1.0/sql/schema-object-names/", "title": "Schema Object Names", "content": " Schema Object Names Some objects names in TiDB, including database, table, index, column, alias, etc., are known as identifiers.In TiDB, you can quote or unquote an identifier. If an identifier contains special characters or is a reserved word, you must quote it whenever you refer to it. To quote, use the backtick (`) to wrap the identifier. For example:mysql> SELECT * FROM `table` WHERE `table`.id = 20; If the ANSI_QUOTES SQL mode is enabled, you can also quote identifiers within double quotation marks(“):mysql> CREATE TABLE "test" (a varchar(10)); ERROR 1105 (HY000): line 0 column 19 near " (a varchar(10))" (total length 35) mysql> SET SESSION sql_mode='ANSI_QUOTES'; Query OK, 0 rows affected (0.00 sec) mysql> CREATE TABLE "test" (a varchar(10)); Query OK, 0 rows affected (0.09 sec) The quote characters can be included within an identifier. Double the character if the character to be included within the identifier is the same as that used to quote the identifier itself. For example, the following statement creates a table named a`b:mysql> CREATE TABLE `a``b` (a int); In a SELECT statement, a quoted column alias can be specified using an identifier or a string quoting characters:mysql> SELECT 1 AS `identifier`, 2 AS 'string'; +------------+--------+ | identifier | string | +------------+--------+ | 1 | 2 | +------------+--------+ 1 row in set (0.00 sec) For more information, see MySQL Schema Object Names.Identifier qualifiers Object names can be unqualified or qualified. For example, the following statement creates a table using the unqualified name t:CREATE TABLE t (i int); If there is no default database, the ERROR 1046 (3D000): No database selected is displayed. You can also use the qualified name test.t:CREATE TABLE test.t (i int); The qualifier character is a separate token and need not be contiguous with the associated identifiers. For example, there can be white spaces around ., and table_name.col_name and table_name . col_name are equivalent.To quote this identifier, use:`table_name`.`col_name` Instead of`table_name.col_name` For more information, see MySQL Identifier Qualifiers."}, {"url": "https://pingcap.com/docs/v2.0/sql/schema-object-names/", "title": "Schema Object Names", "content": " Schema Object Names Some objects names in TiDB, including database, table, index, column, alias, etc., are known as identifiers.In TiDB, you can quote or unquote an identifier. If an identifier contains special characters or is a reserved word, you must quote it whenever you refer to it. To quote, use the backtick (`) to wrap the identifier. For example:mysql> SELECT * FROM `table` WHERE `table`.id = 20; If the ANSI_QUOTES SQL mode is enabled, you can also quote identifiers within double quotation marks(“):mysql> CREATE TABLE "test" (a varchar(10)); ERROR 1105 (HY000): line 0 column 19 near " (a varchar(10))" (total length 35) mysql> SET SESSION sql_mode='ANSI_QUOTES'; Query OK, 0 rows affected (0.00 sec) mysql> CREATE TABLE "test" (a varchar(10)); Query OK, 0 rows affected (0.09 sec) The quote characters can be included within an identifier. Double the character if the character to be included within the identifier is the same as that used to quote the identifier itself. For example, the following statement creates a table named a`b:mysql> CREATE TABLE `a``b` (a int); In a SELECT statement, a quoted column alias can be specified using an identifier or a string quoting characters:mysql> SELECT 1 AS `identifier`, 2 AS 'string'; +------------+--------+ | identifier | string | +------------+--------+ | 1 | 2 | +------------+--------+ 1 row in set (0.00 sec) For more information, see MySQL Schema Object Names.Identifier qualifiers Object names can be unqualified or qualified. For example, the following statement creates a table using the unqualified name t:CREATE TABLE t (i int); If there is no default database, the ERROR 1046 (3D000): No database selected is displayed. You can also use the qualified name test.t:CREATE TABLE test.t (i int); The qualifier character is a separate token and need not be contiguous with the associated identifiers. For example, there can be white spaces around ., and table_name.col_name and table_name . col_name are equivalent.To quote this identifier, use:`table_name`.`col_name` Instead of`table_name.col_name` For more information, see MySQL Identifier Qualifiers."}, {"url": "https://pingcap.com/docs/sql/slow-query/", "title": "Slow Query Log", "content": " Slow Query Log The slow query log is a record of SQL statements that took a long time to perform.A problematic SQL statement can increase the pressure on the entire cluster, resulting in a longer response time. To solve this problem, you can use the slow query log to identify the problematic statements and thus improve the performance.Obtain the log By grep the keyword SLOW_QUERY in the log file of TiDB, you can obtain the logs of statements whose execution time exceeds slow-threshold.You can edit slow-threshold in the configuration file and its default value is 300ms. If you configure the slow-query-file, all the slow query logs will be written in this file.Usage example 2018/08/20 19:52:08.632 adapter.go:363: [warning] [SLOW_QUERY] cost_time:18.647928814s process_time:1m6.768s wait_time:12m11.212s backoff_time:600ms request_count:2058 total_keys:1869712 processed_keys:1869710 succ:true con:3 user:root@127.0.0.1 txn_start_ts:402329674704224261 database:test table_ids:[31],index_ids:[1], sql:select count(c) from sbtest1 use index (k_1) Fields description This section describes fields in the slow query log based on the usage example above.cost_time The execution time of this statement. Only the statements whose execution time exceeds slow-threshold output this log.process_time The total processing time of this statement in TiKV. Because data is sent to TiKV concurrently for execution, this value might exceed cost_time.wait_time The total waiting time of this statement in TiKV. Because the Coprocessor of TiKV runs a limited number of threads, requests might queue up when all threads of Coprocessor are working. When a request in the queue takes a long time to process, the waiting time of the subsequent requests will increase.backoff_time The waiting time before retry when this statement encounters errors that require a retry. The common errors as such include: lock occurs, Region split, the TiKV server is busy.request_count The number of Coprocessor requests that this statement sends.total_keys The number of keys that Coprocessor has scanned.processed_keys The number of keys that Coprocessor has processed. Compared with total_keys, processed_keys does not include the old versions of MVCC. A great difference between processed_keys and total_keys indicates that the number of old versions are relatively large.succ Whether the execution of the request succeeds or not.con Connection ID (session ID). For example, you can use the keyword con:3 to grep the log whose session ID is 3.user The name of the user who executes this statement.txn_start_ts The start timestamp of the transaction, that is, the ID of the transaction. You can use this value to grep the transaction-related logs.database The current database.table_ids The IDs of the tables involved in the statement.index_ids The IDs of the indexes involved in the statement.sql The SQL statement.Identify problematic SQL statements Not all of the SLOW_QUERY statements are problematic. Only those whose process_time is very large will increase the pressure on the entire cluster.The statements whose wait_time is very large and process_time is very small are usually not problematic. The large wait_time is because the statement is blocked by real problematic statements and it has to wait in the execution queue, which leads to a much longer response time.admin show slow command In addition to the TiDB log file, you can identify slow queries by running the admin show slow command:admin show slow recent N admin show slow top [internal | all] N recent N shows the recent N slow query records, for example:admin show slow recent 10 top N shows the slowest N query records recently (within a few days). If the internal option is provided, the returned results would be the inner SQL executed by the system; If the all option is provided, the returned results would be the user’s SQL combinated with inner SQL; Otherwise, this command would only return the slow query records from the user’s SQL.admin show slow top 3 admin show slow top internal 3 admin show slow top all 5 Due to the memory footprint restriction, the stored slow query records count is limited. If the specified N is greater than the records count, the returned records count may be smaller than N."}, {"url": "https://pingcap.com/docs/v2.0/sql/slow-query/", "title": "Slow Query Log", "content": " Slow Query Log The slow query log is a record of SQL statements that took a long time to perform.A problematic SQL statement can increase the pressure on the entire cluster, resulting in a longer response time. To solve this problem, you can use the slow query log to identify the problematic statements and thus improve the performance.Obtain the log By grep the keyword SLOW_QUERY in the log file of TiDB, you can obtain the logs of statements whose execution time exceeds slow-threshold.You can edit slow-threshold in the configuration file and its default value is 300ms. If you configure the slow-query-file, all the slow query logs will be written in this file.Usage example 2018/08/20 19:52:08.632 adapter.go:363: [warning] [SLOW_QUERY] cost_time:18.647928814s process_time:1m6.768s wait_time:12m11.212s backoff_time:600ms request_count:2058 total_keys:1869712 processed_keys:1869710 succ:true con:3 user:root@127.0.0.1 txn_start_ts:402329674704224261 database:test table_ids:[31],index_ids:[1], sql:select count(c) from sbtest1 use index (k_1) Fields description This section describes fields in the slow query log based on the usage example above.cost_time The execution time of this statement. Only the statements whose execution time exceeds slow-threshold output this log.process_time The total processing time of this statement in TiKV. Because data is sent to TiKV concurrently for execution, this value might exceed cost_time.wait_time The total waiting time of this statement in TiKV. Because the Coprocessor of TiKV runs a limited number of threads, requests might queue up when all threads of Coprocessor are working. When a request in the queue takes a long time to process, the waiting time of the subsequent requests will increase.backoff_time The waiting time before retry when this statement encounters errors that require a retry. The common errors as such include: lock occurs, Region split, the TiKV server is busy.request_count The number of Coprocessor requests that this statement sends.total_keys The number of keys that Coprocessor has scanned.processed_keys The number of keys that Coprocessor has processed. Compared with total_keys, processed_keys does not include the old versions of MVCC or the MVCC delete marks. A great difference between processed_keys and total_keys indicates that the number of old versions are relatively large.succ Whether the execution of the request succeeds or not.con Connection ID (session ID). For example, you can use the keyword con:3 to grep the log whose session ID is 3.user The name of the user who executes this statement.txn_start_ts The start timestamp of the transaction, that is, the ID of the transaction. You can use this value to grep the transaction-related logs.database The current database.table_ids The IDs of the tables involved in the statement.index_ids The IDs of the indexes involved in the statement.sql The SQL statement.Identify problematic SQL statements Not all of the SLOW_QUERY statements are problematic. Only those whose process_time is very large will increase the pressure on the entire cluster.The statements whose wait_time is very large and process_time is very small are usually not problematic. The large wait_time is because the statement is blocked by real problematic statements and it has to wait in the execution queue, which leads to a much longer response time."}, {"url": "https://pingcap.com/docs/op-guide/recommendation/", "title": "Software and Hardware Requirements", "content": " Software and Hardware Requirements About As an open source distributed NewSQL database with high performance, TiDB can be deployed in the Intel architecture server and major virtualization environments and runs well. TiDB supports most of the major hardware networks and Linux operating systems.Linux OS version requirements Linux OS Platform Version Red Hat Enterprise Linux 7.3 or later CentOS 7.3 or later Oracle Enterprise Linux 7.3 or later Ubuntu LTS 16.04 or later Note: For Oracle Enterprise Linux, TiDB supports the Red Hat Compatible Kernel (RHCK) and does not support the Unbreakable Enterprise Kernel provided by Oracle Enterprise Linux. A large number of TiDB tests have been run on the CentOS 7.3 system, and in our community there are a lot of best practices in which TiDB is deployed on the Linux operating system. Therefore, it is recommended to deploy TiDB on CentOS 7.3 or later. The support for the Linux operating systems above includes the deployment and operation in physical servers as well as in major virtualized environments like VMware, KVM and XEM. Server requirements You can deploy and run TiDB on the 64-bit generic hardware server platform in the Intel x86-64 architecture. The requirements and recommendations about server hardware configuration for development, test and production environments are as follows:Development and test environments Component CPU Memory Local Storage Network Instance Number (Minimum Requirement) TiDB 8 core+ 16 GB+ SAS, 200 GB+ Gigabit network card 1 (can be deployed on the same machine with PD) PD 4 core+ 8 GB+ SAS, 200 GB+ Gigabit network card 1 (can be deployed on the same machine with TiDB) TiKV 8 core+ 32 GB+ SAS, 200 GB+ Gigabit network card 3 Total Server Number 4 Note: In the test environment, the TiDB and PD can be deployed on the same server. For performance-related test, do not use low-performance storage and network hardware configuration, in order to guarantee the correctness of the test result. Production environment Component CPU Memory Hard Disk Type Network Instance Number (Minimum Requirement) TiDB 16 core+ 32 GB+ SAS 10 Gigabit network card (2 preferred) 2 PD 4 core+ 8 GB+ SSD 10 Gigabit network card (2 preferred) 3 TiKV 16 core+ 32 GB+ SSD 10 Gigabit network card (2 preferred) 3 Monitor 8 core+ 16 GB+ SAS Gigabit network card 1 Total Server Number 9 Note: In the production environment, you can deploy and run TiDB and PD on the same server. If you have a higher requirement for performance and reliability, try to deploy them separately. It is strongly recommended to use higher configuration in the production environment. It is recommended to keep the size of TiKV hard disk within 2 TB if you are using PCI-E SSD disks or within 1.5 TB if you are using regular SSD disks. Network requirements As an open source distributed NewSQL database, TiDB requires the following network port configuration to run. Based on the TiDB deployment in actual environments, the administrator can open relevant ports in the network side and host side. Component Default Port Description TiDB 4000 the communication port for the application and DBA tools TiDB 10080 the communication port to report TiDB status TiKV 20160 the TiKV communication port PD 2379 the communication port between TiDB and PD PD 2380 the inter-node communication port within the PD cluster Pump 8250 the Pump communication port Drainer 8249 the Drainer communication port Prometheus 9090 the communication port for the Prometheus service Pushgateway 9091 the aggregation and report port for TiDB, TiKV, and PD monitor Node_exporter 9100 the communication port to report the system information of every TiDB cluster node Blackbox_exporter 9115 the Blackbox_exporter communication port, used to monitor the ports in the TiDB cluster Grafana 3000 the port for the external Web monitoring service and client (Browser) access Grafana 8686 the grafana_collector communication port, used to export the Dashboard as the PDF format Kafka_exporter 9308 the Kafka_exporter communication port, used to monitor the binlog Kafka cluster Web browser requirements Based on the Prometheus and Grafana platform, TiDB provides a visual data monitoring solution to monitor the TiDB cluster status. To access the Grafana monitor interface, it is recommended to use a higher version of Microsoft IE, Google Chrome or Mozilla Firefox."}, {"url": "https://pingcap.com/docs/v1.0/op-guide/recommendation/", "title": "Software and Hardware Requirements", "content": " Software and Hardware Requirements About As an open source distributed NewSQL database with high performance, TiDB can be deployed in the Intel architecture server and major virtualization environments and runs well. TiDB supports most of the major hardware networks and Linux operating systems.Linux OS version requirements Linux OS Platform Version Red Hat Enterprise Linux 7.3 and above CentOS 7.3 and above Oracle Enterprise Linux 7.3 and above Ubuntu LTS 16.04 and above Note: For Oracle Enterprise Linux, TiDB supports the Red Hat Compatible Kernel (RHCK) and does not support the Unbreakable Enterprise Kernel provided by Oracle Enterprise Linux. The support for the Linux operating systems above include the deployment and operation in physical servers as well as in major virtualized environments like VMware, KVM and XEM. Server requirements You can deploy and run TiDB on the 64-bit generic hardware server platform in the Intel x86-64 architecture. The requirements and recommendations about server hardware configuration for development, testing and production environments are as follows:Development and testing environments Component CPU Memory Local Storage Network Instance Number (Minimum Requirement) TiDB 8 core+ 16 GB+ SAS, 200 GB+ Gigabit network card 1 (can be deployed on the same machine with PD) PD 8 core+ 16 GB+ SAS, 200 GB+ Gigabit network card 1 (can be deployed on the same machine with TiDB) TiKV 8 core+ 32 GB+ SAS, 200 GB+ Gigabit network card 3 Total Server Number 4 Note: In the test environment, the TiDB and PD can be deployed on the same server. For performance-related testing, do not use low-performance storage and network hardware configuration, in order to guarantee the correctness of the test result. Production environment Component CPU Memory Hard Disk Type Network Instance Number (Minimum Requirement) TiDB 16 core+ 48 GB+ SAS 10 Gigabit network card (2 preferred) 2 PD 8 core+ 16 GB+ SSD 10 Gigabit network card (2 preferred) 3 TiKV 16 core+ 48 GB+ SSD 10 Gigabit network card (2 preferred) 3 Monitor 8 core+ 16 GB+ SAS Gigabit network card 1 Total Server Number 9 Note: In the production environment, you can deploy and run TiDB and PD on the same server. If you have a higher requirement for performance and reliability, try to deploy them separately. It is strongly recommended to use higher configuration in the production environment. It is recommended to keep the size of TiKV hard disk within 800G in case it takes too long to restore data when the hard disk is damaged. Network requirements As an open source distributed NewSQL database, TiDB requires the following network port configuration to run. Based on the TiDB deployment in actual environments, the administrator can enable relevant ports in the network side and host side. Component Default Port Description TiDB 4000 the communication port for the application and DBA tools TiDB 10080 the communication port to report TiDB status TiKV 20160 the TiKV communication port PD 2379 the communication port between TiDB and PD PD 2380 the inter-node communication port within the PD cluster Prometheus 9090 the communication port for the Prometheus service Pushgateway 9091 the aggregation and report port for TiDB, TiKV, and PD monitor Node_exporter 9100 the communication port to report the system information of every TiDB cluster node Grafana 3000 the port for the external Web monitoring service and client (Browser) access Web browser requirements Based on the Prometheus and Grafana platform, TiDB provides a visual data monitoring solution to monitor the TiDB cluster status. To visit the Grafana monitor interface, it is recommended to use a higher version of Microsoft IE, Google Chrome or Mozilla Firefox."}, {"url": "https://pingcap.com/docs/v2.0/op-guide/recommendation/", "title": "Software and Hardware Requirements", "content": " Software and Hardware Requirements About As an open source distributed NewSQL database with high performance, TiDB can be deployed in the Intel architecture server and major virtualization environments and runs well. TiDB supports most of the major hardware networks and Linux operating systems.Linux OS version requirements Linux OS Platform Version Red Hat Enterprise Linux 7.3 or later CentOS 7.3 or later Oracle Enterprise Linux 7.3 or later Ubuntu LTS 16.04 or later Note: For Oracle Enterprise Linux, TiDB supports the Red Hat Compatible Kernel (RHCK) and does not support the Unbreakable Enterprise Kernel provided by Oracle Enterprise Linux. A large number of TiDB tests have been run on the CentOS 7.3 system, and in our community there are a lot of best practices in which TiDB is deployed on the Linux operating system. Therefore, it is recommended to deploy TiDB on CentOS 7.3 or later. The support for the Linux operating systems above includes the deployment and operation in physical servers as well as in major virtualized environments like VMware, KVM and XEM. Server requirements You can deploy and run TiDB on the 64-bit generic hardware server platform in the Intel x86-64 architecture. The requirements and recommendations about server hardware configuration for development, test and production environments are as follows:Development and test environments Component CPU Memory Local Storage Network Instance Number (Minimum Requirement) TiDB 8 core+ 16 GB+ SAS, 200 GB+ Gigabit network card 1 (can be deployed on the same machine with PD) PD 4 core+ 8 GB+ SAS, 200 GB+ Gigabit network card 1 (can be deployed on the same machine with TiDB) TiKV 8 core+ 32 GB+ SAS, 200 GB+ Gigabit network card 3 Total Server Number 4 Note: In the test environment, the TiDB and PD can be deployed on the same server. For performance-related test, do not use low-performance storage and network hardware configuration, in order to guarantee the correctness of the test result. Production environment Component CPU Memory Hard Disk Type Network Instance Number (Minimum Requirement) TiDB 16 core+ 32 GB+ SAS 10 Gigabit network card (2 preferred) 2 PD 4 core+ 8 GB+ SSD 10 Gigabit network card (2 preferred) 3 TiKV 16 core+ 32 GB+ SSD 10 Gigabit network card (2 preferred) 3 Monitor 8 core+ 16 GB+ SAS Gigabit network card 1 Total Server Number 9 Note: In the production environment, you can deploy and run TiDB and PD on the same server. If you have a higher requirement for performance and reliability, try to deploy them separately. It is strongly recommended to use higher configuration in the production environment. It is recommended to keep the size of TiKV hard disk within 2 TB if you are using PCI-E SSD disks or within 1.5 TB if you are using regular SSD disks. Network requirements As an open source distributed NewSQL database, TiDB requires the following network port configuration to run. Based on the TiDB deployment in actual environments, the administrator can open relevant ports in the network side and host side. Component Default Port Description TiDB 4000 the communication port for the application and DBA tools TiDB 10080 the communication port to report TiDB status TiKV 20160 the TiKV communication port PD 2379 the communication port between TiDB and PD PD 2380 the inter-node communication port within the PD cluster Pump 8250 the Pump communication port Drainer 8249 the Drainer communication port Prometheus 9090 the communication port for the Prometheus service Pushgateway 9091 the aggregation and report port for TiDB, TiKV, and PD monitor Node_exporter 9100 the communication port to report the system information of every TiDB cluster node Blackbox_exporter 9115 the Blackbox_exporter communication port, used to monitor the ports in the TiDB cluster Grafana 3000 the port for the external Web monitoring service and client (Browser) access Grafana 8686 the grafana_collector communication port, used to export the Dashboard as the PDF format Kafka_exporter 9308 the Kafka_exporter communication port, used to monitor the binlog Kafka cluster Web browser requirements Based on the Prometheus and Grafana platform, TiDB provides a visual data monitoring solution to monitor the TiDB cluster status. To access the Grafana monitor interface, it is recommended to use a higher version of Microsoft IE, Google Chrome or Mozilla Firefox."}, {"url": "https://pingcap.com/docs/sql/string-functions/", "title": "String Functions", "content": " String Functions Name Description ASCII() Return numeric value of left-most character CHAR() Return the character for each integer passed BIN() Return a string containing binary representation of a number HEX() Return a hexadecimal representation of a decimal or string value OCT() Return a string containing octal representation of a number UNHEX() Return a string containing hex representation of a number TO_BASE64() Return the argument converted to a base-64 string FROM_BASE64() Decode to a base-64 string and return result LOWER() Return the argument in lowercase LCASE() Synonym for LOWER() UPPER() Convert to uppercase UCASE() Synonym for UPPER() LPAD() Return the string argument, left-padded with the specified string RPAD() Append string the specified number of times TRIM() Remove leading and trailing spaces LTRIM() Remove leading spaces RTRIM() Remove trailing spaces BIT_LENGTH() Return length of argument in bits CHAR_LENGTH() Return number of characters in argument CHARACTER_LENGTH() Synonym for CHAR_LENGTH() LENGTH() Return the length of a string in bytes OCTET_LENGTH() Synonym for LENGTH() INSERT() Insert a substring at the specified position up to the specified number of characters REPLACE() Replace occurrences of a specified string SUBSTR() Return the substring as specified SUBSTRING() Return the substring as specified SUBSTRING_INDEX() Return a substring from a string before the specified number of occurrences of the delimiter MID() Return a substring starting from the specified position LEFT() Return the leftmost number of characters as specified RIGHT() Return the specified rightmost number of characters INSTR() Return the index of the first occurrence of substring LOCATE() Return the position of the first occurrence of substring POSITION() Synonym for LOCATE() REPEAT() Repeat a string the specified number of times CONCAT() Return concatenated string CONCAT_WS() Return concatenate with separator REVERSE() Reverse the characters in a string SPACE() Return a string of the specified number of spaces FIELD() Return the index (position) of the first argument in the subsequent arguments ELT() Return string at index number EXPORT_SET() Return a string such that for every bit set in the value bits, you get an on string and for every unset bit, you get an off string MAKE_SET() Return a set of comma-separated strings that have the corresponding bit in bits set FIND_IN_SET() Return the index position of the first argument within the second argument FORMAT() Return a number formatted to specified number of decimal places ORD() Return character code for leftmost character of the argument QUOTE() Escape the argument for use in an SQL statement String comparison functions Name Description LIKE Simple pattern matching NOT LIKE Negation of simple pattern matching STRCMP() Compare two strings Regular expressions Name Description REGEXP Pattern matching using regular expressions RLIKE Synonym for REGEXP NOT REGEXP Negation of REGEXP "}, {"url": "https://pingcap.com/docs/v1.0/sql/string-functions/", "title": "String Functions", "content": " String Functions Name Description ASCII() Return numeric value of left-most character CHAR() Return the character for each integer passed BIN() Return a string containing binary representation of a number HEX() Return a hexadecimal representation of a decimal or string value OCT() Return a string containing octal representation of a number UNHEX() Return a string containing hex representation of a number TO_BASE64() Return the argument converted to a base-64 string FROM_BASE64() Decode to a base-64 string and return result LOWER() Return the argument in lowercase LCASE() Synonym for LOWER() UPPER() Convert to uppercase UCASE() Synonym for UPPER() LPAD() Return the string argument, left-padded with the specified string RPAD() Append string the specified number of times TRIM() Remove leading and trailing spaces LTRIM() Remove leading spaces RTRIM() Remove trailing spaces BIT_LENGTH() Return length of argument in bits CHAR_LENGTH() Return number of characters in argument CHARACTER_LENGTH() Synonym for CHAR_LENGTH() LENGTH() Return the length of a string in bytes OCTET_LENGTH() Synonym for LENGTH() INSERT() Insert a substring at the specified position up to the specified number of characters REPLACE() Replace occurrences of a specified string SUBSTR() Return the substring as specified SUBSTRING() Return the substring as specified SUBSTRING_INDEX() Return a substring from a string before the specified number of occurrences of the delimiter MID() Return a substring starting from the specified position LEFT() Return the leftmost number of characters as specified RIGHT() Return the specified rightmost number of characters INSTR() Return the index of the first occurrence of substring LOCATE() Return the position of the first occurrence of substring POSITION() Synonym for LOCATE() REPEAT() Repeat a string the specified number of times CONCAT() Return concatenated string CONCAT_WS() Return concatenate with separator REVERSE() Reverse the characters in a string SPACE() Return a string of the specified number of spaces FIELD() Return the index (position) of the first argument in the subsequent arguments ELT() Return string at index number EXPORT_SET() Return a string such that for every bit set in the value bits, you get an on string and for every unset bit, you get an off string MAKE_SET() Return a set of comma-separated strings that have the corresponding bit in bits set FIND_IN_SET() Return the index position of the first argument within the second argument FORMAT() Return a number formatted to specified number of decimal places ORD() Return character code for leftmost character of the argument QUOTE() Escape the argument for use in an SQL statement SOUNDEX() Return a soundex string SOUNDS LIKE Compare sounds String comparison functions Name Description LIKE Simple pattern matching NOT LIKE Negation of simple pattern matching STRCMP() Compare two strings MATCH Perform full-text search Regular expressions Name Description REGEXP Pattern matching using regular expressions RLIKE Synonym for REGEXP NOT REGEXP Negation of REGEXP "}, {"url": "https://pingcap.com/docs/v2.0/sql/string-functions/", "title": "String Functions", "content": " String Functions Name Description ASCII() Return numeric value of left-most character CHAR() Return the character for each integer passed BIN() Return a string containing binary representation of a number HEX() Return a hexadecimal representation of a decimal or string value OCT() Return a string containing octal representation of a number UNHEX() Return a string containing hex representation of a number TO_BASE64() Return the argument converted to a base-64 string FROM_BASE64() Decode to a base-64 string and return result LOWER() Return the argument in lowercase LCASE() Synonym for LOWER() UPPER() Convert to uppercase UCASE() Synonym for UPPER() LPAD() Return the string argument, left-padded with the specified string RPAD() Append string the specified number of times TRIM() Remove leading and trailing spaces LTRIM() Remove leading spaces RTRIM() Remove trailing spaces BIT_LENGTH() Return length of argument in bits CHAR_LENGTH() Return number of characters in argument CHARACTER_LENGTH() Synonym for CHAR_LENGTH() LENGTH() Return the length of a string in bytes OCTET_LENGTH() Synonym for LENGTH() INSERT() Insert a substring at the specified position up to the specified number of characters REPLACE() Replace occurrences of a specified string SUBSTR() Return the substring as specified SUBSTRING() Return the substring as specified SUBSTRING_INDEX() Return a substring from a string before the specified number of occurrences of the delimiter MID() Return a substring starting from the specified position LEFT() Return the leftmost number of characters as specified RIGHT() Return the specified rightmost number of characters INSTR() Return the index of the first occurrence of substring LOCATE() Return the position of the first occurrence of substring POSITION() Synonym for LOCATE() REPEAT() Repeat a string the specified number of times CONCAT() Return concatenated string CONCAT_WS() Return concatenate with separator REVERSE() Reverse the characters in a string SPACE() Return a string of the specified number of spaces FIELD() Return the index (position) of the first argument in the subsequent arguments ELT() Return string at index number EXPORT_SET() Return a string such that for every bit set in the value bits, you get an on string and for every unset bit, you get an off string MAKE_SET() Return a set of comma-separated strings that have the corresponding bit in bits set FIND_IN_SET() Return the index position of the first argument within the second argument FORMAT() Return a number formatted to specified number of decimal places ORD() Return character code for leftmost character of the argument QUOTE() Escape the argument for use in an SQL statement SOUNDEX() Return a soundex string SOUNDS LIKE Compare sounds String comparison functions Name Description LIKE Simple pattern matching NOT LIKE Negation of simple pattern matching STRCMP() Compare two strings MATCH Perform full-text search Regular expressions Name Description REGEXP Pattern matching using regular expressions RLIKE Synonym for REGEXP NOT REGEXP Negation of REGEXP "}, {"url": "https://pingcap.com/docs-cn/sql/literal-value-string-literals/", "title": "String Literals", "content": " String Literals String Literals 是一个 bytes 或者 characters 的序列,两端被单引号 ' 或者双引号 " 包围,例如:'example string' "example string" 如果字符串是连续的,会被合并为一个独立的 string。以下表示是一样的:'a string' 'a' ' ' 'string' "a" ' ' "string" 如果 ANSI_QUOTES SQL MODE 开启了,那么只有单引号内的会被认为是 String Literals,对于双引号内的字符串,会被认为是一个 identifier。binary string 是一串 bytes 组成的字符串,每一个 binary string 有一个叫做 binary 的 character set 和 collation。一个非二进制的字符串是一个由字符组成的字符串,它有除 binary 外的 character set和与之兼容的 collation。对于两种字符串类型,比较都是基于每个字符的数值。对于 binary string 而言,比较单元就是字节,对于非二进制的字符串,那么单元就是字符,而有的字符集支持多字节字符。一个 String Literal 可以拥有一个可选的 character set introducer 和 COLLATE clause,可以用来指派特定的字符集跟 collation(TiDB 对此只是做了语法上的兼容,并不实质做处理)。[_charset_name]'string' [COLLATE collation_name] 例如:SELECT _latin1'string'; SELECT _binary'string'; SELECT _utf8'string' COLLATE utf8_bin; 你可以使用 N’literal’ 或者 n’literal’ 来创建使用 national character set 的字符串,下列语句是一样的:SELECT N'some text'; SELECT n'some text'; SELECT _utf8'some text'; 转义字符:| 转义序列 | 意义 | | :——-: | :——-:| | 0 | ASCII NUL (X’00’) 字符 | | ’ | 单引号 | | ” | 双引号 | | b | 退格符号 | | n | 换行符 | | r | 回车符 | | t | tab 符(制表符)| | z | ASCII 26 (Ctrl + Z) | | | 反斜杠 | | % | % | | _ | _ |如果要在 string literal 中使用 ' 或者 ",有以下几种办法: 在 ' 引用的字符串中,可以用 '' 来表示单引号。 在 " 引用的字符串中,可以用 "" 来表示双引号。 前面接转义符。 在 ' 中表示 " 或者在 " 中表示 ' 都不需要特别的处理。 更多细节。"}, {"url": "https://pingcap.com/success-stories/", "title": "Success Stories", "content": ""}, {"url": "https://pingcap.com/docs/tools/syncer/", "title": "Syncer User Guide", "content": " Syncer User Guide About Syncer Syncer is a tool used to import data incrementally. It is a part of the TiDB enterprise toolset. To obtain Syncer, see Download the TiDB enterprise toolset.Syncer architecture Download the TiDB enterprise toolset (Linux) # Download the tool package. wget http://download.pingcap.org/tidb-enterprise-tools-latest-linux-amd64.tar.gz wget http://download.pingcap.org/tidb-enterprise-tools-latest-linux-amd64.sha256 # Check the file integrity. If the result is OK, the file is correct. sha256sum -c tidb-enterprise-tools-latest-linux-amd64.sha256 # Extract the package. tar -xzf tidb-enterprise-tools-latest-linux-amd64.tar.gz cd tidb-enterprise-tools-latest-linux-amd64 Where to deploy Syncer You can deploy Syncer to any of the machines that can connect to MySQL or the TiDB cluster. But it is recommended to deploy Syncer to the TiDB cluster.Use Syncer to import data incrementally Before importing data, read Check before importing data using Syncer.1. Set the position to synchronize Edit the meta file of Syncer, assuming the meta file is syncer.meta:# cat syncer.meta binlog-name = "mysql-bin.000003" binlog-pos = 930143241 binlog-gtid = "2bfabd22-fff7-11e6-97f7-f02fa73bcb01:1-23,61ccbb5d-c82d-11e6-ac2e-487b6bd31bf7:1-4" Note: The syncer.meta file only needs to be configured when it is first used. The position is automatically updated when the new subsequent binlog is synchronized. If you use the binlog position to synchronize, you only need to configure binlog-name and binlog-pos; if you use binlog-gtid to synchronize, you need to configure binlog-gtid and set --enable-gtid when starting Syncer. 2. Start Syncer Description of Syncer command line options:Usage of Syncer: -L string log level: debug, info, warn, error, fatal (default "info") -V to print Syncer version info (default false) -auto-fix-gtid to automatically fix the gtid info when MySQL master and slave switches (default false) -b int the size of batch transactions (default 10) -c int the number of batch threads that Syncer processes (default 16) -config string to specify the corresponding configuration file when starting Syncer; for example, `--config config.toml` -enable-gtid to start Syncer using the mode; default false; before enabling this option, you need to enable GTID in the upstream MySQL -log-file string to specify the log file directory, such as `--log-file ./syncer.log` -log-rotate string to specify the log file rotating cycle, hour/day (default "day") -meta string to specify the meta file of Syncer upstream (in the same directory with the configuration file by default "syncer.meta") -server-id int to specify MySQL slave sever-id (default 101) -status-addr string to specify Syncer metrics, such as `--status-addr 127:0.0.1:10088` The config.toml configuration file of Syncer:log-level = "info" server-id = 101 # The file path for meta: meta = "./syncer.meta" worker-count = 16 batch = 10 # The testing address for pprof. It can also be used by Prometheus to pull Syncer metrics. # Change "127.0.0.1" to the IP address of the corresponding host status-addr = "127.0.0.1:10086" # Note: skip-sqls is abandoned, and use skip-ddls instead. # skip-ddls skips the DDL statements that are incompatible with TiDB, and supports regular expressions. # skip-ddls = ["^CREATEs+USER"] # Note: skip-events is abandoned, and use skip-dmls instead. # skip-dmls skips the DML statements. The type value can be 'insert', 'update' and 'delete'. # The 'delete' statements that skip-dmls skips in the foo.bar table: # [[skip-dmls]] # db-name = "foo" # tbl-name = "bar" # type = "delete" # # The 'delete' statements that skip-dmls skips in all tables: # [[skip-dmls]] # type = "delete" # # The 'delete' statements that skip-dmls skips in all foo.* tables: # [[skip-dmls]] # db-name = "foo" # type = "delete" # Specify the database name to be synchronized. Support regular expressions. Start with '~' to use regular expressions. # replicate-do-db = ["~^b.*","s1"] # Specify the db.table to be synchronized. # db-name and tbl-name do not support the `db-name ="dbname, dbname2"` format. # [[replicate-do-table]] # db-name ="dbname" # tbl-name = "table-name" # [[replicate-do-table]] # db-name ="dbname1" # tbl-name = "table-name1" # Specify the db.table to be synchronized. Support regular expressions. Start with '~' to use regular expressions. # [[replicate-do-table]] # db-name ="test" # tbl-name = "~^a.*" # Specify the database you want to ignore in synchronization. Support regular expressions. Start with '~' to use regular expressions. # replicate-ignore-db = ["~^b.*","s1"] # Specify the database table you want to ignore in synchronization. # db-name and tbl-name do not support the `db-name ="dbname, dbname2"` format. # [[replicate-ignore-table]] # db-name = "your_db" # tbl-name = "your_table" # Specify the database table you want to ignore in synchronization. Support regular expressions. Start with '~' to use regular expressions. # [[replicate-ignore-table]] # db-name ="test" # tbl-name = "~^a.*" # The sharding synchronizing rules support wildcharacter. # 1. The asterisk character ("*", also called "star") matches zero or more characters, # For example, "doc*" matches "doc" and "document" but not "dodo"; # The asterisk character must be in the end of the wildcard word, # and there is only one asterisk in one wildcard word. # 2. The question mark ("?") matches any single character. # [[route-rules]] # pattern-schema = "route_*" # pattern-table = "abc_*" # target-schema = "route" # target-table = "abc" # [[route-rules]] # pattern-schema = "route_*" # pattern-table = "xyz_*" # target-schema = "route" # target-table = "xyz" [from] host = "127.0.0.1" user = "root" password = "" port = 3306 [to] host = "127.0.0.1" user = "root" password = "" port = 4000 Start Syncer:./bin/syncer -config config.toml 2016/10/27 15:22:01 binlogsyncer.go:226: [info] begin to sync binlog from position (mysql-bin.000003, 1280) 2016/10/27 15:22:01 binlogsyncer.go:130: [info] register slave for master server 127.0.0.1:3306 2016/10/27 15:22:01 binlogsyncer.go:552: [info] rotate to (mysql-bin.000003, 1280) 2016/10/27 15:22:01 syncer.go:549: [info] rotate binlog to (mysql-bin.000003, 1280) 3. Insert data into MySQL INSERT INTO t1 VALUES (4, 4), (5, 5); 4. Log in to TiDB and view the data mysql -h127.0.0.1 -P4000 -uroot -p mysql> select * from t1; +----+------+ | id | age | +----+------+ | 1 | 1 | | 2 | 2 | | 3 | 3 | | 4 | 4 | | 5 | 5 | +----+------+ Syncer outputs the current synchronized data statistics every 30 seconds:2017/06/08 01:18:51 syncer.go:934: [info] [syncer]total events = 15, total tps = 130, recent tps = 4, master-binlog = (ON.000001, 11992), master-binlog-gtid=53ea0ed1-9bf8-11e6-8bea-64006a897c73:1-74, syncer-binlog = (ON.000001, 2504), syncer-binlog-gtid = 53ea0ed1-9bf8-11e6-8bea-64006a897c73:1-17 2017/06/08 01:19:21 syncer.go:934: [info] [syncer]total events = 15, total tps = 191, recent tps = 2, master-binlog = (ON.000001, 11992), master-binlog-gtid=53ea0ed1-9bf8-11e6-8bea-64006a897c73:1-74, syncer-binlog = (ON.000001, 2504), syncer-binlog-gtid = 53ea0ed1-9bf8-11e6-8bea-64006a897c73:1-35 The update in MySQL is automatically synchronized in TiDB.Description of Syncer configuration Specify the database to be synchronized This section describes the priority of parameters when you use Syncer to synchronize the database. To use the route-rules, see Support for synchronizing data from sharded tables. Priority: replicate-do-db …"}, {"url": "https://pingcap.com/docs/v1.0/tools/syncer/", "title": "Syncer User Guide", "content": " Syncer User Guide About Syncer Syncer is a tool used to import data incrementally. It is a part of the TiDB enterprise toolset. To obtain Syncer, see Download the TiDB enterprise toolset.Syncer architecture Download the TiDB enterprise toolset (Linux) # Download the tool package. wget http://download.pingcap.org/tidb-enterprise-tools-latest-linux-amd64.tar.gz wget http://download.pingcap.org/tidb-enterprise-tools-latest-linux-amd64.sha256 # Check the file integrity. If the result is OK, the file is correct. sha256sum -c tidb-enterprise-tools-latest-linux-amd64.sha256 # Extract the package. tar -xzf tidb-enterprise-tools-latest-linux-amd64.tar.gz cd tidb-enterprise-tools-latest-linux-amd64 Where to deploy Syncer You can deploy Syncer to any of the machines that can connect to MySQL or the TiDB cluster. But it is recommended to deploy Syncer to the TiDB cluster.Use Syncer to import data incrementally Before importing data, read Check before importing data using Syncer.1. Set the position to synchronize Edit the meta file of Syncer, assuming the meta file is syncer.meta:# cat syncer.meta binlog-name = "mysql-bin.000003" binlog-pos = 930143241 binlog-gtid = "2bfabd22-fff7-11e6-97f7-f02fa73bcb01:1-23,61ccbb5d-c82d-11e6-ac2e-487b6bd31bf7:1-4" Note: The syncer.meta file only needs to be configured when it is first used. The position is automatically updated when the new subsequent binlog is synchronized. If you use the binlog position to synchronize, you only need to configure binlog-name and binlog-pos; if you use binlog-gtid to synchronize, you need to configure binlog-gtid and set --enable-gtid when starting Syncer. 2. Start Syncer Description of Syncer command line options:Usage of Syncer: -L string log level: debug, info, warn, error, fatal (default "info") -V to print Syncer version info (default false) -auto-fix-gtid to automatically fix the gtid info when MySQL master and slave switches (default false) -b int the size of batch transactions (default 10) -c int the number of batch threads that Syncer processes (default 16) -config string to specify the corresponding configuration file when starting Syncer; for example, `--config config.toml` -enable-gtid to start Syncer using the mode; default false; before enabling this option, you need to enable GTID in the upstream MySQL -log-file string to specify the log file directory, such as `--log-file ./syncer.log` -log-rotate string to specify the log file rotating cycle, hour/day (default "day") -meta string to specify the meta file of Syncer upstream (in the same directory with the configuration file by default "syncer.meta") -server-id int to specify MySQL slave sever-id (default 101) -status-addr string to specify Syncer metrics, such as `--status-addr 127:0.0.1:10088` The config.toml configuration file of Syncer:log-level = "info" server-id = 101 # The file path for meta: meta = "./syncer.meta" worker-count = 16 batch = 10 # The testing address for pprof. It can also be used by Prometheus to pull Syncer metrics. # Change "127.0.0.1" to the IP address of the corresponding host status-addr = "127.0.0.1:10086" # Note: skip-sqls is abandoned, and use skip-ddls instead. # skip-ddls skips the DDL statements that are incompatible with TiDB, and supports regular expressions. # skip-ddls = ["^CREATEs+USER"] # Note: skip-events is abandoned, and use skip-dmls instead. # skip-dmls skips the DML statements. The type value can be 'insert', 'update' and 'delete'. # The 'delete' statements that skip-dmls skips in the foo.bar table: # [[skip-dmls]] # db-name = "foo" # tbl-name = "bar" # type = "delete" # # The 'delete' statements that skip-dmls skips in all tables: # [[skip-dmls]] # type = "delete" # # The 'delete' statements that skip-dmls skips in all foo.* tables: # [[skip-dmls]] # db-name = "foo" # type = "delete" # Specify the database name to be synchronized. Support regular expressions. Start with '~' to use regular expressions. # replicate-do-db = ["~^b.*","s1"] # Specify the db.table to be synchronized. # db-name and tbl-name do not support the `db-name ="dbname,dbname2"` format. # [[replicate-do-table]] # db-name ="dbname" # tbl-name = "table-name" # [[replicate-do-table]] # db-name ="dbname1" # tbl-name = "table-name1" # Specify the db.table to be synchronized. Support regular expressions. Start with '~' to use regular expressions. # [[replicate-do-table]] # db-name ="test" # tbl-name = "~^a.*" # Specify the database you want to ignore in synchronization. Support regular expressions. Start with '~' to use regular expressions. # replicate-ignore-db = ["~^b.*","s1"] # Specify the database table you want to ignore in synchronization. # db-name and tbl-name do not support the `db-name ="dbname,dbname2"` format. # [[replicate-ignore-table]] # db-name = "your_db" # tbl-name = "your_table" # Specify the database table you want to ignore in synchronization. Support regular expressions. Start with '~' to use regular expressions. # [[replicate-ignore-table]] # db-name ="test" # tbl-name = "~^a.*" # The sharding synchronizing rules support wildcharacter. # 1. The asterisk character ("*", also called "star") matches zero or more characters, # For example, "doc*" matches "doc" and "document" but not "dodo"; # The asterisk character must be in the end of the wildcard word, # and there is only one asterisk in one wildcard word. # 2. The question mark ("?") matches any single character. # [[route-rules]] # pattern-schema = "route_*" # pattern-table = "abc_*" # target-schema = "route" # target-table = "abc" # [[route-rules]] # pattern-schema = "route_*" # pattern-table = "xyz_*" # target-schema = "route" # target-table = "xyz" [from] host = "127.0.0.1" user = "root" password = "" port = 3306 [to] host = "127.0.0.1" user = "root" password = "" port = 4000 Start Syncer:./bin/syncer -config config.toml 2016/10/27 15:22:01 binlogsyncer.go:226: [info] begin to sync binlog from position (mysql-bin.000003, 1280) 2016/10/27 15:22:01 binlogsyncer.go:130: [info] register slave for master server 127.0.0.1:3306 2016/10/27 15:22:01 binlogsyncer.go:552: [info] rotate to (mysql-bin.000003, 1280) 2016/10/27 15:22:01 syncer.go:549: [info] rotate binlog to (mysql-bin.000003, 1280) 3. Insert data into MySQL INSERT INTO t1 VALUES (4, 4), (5, 5); 4. Log in to TiDB and view the data mysql -h127.0.0.1 -P4000 -uroot -p mysql> select * from t1; +----+------+ | id | age | +----+------+ | 1 | 1 | | 2 | 2 | | 3 | 3 | | 4 | 4 | | 5 | 5 | +----+------+ Syncer outputs the current synchronized data statistics every 30 seconds:2017/06/08 01:18:51 syncer.go:934: [info] [syncer]total events = 15, total tps = 130, recent tps = 4, master-binlog = (ON.000001, 11992), master-binlog-gtid=53ea0ed1-9bf8-11e6-8bea-64006a897c73:1-74, syncer-binlog = (ON.000001, 2504), syncer-binlog-gtid = 53ea0ed1-9bf8-11e6-8bea-64006a897c73:1-17 2017/06/08 01:19:21 syncer.go:934: [info] [syncer]total events = 15, total tps = 191, recent tps = 2, master-binlog = (ON.000001, 11992), master-binlog-gtid=53ea0ed1-9bf8-11e6-8bea-64006a897c73:1-74, syncer-binlog = (ON.000001, 2504), syncer-binlog-gtid = 53ea0ed1-9bf8-11e6-8bea-64006a897c73:1-35 The update in MySQL is automatically synchronized in TiDB.Description of Syncer configuration Specify the database to be synchronized This section describes the priority of parameters when you use Syncer to synchronize the database. To use the route-rules, see Support for synchronizing data from sharded tables. Priority: replicate-do-db …"}, {"url": "https://pingcap.com/docs/v2.0/tools/syncer/", "title": "Syncer User Guide", "content": " Syncer User Guide About Syncer Syncer is a tool used to import data incrementally. It is a part of the TiDB enterprise toolset. To obtain Syncer, see Download the TiDB enterprise toolset.Syncer architecture Download the TiDB enterprise toolset (Linux) # Download the tool package. wget http://download.pingcap.org/tidb-enterprise-tools-latest-linux-amd64.tar.gz wget http://download.pingcap.org/tidb-enterprise-tools-latest-linux-amd64.sha256 # Check the file integrity. If the result is OK, the file is correct. sha256sum -c tidb-enterprise-tools-latest-linux-amd64.sha256 # Extract the package. tar -xzf tidb-enterprise-tools-latest-linux-amd64.tar.gz cd tidb-enterprise-tools-latest-linux-amd64 Where to deploy Syncer You can deploy Syncer to any of the machines that can connect to MySQL or the TiDB cluster. But it is recommended to deploy Syncer to the TiDB cluster.Use Syncer to import data incrementally Before importing data, read Check before importing data using Syncer.1. Set the position to synchronize Edit the meta file of Syncer, assuming the meta file is syncer.meta:# cat syncer.meta binlog-name = "mysql-bin.000003" binlog-pos = 930143241 binlog-gtid = "2bfabd22-fff7-11e6-97f7-f02fa73bcb01:1-23,61ccbb5d-c82d-11e6-ac2e-487b6bd31bf7:1-4" Note: The syncer.meta file only needs to be configured when it is first used. The position is automatically updated when the new subsequent binlog is synchronized. If you use the binlog position to synchronize, you only need to configure binlog-name and binlog-pos; if you use binlog-gtid to synchronize, you need to configure binlog-gtid and set --enable-gtid when starting Syncer. 2. Start Syncer Description of Syncer command line options:Usage of Syncer: -L string log level: debug, info, warn, error, fatal (default "info") -V to print Syncer version info (default false) -auto-fix-gtid to automatically fix the gtid info when MySQL master and slave switches (default false) -b int the size of batch transactions (default 10) -c int the number of batch threads that Syncer processes (default 16) -config string to specify the corresponding configuration file when starting Syncer; for example, `--config config.toml` -enable-gtid to start Syncer using the mode; default false; before enabling this option, you need to enable GTID in the upstream MySQL -log-file string to specify the log file directory, such as `--log-file ./syncer.log` -log-rotate string to specify the log file rotating cycle, hour/day (default "day") -meta string to specify the meta file of Syncer upstream (in the same directory with the configuration file by default "syncer.meta") -server-id int to specify MySQL slave sever-id (default 101) -status-addr string to specify Syncer metrics, such as `--status-addr 127:0.0.1:10088` The config.toml configuration file of Syncer:log-level = "info" server-id = 101 # The file path for meta: meta = "./syncer.meta" worker-count = 16 batch = 10 # The testing address for pprof. It can also be used by Prometheus to pull Syncer metrics. # Change "127.0.0.1" to the IP address of the corresponding host status-addr = "127.0.0.1:10086" # Note: skip-sqls is abandoned, and use skip-ddls instead. # skip-ddls skips the DDL statements that are incompatible with TiDB, and supports regular expressions. # skip-ddls = ["^CREATEs+USER"] # Note: skip-events is abandoned, and use skip-dmls instead. # skip-dmls skips the DML statements. The type value can be 'insert', 'update' and 'delete'. # The 'delete' statements that skip-dmls skips in the foo.bar table: # [[skip-dmls]] # db-name = "foo" # tbl-name = "bar" # type = "delete" # # The 'delete' statements that skip-dmls skips in all tables: # [[skip-dmls]] # type = "delete" # # The 'delete' statements that skip-dmls skips in all foo.* tables: # [[skip-dmls]] # db-name = "foo" # type = "delete" # Specify the database name to be synchronized. Support regular expressions. Start with '~' to use regular expressions. # replicate-do-db = ["~^b.*","s1"] # Specify the db.table to be synchronized. # db-name and tbl-name do not support the `db-name ="dbname, dbname2"` format. # [[replicate-do-table]] # db-name ="dbname" # tbl-name = "table-name" # [[replicate-do-table]] # db-name ="dbname1" # tbl-name = "table-name1" # Specify the db.table to be synchronized. Support regular expressions. Start with '~' to use regular expressions. # [[replicate-do-table]] # db-name ="test" # tbl-name = "~^a.*" # Specify the database you want to ignore in synchronization. Support regular expressions. Start with '~' to use regular expressions. # replicate-ignore-db = ["~^b.*","s1"] # Specify the database table you want to ignore in synchronization. # db-name and tbl-name do not support the `db-name ="dbname, dbname2"` format. # [[replicate-ignore-table]] # db-name = "your_db" # tbl-name = "your_table" # Specify the database table you want to ignore in synchronization. Support regular expressions. Start with '~' to use regular expressions. # [[replicate-ignore-table]] # db-name ="test" # tbl-name = "~^a.*" # The sharding synchronizing rules support wildcharacter. # 1. The asterisk character ("*", also called "star") matches zero or more characters, # For example, "doc*" matches "doc" and "document" but not "dodo"; # The asterisk character must be in the end of the wildcard word, # and there is only one asterisk in one wildcard word. # 2. The question mark ("?") matches any single character. # [[route-rules]] # pattern-schema = "route_*" # pattern-table = "abc_*" # target-schema = "route" # target-table = "abc" # [[route-rules]] # pattern-schema = "route_*" # pattern-table = "xyz_*" # target-schema = "route" # target-table = "xyz" [from] host = "127.0.0.1" user = "root" password = "" port = 3306 [to] host = "127.0.0.1" user = "root" password = "" port = 4000 Start Syncer:./bin/syncer -config config.toml 2016/10/27 15:22:01 binlogsyncer.go:226: [info] begin to sync binlog from position (mysql-bin.000003, 1280) 2016/10/27 15:22:01 binlogsyncer.go:130: [info] register slave for master server 127.0.0.1:3306 2016/10/27 15:22:01 binlogsyncer.go:552: [info] rotate to (mysql-bin.000003, 1280) 2016/10/27 15:22:01 syncer.go:549: [info] rotate binlog to (mysql-bin.000003, 1280) 3. Insert data into MySQL INSERT INTO t1 VALUES (4, 4), (5, 5); 4. Log in to TiDB and view the data mysql -h127.0.0.1 -P4000 -uroot -p mysql> select * from t1; +----+------+ | id | age | +----+------+ | 1 | 1 | | 2 | 2 | | 3 | 3 | | 4 | 4 | | 5 | 5 | +----+------+ Syncer outputs the current synchronized data statistics every 30 seconds:2017/06/08 01:18:51 syncer.go:934: [info] [syncer]total events = 15, total tps = 130, recent tps = 4, master-binlog = (ON.000001, 11992), master-binlog-gtid=53ea0ed1-9bf8-11e6-8bea-64006a897c73:1-74, syncer-binlog = (ON.000001, 2504), syncer-binlog-gtid = 53ea0ed1-9bf8-11e6-8bea-64006a897c73:1-17 2017/06/08 01:19:21 syncer.go:934: [info] [syncer]total events = 15, total tps = 191, recent tps = 2, master-binlog = (ON.000001, 11992), master-binlog-gtid=53ea0ed1-9bf8-11e6-8bea-64006a897c73:1-74, syncer-binlog = (ON.000001, 2504), syncer-binlog-gtid = 53ea0ed1-9bf8-11e6-8bea-64006a897c73:1-35 The update in MySQL is automatically synchronized in TiDB.Description of Syncer configuration Specify the database to be synchronized This section describes the priority of parameters when you use Syncer to synchronize the database. To use the route-rules, see Support for synchronizing data from sharded tables. Priority: replicate-do-db …"}, {"url": "https://pingcap.com/docs-cn/tools/syncer/", "title": "Syncer 使用文档", "content": " Syncer 使用文档 Syncer 简介 Syncer 是一个数据导入工具,能方便地将 MySQL 的数据增量导入到 TiDB。Syncer 属于 TiDB 企业版工具集,如何获取可参考下载 TiDB 企业版工具集。Syncer 架构 下载 TiDB 企业版工具集 (Linux) # 下载 tool 压缩包 wget http://download.pingcap.org/tidb-enterprise-tools-latest-linux-amd64.tar.gz wget http://download.pingcap.org/tidb-enterprise-tools-latest-linux-amd64.sha256 # 检查文件完整性,返回 ok 则正确 sha256sum -c tidb-enterprise-tools-latest-linux-amd64.sha256 # 解开压缩包 tar -xzf tidb-enterprise-tools-latest-linux-amd64.tar.gz cd tidb-enterprise-tools-latest-linux-amd64 Syncer 部署位置 Syncer 可以部署在任一台可以连通对应的 MySQL 和 TiDB 集群的机器上,推荐部署在 TiDB 集群。Syncer 增量导入数据示例 使用前请详细阅读 Syncer 同步前预检查设置同步开始的 position 设置 Syncer 的 meta 文件, 这里假设 meta 文件是 syncer.meta:# cat syncer.meta binlog-name = "mysql-bin.000003" binlog-pos = 930143241 binlog-gtid = "2bfabd22-fff7-11e6-97f7-f02fa73bcb01:1-23,61ccbb5d-c82d-11e6-ac2e-487b6bd31bf7:1-4" 注: syncer.meta 只需要第一次使用的时候配置,后续 Syncer 同步新的 binlog 之后会自动将其更新到最新的 position。 如果使用 binlog position 同步则只需要配置 binlog-name binlog-pos; 使用 gtid 同步则需要设置 gtid,且启动 Syncer 时带有 --enable-gtid。 启动 Syncer Syncer 的命令行参数说明:Usage of syncer: -L string 日志等级: debug, info, warn, error, fatal (默认为 "info") -V 输出 syncer 版本;默认 false -auto-fix-gtid 当 mysql master/slave 切换时,自动修复 gtid 信息;默认 false -b int batch 事务大小 (默认 10) -c int syncer 处理 batch 线程数 (默认 16) -config string 指定相应配置文件启动 sycner 服务;如 `--config config.toml` -enable-gtid 使用 gtid 模式启动 syncer;默认 false,开启前需要上游 MySQL 开启 GTID 功能 -log-file string 指定日志文件目录;如 `--log-file ./syncer.log` -log-rotate string 指定日志切割周期, hour/day (默认 "day") -meta string 指定 syncer 上游 meta 信息文件 (默认与配置文件相同目录下 "syncer.meta") -server-id int 指定 MySQL slave sever-id (默认 101) -status-addr string 指定 syncer metric 信息; 如 `--status-addr 127:0.0.1:10088` Syncer 的配置文件 config.toml:log-level = "info" server-id = 101 ## meta 文件地址 meta = "./syncer.meta" worker-count = 16 batch = 10 ## pprof 调试地址, Prometheus 也可以通过该地址拉取 syncer metrics ## 将 127.0.0.1 修改为相应主机 IP 地址 status-addr = "127.0.0.1:10086" # 注意: skip-sqls 已经废弃, 请使用 skip-ddls. # skip-ddls 可以跳过与 TiDB 不兼容的 DDL 语句,支持正则语法。 # skip-ddls = ["^CREATEs+USER"] # 注意: skip-events 已经废弃, 请使用 skip-dmls # skip-dmls 用于跳过 DML 语句. type 字段取值为 'insert', 'update', 'delete'。 # 下面的例子为跳过 foo.bar 表的所有 delete 语句。 # [[skip-dmls]] # db-name = "foo" # tbl-name = "bar" # type = "delete" # # 下面的例子为跳过所有表的 delete 语句。 # [[skip-dmls]] # type = "delete" # # 下面的例子为跳过 foo 库中所有表的 delete 语句。 # [[skip-dmls]] # db-name = "foo" # type = "delete" ## 指定要同步数据库名;支持正则匹配,表达式语句必须以 `~` 开始 #replicate-do-db = ["~^b.*","s1"] ## 指定要同步的 db.table 表 ## db-name 与 tbl-name 不支持 `db-name ="dbname,dbname2"` 格式 #[[replicate-do-table]] #db-name ="dbname" #tbl-name = "table-name" #[[replicate-do-table]] #db-name ="dbname1" #tbl-name = "table-name1" ## 指定要同步的 db.table 表;支持正则匹配,表达式语句必须以 `~` 开始 #[[replicate-do-table]] #db-name ="test" #tbl-name = "~^a.*" ## 指定**忽略**同步数据库;支持正则匹配,表达式语句必须以 `~` 开始 #replicate-ignore-db = ["~^b.*","s1"] ## 指定**忽略**同步数据库 ## db-name & tbl-name 不支持 `db-name ="dbname,dbname2"` 语句格式 #[[replicate-ignore-table]] #db-name = "your_db" #tbl-name = "your_table" ## 指定要**忽略**同步数据库名;支持正则匹配,表达式语句必须以 `~` 开始 #[[replicate-ignore-table]] #db-name ="test" #tbl-name = "~^a.*" # sharding 同步规则,采用 wildcharacter # 1. 星号字符 (*) 可以匹配零个或者多个字符, # 例子, doc* 匹配 doc 和 document, 但是和 dodo 不匹配; # 星号只能放在 pattern 结尾,并且一个 pattern 中只能有一个 # 2. 问号字符 (?) 匹配任一一个字符 #[[route-rules]] #pattern-schema = "route_*" #pattern-table = "abc_*" #target-schema = "route" #target-table = "abc" #[[route-rules]] #pattern-schema = "route_*" #pattern-table = "xyz_*" #target-schema = "route" #target-table = "xyz" [from] host = "127.0.0.1" user = "root" password = "" port = 3306 [to] host = "127.0.0.1" user = "root" password = "" port = 4000 启动 Syncer:./bin/syncer -config config.toml 2016/10/27 15:22:01 binlogsyncer.go:226: [info] begin to sync binlog from position (mysql-bin.000003, 1280) 2016/10/27 15:22:01 binlogsyncer.go:130: [info] register slave for master server 127.0.0.1:3306 2016/10/27 15:22:01 binlogsyncer.go:552: [info] rotate to (mysql-bin.000003, 1280) 2016/10/27 15:22:01 syncer.go:549: [info] rotate binlog to (mysql-bin.000003, 1280) 在 MySQL 中插入新的数据 INSERT INTO t1 VALUES (4, 4), (5, 5); 登录到 TiDB 查看:mysql -h127.0.0.1 -P4000 -uroot -p mysql> select * from t1; +----+------+ | id | age | +----+------+ | 1 | 1 | | 2 | 2 | | 3 | 3 | | 4 | 4 | | 5 | 5 | +----+------+ Syncer 每隔 30s 会输出当前的同步统计,如下所示:2017/06/08 01:18:51 syncer.go:934: [info] [syncer]total events = 15, total tps = 130, recent tps = 4, master-binlog = (ON.000001, 11992), master-binlog-gtid=53ea0ed1-9bf8-11e6-8bea-64006a897c73:1-74, syncer-binlog = (ON.000001, 2504), syncer-binlog-gtid = 53ea0ed1-9bf8-11e6-8bea-64006a897c73:1-17 2017/06/08 01:19:21 syncer.go:934: [info] [syncer]total events = 15, total tps = 191, recent tps = 2, master-binlog = (ON.000001, 11992), master-binlog-gtid=53ea0ed1-9bf8-11e6-8bea-64006a897c73:1-74, syncer-binlog = (ON.000001, 2504), syncer-binlog-gtid = 53ea0ed1-9bf8-11e6-8bea-64006a897c73:1-35 由上述示例可见,使用 Syncer 可以自动将 MySQL 的更新同步到 TiDB。Syncer 配置说明 指定数据库同步 本部分将通过实际案例描述 Syncer 同步数据库参数的优先级关系。 如果使用 route-rules 规则,参考 Sharding 同步支持 优先级:replicate-do-db –> replicate-do-table –> replicate-ignore-db –> replicate-ignore-table # 指定同步 ops 数据库 # 指定同步以 ti 开头的数据库 replicate-do-db = ["ops","~^ti.*"] # china 数据库下有 guangzhou / shanghai / beijing 等多张表,只同步 shanghai 与 beijing 表。 # 指定同步 china 数据库下 shanghai 表 [[replicate-do-table]] db-name ="china" tbl-name = "shanghai" # 指定同步 china 数据库下 beijing 表 [[replicate-do-table]] db-name ="china" tbl-name = "beijing" # ops 数据库下有 ops_user / ops_admin / weekly 等数据表,只需要同步 ops_user 表。 # 因 replicate-do-db 优先级比 replicate-do-table 高,所以此处设置只同步 ops_user 表无效,实际工作会同步 ops 整个数据库 [[replicate-do-table]] db-name ="ops" tbl-name = "ops_user" # history 数据下有 2017_01 2017_02 ... 2017_12 / 2016_01 2016_02 ... 2016_12 等多张表,只需要同步 2017 年的数据表 [[replicate-do-table]] db-name ="history" tbl-name = "~^2017_.*" # 忽略同步 ops 与 fault 数据库 # 忽略同步以 www 开头的数据库 ## 因 replicate-do-db 优先级比 replicate-ignore-db 高,所以此处忽略同步 ops 不生效。 replicate-ignore-db = ["ops","fault","~^www"] # fault 数据库下有 faults / user_feedback / ticket 等数据表 # 忽略同步 user_feedback 数据表 # 因 replicate-ignore-db 优先级比 replicate-ignore-table 高,所以此处设置只同步 user_feedback 表无效,实际工作会同步 fault 整个数据库 [[replicate-ignore-table]] db-name = "fault" tbl-name = "user_feedback" # order 数据下有 2017_01 2017_02 ... 2017_12 / 2016_01 2016_02 ... 2016_12 等多张表,忽略 2016 年的数据表 [[replicate-ignore-table]] db-name ="order" tbl-name = "~^2016_.*" Sharding 同步支持 根据配置文件的 route-rules,支持将分库分表的数据导入到同一个库同一个表中,但是在开始前需要检查分库分表规则,如下: 是否可以利用 route-rules 的语义规则表示 分表中是否包含唯一递增主键,或者合并后是否包含数据上有冲突的唯一索引或者主键 暂时对 DDL 支持不完善。分库分表同步示例 只需在所有 MySQL 实例下面,启动 Syncer, 并设置 route-rules。 replicate-do-db & replicate-ignore-db 与 route-rules 同时使用场景下,replicate-do-db & replicate-ignore-db 需要指定 route-rules 中 target-schema & target-table 的内容。 # 场景如下: # 数据库A 下有 order_2016 / history_2016 等多个数据库 # 数据库B 下有 order_2017 / history_2017 等多个数据库 # 指定同步数据库A order_2016 数据库,数据表如下 2016_01 2016_02 ... 2016_12 # 指定同步数据表B order_2017 数据库,数据表如下 2017_01 2017_02 ... 2017_12 # 表内使用 order_id 作为主键,数据之间主键不冲突 # 忽略同步 history_2016 与 history_2017 数据库 # 目标库需要为 order ,目标数据表为 order_2017 / order_2016 # Syncer 获取到上游数据后,发现 route-rules 规则启用,先做合库合表操作,再进行 do-db & do-table 判定 ## 此处需要设置 target-schema & target-table 判定需要同步的数据库 [[replicate-do-table]] db-name ="order" tbl-name = "order_2016" [[replicate-do-table]] db-name ="order" tbl-name = "order_2017" [[route-rules]] …"}, {"url": "https://pingcap.com/docs-cn/v1.0/tools/syncer/", "title": "Syncer 使用文档", "content": " Syncer 使用文档 Syncer 简介 Syncer 是一个数据导入工具,能方便地将 MySQL 的数据增量导入到 TiDB。Syncer 属于 TiDB 企业版工具集,如何获取可参考下载 TiDB 企业版工具集。Syncer 架构 下载 TiDB 企业版工具集 (Linux) # 下载 tool 压缩包 wget http://download.pingcap.org/tidb-enterprise-tools-latest-linux-amd64.tar.gz wget http://download.pingcap.org/tidb-enterprise-tools-latest-linux-amd64.sha256 # 检查文件完整性,返回 ok 则正确 sha256sum -c tidb-enterprise-tools-latest-linux-amd64.sha256 # 解开压缩包 tar -xzf tidb-enterprise-tools-latest-linux-amd64.tar.gz cd tidb-enterprise-tools-latest-linux-amd64 Syncer 部署位置 Syncer 可以部署在任一台可以连通对应的 MySQL 和 TiDB 集群的机器上,推荐部署在 TiDB 集群。Syncer 增量导入数据示例 使用前请详细阅读 Syncer 同步前预检查设置同步开始的 position 设置 Syncer 的 meta 文件, 这里假设 meta 文件是 syncer.meta:# cat syncer.meta binlog-name = "mysql-bin.000003" binlog-pos = 930143241 binlog-gtid = "2bfabd22-fff7-11e6-97f7-f02fa73bcb01:1-23,61ccbb5d-c82d-11e6-ac2e-487b6bd31bf7:1-4" 注: syncer.meta 只需要第一次使用的时候配置,后续 Syncer 同步新的 binlog 之后会自动将其更新到最新的 position。 如果使用 binlog position 同步则只需要配置 binlog-name binlog-pos; 使用 gtid 同步则需要设置 gtid,且启动 Syncer 时带有 --enable-gtid。 启动 Syncer Syncer 的命令行参数说明:Usage of syncer: -L string 日志等级: debug, info, warn, error, fatal (默认为 "info") -V 输出 syncer 版本;默认 false -auto-fix-gtid 当 mysql master/slave 切换时,自动修复 gtid 信息;默认 false -b int batch 事务大小 (默认 10) -c int syncer 处理 batch 线程数 (默认 16) -config string 指定相应配置文件启动 sycner 服务;如 `--config config.toml` -enable-gtid 使用 gtid 模式启动 syncer;默认 false,开启前需要上游 MySQL 开启 GTID 功能 -log-file string 指定日志文件目录;如 `--log-file ./syncer.log` -log-rotate string 指定日志切割周期, hour/day (默认 "day") -meta string 指定 syncer 上游 meta 信息文件 (默认与配置文件相同目录下 "syncer.meta") -server-id int 指定 MySQL slave sever-id (默认 101) -status-addr string 指定 syncer metric 信息; 如 `--status-addr 127:0.0.1:10088` Syncer 的配置文件 config.toml:log-level = "info" server-id = 101 ## meta 文件地址 meta = "./syncer.meta" worker-count = 16 batch = 10 ## pprof 调试地址, Prometheus 也可以通过该地址拉取 syncer metrics ## 将 127.0.0.1 修改为相应主机 IP 地址 status-addr = "127.0.0.1:10086" # 注意: skip-sqls 已经废弃, 请使用 skip-ddls. # skip-ddls 可以跳过与 TiDB 不兼容的 DDL 语句,支持正则语法。 # skip-ddls = ["^CREATEs+USER"] # 注意: skip-events 已经废弃, 请使用 skip-dmls # skip-dmls 用于跳过 DML 语句. type 字段取值为 'insert', 'update', 'delete'。 # 下面的例子为跳过 foo.bar 表的所有 delete 语句。 # [[skip-dmls]] # db-name = "foo" # tbl-name = "bar" # type = "delete" # # 下面的例子为跳过所有表的 delete 语句。 # [[skip-dmls]] # type = "delete" # # 下面的例子为跳过 foo 库中所有表的 delete 语句。 # [[skip-dmls]] # db-name = "foo" # type = "delete" ## 指定要同步数据库名;支持正则匹配,表达式语句必须以 `~` 开始 #replicate-do-db = ["~^b.*","s1"] ## 指定要同步的 db.table 表 ## db-name 与 tbl-name 不支持 `db-name ="dbname,dbname2"` 格式 #[[replicate-do-table]] #db-name ="dbname" #tbl-name = "table-name" #[[replicate-do-table]] #db-name ="dbname1" #tbl-name = "table-name1" ## 指定要同步的 db.table 表;支持正则匹配,表达式语句必须以 `~` 开始 #[[replicate-do-table]] #db-name ="test" #tbl-name = "~^a.*" ## 指定**忽略**同步数据库;支持正则匹配,表达式语句必须以 `~` 开始 #replicate-ignore-db = ["~^b.*","s1"] ## 指定**忽略**同步数据库 ## db-name & tbl-name 不支持 `db-name ="dbname,dbname2"` 语句格式 #[[replicate-ignore-table]] #db-name = "your_db" #tbl-name = "your_table" ## 指定要**忽略**同步数据库名;支持正则匹配,表达式语句必须以 `~` 开始 #[[replicate-ignore-table]] #db-name ="test" #tbl-name = "~^a.*" # sharding 同步规则,采用 wildcharacter # 1. 星号字符 (*) 可以匹配零个或者多个字符, # 例子, doc* 匹配 doc 和 document, 但是和 dodo 不匹配; # 星号只能放在 pattern 结尾,并且一个 pattern 中只能有一个 # 2. 问号字符 (?) 匹配任一一个字符 #[[route-rules]] #pattern-schema = "route_*" #pattern-table = "abc_*" #target-schema = "route" #target-table = "abc" #[[route-rules]] #pattern-schema = "route_*" #pattern-table = "xyz_*" #target-schema = "route" #target-table = "xyz" [from] host = "127.0.0.1" user = "root" password = "" port = 3306 [to] host = "127.0.0.1" user = "root" password = "" port = 4000 启动 Syncer:./bin/syncer -config config.toml 2016/10/27 15:22:01 binlogsyncer.go:226: [info] begin to sync binlog from position (mysql-bin.000003, 1280) 2016/10/27 15:22:01 binlogsyncer.go:130: [info] register slave for master server 127.0.0.1:3306 2016/10/27 15:22:01 binlogsyncer.go:552: [info] rotate to (mysql-bin.000003, 1280) 2016/10/27 15:22:01 syncer.go:549: [info] rotate binlog to (mysql-bin.000003, 1280) 在 MySQL 中插入新的数据 INSERT INTO t1 VALUES (4, 4), (5, 5); 登录到 TiDB 查看:mysql -h127.0.0.1 -P4000 -uroot -p mysql> select * from t1; +----+------+ | id | age | +----+------+ | 1 | 1 | | 2 | 2 | | 3 | 3 | | 4 | 4 | | 5 | 5 | +----+------+ Syncer 每隔 30s 会输出当前的同步统计,如下所示:2017/06/08 01:18:51 syncer.go:934: [info] [syncer]total events = 15, total tps = 130, recent tps = 4, master-binlog = (ON.000001, 11992), master-binlog-gtid=53ea0ed1-9bf8-11e6-8bea-64006a897c73:1-74, syncer-binlog = (ON.000001, 2504), syncer-binlog-gtid = 53ea0ed1-9bf8-11e6-8bea-64006a897c73:1-17 2017/06/08 01:19:21 syncer.go:934: [info] [syncer]total events = 15, total tps = 191, recent tps = 2, master-binlog = (ON.000001, 11992), master-binlog-gtid=53ea0ed1-9bf8-11e6-8bea-64006a897c73:1-74, syncer-binlog = (ON.000001, 2504), syncer-binlog-gtid = 53ea0ed1-9bf8-11e6-8bea-64006a897c73:1-35 由上述示例可见,使用 Syncer 可以自动将 MySQL 的更新同步到 TiDB。Syncer 配置说明 指定数据库同步 本部分将通过实际案例描述 Syncer 同步数据库参数的优先级关系。 如果使用 route-rules 规则,参考 Sharding 同步支持 优先级:replicate-do-db –> replicate-do-table –> replicate-ignore-db –> replicate-ignore-table # 指定同步 ops 数据库 # 指定同步以 ti 开头的数据库 replicate-do-db = ["ops","~^ti.*"] # china 数据库下有 guangzhou / shanghai / beijing 等多张表,只同步 shanghai 与 beijing 表。 # 指定同步 china 数据库下 shanghai 表 [[replicate-do-table]] db-name ="china" tbl-name = "shanghai" # 指定同步 china 数据库下 beijing 表 [[replicate-do-table]] db-name ="china" tbl-name = "beijing" # ops 数据库下有 ops_user / ops_admin / weekly 等数据表,只需要同步 ops_user 表。 # 因 replicate-do-db 优先级比 replicate-do-table 高,所以此处设置只同步 ops_user 表无效,实际工作会同步 ops 整个数据库 [[replicate-do-table]] db-name ="ops" tbl-name = "ops_user" # history 数据下有 2017_01 2017_02 ... 2017_12 / 2016_01 2016_02 ... 2016_12 等多张表,只需要同步 2017 年的数据表 [[replicate-do-table]] db-name ="history" tbl-name = "~^2017_.*" # 忽略同步 ops 与 fault 数据库 # 忽略同步以 www 开头的数据库 ## 因 replicate-do-db 优先级比 replicate-ignore-db 高,所以此处忽略同步 ops 不生效。 replicate-ignore-db = ["ops","fault","~^www"] # fault 数据库下有 faults / user_feedback / ticket 等数据表 # 忽略同步 user_feedback 数据表 # 因 replicate-ignore-db 优先级比 replicate-ignore-table 高,所以此处设置只同步 user_feedback 表无效,实际工作会同步 fault 整个数据库 [[replicate-ignore-table]] db-name = "fault" tbl-name = "user_feedback" # order 数据下有 2017_01 2017_02 ... 2017_12 / 2016_01 2016_02 ... 2016_12 等多张表,忽略 2016 年的数据表 [[replicate-ignore-table]] db-name ="order" tbl-name = "~^2016_.*" Sharding 同步支持 根据配置文件的 route-rules,支持将分库分表的数据导入到同一个库同一个表中,但是在开始前需要检查分库分表规则,如下: 是否可以利用 route-rules 的语义规则表示 分表中是否包含唯一递增主键,或者合并后是否包含数据上有冲突的唯一索引或者主键 暂时对 DDL 支持不完善。分库分表同步示例 只需在所有 MySQL 实例下面,启动 Syncer, 并设置 route-rules。 replicate-do-db & replicate-ignore-db 与 route-rules 同时使用场景下,replicate-do-db & replicate-ignore-db 需要指定 route-rules 中 target-schema & target-table 的内容。 # 场景如下: # 数据库A 下有 order_2016 / history_2016 等多个数据库 # 数据库B 下有 order_2017 / history_2017 等多个数据库 # 指定同步数据库A order_2016 数据库,数据表如下 2016_01 2016_02 ... 2016_12 # 指定同步数据表B order_2017 数据库,数据表如下 2017_01 2017_02 ... 2017_12 # 表内使用 order_id 作为主键,数据之间主键不冲突 # 忽略同步 history_2016 与 history_2017 数据库 # 目标库需要为 order ,目标数据表为 order_2017 / order_2016 # Syncer 获取到上游数据后,发现 route-rules 规则启用,先做合库合表操作,再进行 do-db & do-table 判定 ## 此处需要设置 target-schema & target-table 判定需要同步的数据库 [[replicate-do-table]] db-name ="order" tbl-name = "order_2016" [[replicate-do-table]] db-name ="order" tbl-name = "order_2017" [[route-rules]] …"}, {"url": "https://pingcap.com/docs-cn/v2.0/tools/syncer/", "title": "Syncer 使用文档", "content": " Syncer 使用文档 Syncer 简介 Syncer 是一个数据导入工具,能方便地将 MySQL 的数据增量导入到 TiDB。Syncer 属于 TiDB 企业版工具集,如何获取可参考下载 TiDB 企业版工具集。Syncer 架构 下载 TiDB 企业版工具集 (Linux) # 下载 tool 压缩包 wget http://download.pingcap.org/tidb-enterprise-tools-latest-linux-amd64.tar.gz wget http://download.pingcap.org/tidb-enterprise-tools-latest-linux-amd64.sha256 # 检查文件完整性,返回 ok 则正确 sha256sum -c tidb-enterprise-tools-latest-linux-amd64.sha256 # 解开压缩包 tar -xzf tidb-enterprise-tools-latest-linux-amd64.tar.gz cd tidb-enterprise-tools-latest-linux-amd64 Syncer 部署位置 Syncer 可以部署在任一台可以连通对应的 MySQL 和 TiDB 集群的机器上,推荐部署在 TiDB 集群。Syncer 增量导入数据示例 使用前请详细阅读 Syncer 同步前预检查设置同步开始的 position 设置 Syncer 的 meta 文件, 这里假设 meta 文件是 syncer.meta:# cat syncer.meta binlog-name = "mysql-bin.000003" binlog-pos = 930143241 binlog-gtid = "2bfabd22-fff7-11e6-97f7-f02fa73bcb01:1-23,61ccbb5d-c82d-11e6-ac2e-487b6bd31bf7:1-4" 注: syncer.meta 只需要第一次使用的时候配置,后续 Syncer 同步新的 binlog 之后会自动将其更新到最新的 position。 如果使用 binlog position 同步则只需要配置 binlog-name binlog-pos; 使用 gtid 同步则需要设置 gtid,且启动 Syncer 时带有 --enable-gtid。 启动 Syncer Syncer 的命令行参数说明:Usage of syncer: -L string 日志等级: debug, info, warn, error, fatal (默认为 "info") -V 输出 syncer 版本;默认 false -auto-fix-gtid 当 mysql master/slave 切换时,自动修复 gtid 信息;默认 false -b int batch 事务大小 (默认 10) -c int syncer 处理 batch 线程数 (默认 16) -config string 指定相应配置文件启动 sycner 服务;如 `--config config.toml` -enable-gtid 使用 gtid 模式启动 syncer;默认 false,开启前需要上游 MySQL 开启 GTID 功能 -log-file string 指定日志文件目录;如 `--log-file ./syncer.log` -log-rotate string 指定日志切割周期, hour/day (默认 "day") -meta string 指定 syncer 上游 meta 信息文件 (默认与配置文件相同目录下 "syncer.meta") -server-id int 指定 MySQL slave sever-id (默认 101) -status-addr string 指定 syncer metric 信息; 如 `--status-addr 127:0.0.1:10088` Syncer 的配置文件 config.toml:log-level = "info" server-id = 101 ## meta 文件地址 meta = "./syncer.meta" worker-count = 16 batch = 10 ## pprof 调试地址, Prometheus 也可以通过该地址拉取 syncer metrics ## 将 127.0.0.1 修改为相应主机 IP 地址 status-addr = "127.0.0.1:10086" # 注意: skip-sqls 已经废弃, 请使用 skip-ddls. # skip-ddls 可以跳过与 TiDB 不兼容的 DDL 语句,支持正则语法。 # skip-ddls = ["^CREATEs+USER"] # 注意: skip-events 已经废弃, 请使用 skip-dmls # skip-dmls 用于跳过 DML 语句. type 字段取值为 'insert', 'update', 'delete'。 # 下面的例子为跳过 foo.bar 表的所有 delete 语句。 # [[skip-dmls]] # db-name = "foo" # tbl-name = "bar" # type = "delete" # # 下面的例子为跳过所有表的 delete 语句。 # [[skip-dmls]] # type = "delete" # # 下面的例子为跳过 foo 库中所有表的 delete 语句。 # [[skip-dmls]] # db-name = "foo" # type = "delete" ## 指定要同步数据库名;支持正则匹配,表达式语句必须以 `~` 开始 #replicate-do-db = ["~^b.*","s1"] ## 指定要同步的 db.table 表 ## db-name 与 tbl-name 不支持 `db-name ="dbname,dbname2"` 格式 #[[replicate-do-table]] #db-name ="dbname" #tbl-name = "table-name" #[[replicate-do-table]] #db-name ="dbname1" #tbl-name = "table-name1" ## 指定要同步的 db.table 表;支持正则匹配,表达式语句必须以 `~` 开始 #[[replicate-do-table]] #db-name ="test" #tbl-name = "~^a.*" ## 指定**忽略**同步数据库;支持正则匹配,表达式语句必须以 `~` 开始 #replicate-ignore-db = ["~^b.*","s1"] ## 指定**忽略**同步数据库 ## db-name & tbl-name 不支持 `db-name ="dbname,dbname2"` 语句格式 #[[replicate-ignore-table]] #db-name = "your_db" #tbl-name = "your_table" ## 指定要**忽略**同步数据库名;支持正则匹配,表达式语句必须以 `~` 开始 #[[replicate-ignore-table]] #db-name ="test" #tbl-name = "~^a.*" # sharding 同步规则,采用 wildcharacter # 1. 星号字符 (*) 可以匹配零个或者多个字符, # 例子, doc* 匹配 doc 和 document, 但是和 dodo 不匹配; # 星号只能放在 pattern 结尾,并且一个 pattern 中只能有一个 # 2. 问号字符 (?) 匹配任一一个字符 #[[route-rules]] #pattern-schema = "route_*" #pattern-table = "abc_*" #target-schema = "route" #target-table = "abc" #[[route-rules]] #pattern-schema = "route_*" #pattern-table = "xyz_*" #target-schema = "route" #target-table = "xyz" [from] host = "127.0.0.1" user = "root" password = "" port = 3306 [to] host = "127.0.0.1" user = "root" password = "" port = 4000 启动 Syncer:./bin/syncer -config config.toml 2016/10/27 15:22:01 binlogsyncer.go:226: [info] begin to sync binlog from position (mysql-bin.000003, 1280) 2016/10/27 15:22:01 binlogsyncer.go:130: [info] register slave for master server 127.0.0.1:3306 2016/10/27 15:22:01 binlogsyncer.go:552: [info] rotate to (mysql-bin.000003, 1280) 2016/10/27 15:22:01 syncer.go:549: [info] rotate binlog to (mysql-bin.000003, 1280) 在 MySQL 中插入新的数据 INSERT INTO t1 VALUES (4, 4), (5, 5); 登录到 TiDB 查看:mysql -h127.0.0.1 -P4000 -uroot -p mysql> select * from t1; +----+------+ | id | age | +----+------+ | 1 | 1 | | 2 | 2 | | 3 | 3 | | 4 | 4 | | 5 | 5 | +----+------+ Syncer 每隔 30s 会输出当前的同步统计,如下所示:2017/06/08 01:18:51 syncer.go:934: [info] [syncer]total events = 15, total tps = 130, recent tps = 4, master-binlog = (ON.000001, 11992), master-binlog-gtid=53ea0ed1-9bf8-11e6-8bea-64006a897c73:1-74, syncer-binlog = (ON.000001, 2504), syncer-binlog-gtid = 53ea0ed1-9bf8-11e6-8bea-64006a897c73:1-17 2017/06/08 01:19:21 syncer.go:934: [info] [syncer]total events = 15, total tps = 191, recent tps = 2, master-binlog = (ON.000001, 11992), master-binlog-gtid=53ea0ed1-9bf8-11e6-8bea-64006a897c73:1-74, syncer-binlog = (ON.000001, 2504), syncer-binlog-gtid = 53ea0ed1-9bf8-11e6-8bea-64006a897c73:1-35 由上述示例可见,使用 Syncer 可以自动将 MySQL 的更新同步到 TiDB。Syncer 配置说明 指定数据库同步 本部分将通过实际案例描述 Syncer 同步数据库参数的优先级关系。 如果使用 route-rules 规则,参考 Sharding 同步支持 优先级:replicate-do-db –> replicate-do-table –> replicate-ignore-db –> replicate-ignore-table # 指定同步 ops 数据库 # 指定同步以 ti 开头的数据库 replicate-do-db = ["ops","~^ti.*"] # china 数据库下有 guangzhou / shanghai / beijing 等多张表,只同步 shanghai 与 beijing 表。 # 指定同步 china 数据库下 shanghai 表 [[replicate-do-table]] db-name ="china" tbl-name = "shanghai" # 指定同步 china 数据库下 beijing 表 [[replicate-do-table]] db-name ="china" tbl-name = "beijing" # ops 数据库下有 ops_user / ops_admin / weekly 等数据表,只需要同步 ops_user 表。 # 因 replicate-do-db 优先级比 replicate-do-table 高,所以此处设置只同步 ops_user 表无效,实际工作会同步 ops 整个数据库 [[replicate-do-table]] db-name ="ops" tbl-name = "ops_user" # history 数据下有 2017_01 2017_02 ... 2017_12 / 2016_01 2016_02 ... 2016_12 等多张表,只需要同步 2017 年的数据表 [[replicate-do-table]] db-name ="history" tbl-name = "~^2017_.*" # 忽略同步 ops 与 fault 数据库 # 忽略同步以 www 开头的数据库 ## 因 replicate-do-db 优先级比 replicate-ignore-db 高,所以此处忽略同步 ops 不生效。 replicate-ignore-db = ["ops","fault","~^www"] # fault 数据库下有 faults / user_feedback / ticket 等数据表 # 忽略同步 user_feedback 数据表 # 因 replicate-ignore-db 优先级比 replicate-ignore-table 高,所以此处设置只同步 user_feedback 表无效,实际工作会同步 fault 整个数据库 [[replicate-ignore-table]] db-name = "fault" tbl-name = "user_feedback" # order 数据下有 2017_01 2017_02 ... 2017_12 / 2016_01 2016_02 ... 2016_12 等多张表,忽略 2016 年的数据表 [[replicate-ignore-table]] db-name ="order" tbl-name = "~^2016_.*" Sharding 同步支持 根据配置文件的 route-rules,支持将分库分表的数据导入到同一个库同一个表中,但是在开始前需要检查分库分表规则,如下: 是否可以利用 route-rules 的语义规则表示 分表中是否包含唯一递增主键,或者合并后是否包含数据上有冲突的唯一索引或者主键 暂时对 DDL 支持不完善。分库分表同步示例 只需在所有 MySQL 实例下面,启动 Syncer, 并设置 route-rules。 replicate-do-db & replicate-ignore-db 与 route-rules 同时使用场景下,replicate-do-db & replicate-ignore-db 需要指定 route-rules 中 target-schema & target-table 的内容。 # 场景如下: # 数据库A 下有 order_2016 / history_2016 等多个数据库 # 数据库B 下有 order_2017 / history_2017 等多个数据库 # 指定同步数据库A order_2016 数据库,数据表如下 2016_01 2016_02 ... 2016_12 # 指定同步数据表B order_2017 数据库,数据表如下 2017_01 2017_02 ... 2017_12 # 表内使用 order_id 作为主键,数据之间主键不冲突 # 忽略同步 history_2016 与 history_2017 数据库 # 目标库需要为 order ,目标数据表为 order_2017 / order_2016 # Syncer 获取到上游数据后,发现 route-rules 规则启用,先做合库合表操作,再进行 do-db & do-table 判定 ## 此处需要设置 target-schema & target-table 判定需要同步的数据库 [[replicate-do-table]] db-name ="order" tbl-name = "order_2016" [[replicate-do-table]] db-name ="order" tbl-name = "order_2017" [[route-rules]] …"}, {"url": "https://pingcap.com/docs/tools/data-migration-practice/", "title": "Synchronize Data Using Data Migration", "content": " Synchronize Data Using Data Migration This guide shows how to synchronize data using the Data Migration (DM) tool.Step 1: Deploy the DM cluster It is recommended to deploy the DM cluster using DM-Ansible. For detailed deployment, see Deploy Data Migration Using DM-Ansible. Notes: For database related passwords in all the DM configuration files, use the passwords encrypted by dmctl. If a database password is empty, it is unnecessary to encrypt it. See Encrypt the upstream MySQL user password using dmctl. The user of the upstream and downstream databases must have the corresponding read and write privileges. Step 2: Check the cluster information After the DM cluster is deployed using DM-Ansible, the configuration information is like what is listed below. The configuration information of related components in the DM cluster: Component IP Service port DM-worker 172.16.10.72 10081 DM-worker 172.16.10.73 10081 DM-master 172.16.10.71 11080 The information of upstream and downstream database instances: Database instance IP Port Username Encrypted password Upstream MySQL-1 172.16.10.81 3306 root VjX8cEeTX+qcvZ3bPaO4h0C80pe/1aU= Upstream MySQL-2 172.16.10.82 3306 root VjX8cEeTX+qcvZ3bPaO4h0C80pe/1aU= Downstream TiDB 172.16.10.83 4000 root The configuration in the DM-master process configuration file {ansible deploy}/conf/dm-master.toml:# Master configuration. [[deploy]] mysql-instance = "172.16.10.81:3306" dm-worker = "172.16.10.72:10081" [[deploy]] mysql-instance = "172.16.10.82:3306" dm-worker = "172.16.10.73:10081" Step 3: Configure the data synchronization task The following example assumes that you need to synchronize all the test_table table data in the test_db database of both the upstream MySQL-1 and MySQL-2 instances, to the downstream test_table table in the test_db database of TiDB, in the full data plus incremental data mode.You can refer to the task.yaml.example task configuration template in {ansible deploy}/conf, and then copy, edit, and generate the task.yaml task configuration file as below:# The task name. You need to use a different name for each of the multiple tasks that # run simultaneously. name: "test" # The full data plus incremental data (all) synchronization mode task-mode: "all" # Disables the heartbeat synchronization delay calculation disable-heartbeat: true # The downstream TiDB configuration information target-database: host: "172.16.10.83" port: 4000 user: "root" password: "" # All the upstream MySQL instances that the current task needs to use mysql-instances: - config: # MySQL-1 configuration host: "172.16.10.81" port: 3306 user: "root" # The ciphertext generated by a certain encryption of the plaintext `123456`. # The ciphertext generated by each encryption is different. password: "VjX8cEeTX+qcvZ3bPaO4h0C80pe/1aU=" # The instance ID of MySQL-1, corresponding to the `mysql-instance` in "dm-master.toml" instance-id: "172.16.10.81:3306" # The configuration item name of the black and white lists of the name of the # database/table to be synchronized, used to quote the global black and white # lists configuration that is set in the global black-white-list map below. black-white-list: "global" # The configuration item name of mydumper, used to quote the global mydumper configuration mydumper-config-name: "global" - config: # MySQL-2 configuration host: "172.16.10.82" port: 3306 user: "root" password: "VjX8cEeTX+qcvZ3bPaO4h0C80pe/1aU=" instance-id: "172.16.10.82:3306" black-white-list: "global" mydumper-config-name: "global" # The global configuration of black and white lists. Each instance can quote it by the # configuration item name. black-white-list: global: do-tables: # The upstream tables to be synchronized - db-name: "test_db" # The database name of the table to be synchronized tbl-name: "test_table" # The name of the table to be synchronized # mydumper global configuration. Each instance can quote it by the configuration item name. mydumpers: global: mydumper-path: "./bin/mydumper" # The file path of the mydumper binary extra-args: "-B test_db -T test_table" # Only dumps the "test_table" table of the "test_db" database Step 4: Start the data synchronization task Come to the dmctl directory /home/tidb/dm-ansible/resource/bin/. Run the following command to start dmctl../dmctl --master-addr 172.16.10.71:11080 Run the following command to start the data synchronization tasks.# `task.yaml` is the configuration file that is edited above. start-task task.yaml If the above command returns the following result, it indicates the task is successfully started.{ "result": true, "msg": "", "workers": [ { "result": true, "worker": "172.16.10.72:10081", "msg": "" }, { "result": true, "worker": "172.16.10.73:10081", "msg": "" } ] } If the above command returns other information, you can edit the configuration according to the prompt, and then run the start-task task.yaml command to restart the task. Step 5: Check the data synchronization task If you need to check the task state or whether a certain data synchronization task is running in the DM cluster, run the following command in the dmctl directory:query-status Step 6: Stop the data synchronization task If you do not need to synchronize data any more, run the following command in the dmctl directory to stop the task:# `test` is the task name that you set in the `name` configuration item of # the `task.yaml` configuration file. stop-task test Step 7: Monitor the task and check logs Assuming that Prometheus and Grafana are successfully deployed along with the DM cluster deployment using DM-Ansible, and the Grafana address is 172.16.10.71, you can open http://172.16.10.71:3000 in a browser, choose the DM dashboard to check the related monitoring metrics.While the DM cluster is running, DM-master, DM-worker, and dmctl output the monitoring metrics information through logs. The log directory of each component is as follows: DM-master log directory: It is specified by the --log-file DM-master process parameter. For DM-Ansible deployment, the log directory is {ansible deploy}/log/dm-master.log in the DM-master node. DM-worker log directory: It is specified by the --log-file DM-worker process parameter. For DM-Ansible deployment, the log directory is {ansible deploy}/log/dm-worker.log in the DM-master node. dmctl log directory: It is the same as the binary directory of dmctl. "}, {"url": "https://pingcap.com/terms-of-service/", "title": "Terms of Service", "content": " Terms of Service Last Updated: October 10, 2018By using PingCAP.com and any of PingCAP’s associated mobile applications and websites (“the Site”), you agree to be bound by these Terms of Service and to use the Site in accordance with these Terms of Service and our Privacy Policy. These Terms of Service constitute a binding legal contract between you and PingCAP and govern your use of the Site.We reserve the right to change these Terms of Service or to impose new conditions on use of the Site, from time to time, in which case we will post the revised Terms of Service on this Site and update the “Last Updated” date to reflect the date of the changes. By continuing to use the Site after we post any such changes, you accept the Terms of Service as modified.License Subject to these Terms of Service, PingCAP grants you a non-transferable, non-exclusive, non-assignable limited license (without right of sub-license) to use the Site. Unless otherwise agreed to in writing, you may not use the Site for commercial purposes. The Site is licensed, not sold, to you under these Terms of Service. You have no ownership rights in, or related to, this Site, any services or functionality provided by the Site or any related documentation. PingCAP retains all right, title, and interest in and to the original, and any copies, of the Site (including any changes, modifications, or corrections thereto) and any related documentation.Rights and Restrictions Relating to Site Content This Site and all the materials available on the Site are the property of us or licensors, and are protected by copyright, trademark, and other intellectual property laws. The Site is provided solely for your personal noncommercial use. You may not use the Site or the materials available on the Site in a manner that constitutes an infringement of our rights or that has not been authorized by us. More specifically, unless explicitly authorized in these Terms of Service or by the owner of the materials, you may not modify, copy, reproduce, republish, upload, post, transmit, translate, sell, create derivative works, exploit, or distribute in any manner or medium (including by email or other electronic means) any material from the Site. You may, however, from time to time, download and/or copy individual pages of the Site for nonproprietary use, provided that you keep intact all copyright and other proprietary notices. For information about requesting permission to reproduce or distribute materials from the Site, please contact us.Site Registration Process To access certain features of our Site, PingCAP may ask you to register on the form provided and such registration may require you to provide personally identifiable information such as your name, telephone number, company, and email address. You agree to provide true, accurate, current and complete information about yourself as prompted by the Site’s registration form. If we have reasonable grounds to suspect that such information is untrue, inaccurate, or incomplete, we may suspend or terminate your account and refuse any and all current or future use of the Site (or any portion thereof). Our use of any personally identifiable information you provide to us as part of the registration process is governed by the terms of our Privacy Policy.Password Disclosure You are prohibited from sharing your username and/or password with any other person, and you are responsible for ensuring that you do not take any actions – or fail to take any actions – that could result in their unauthorized access and use of the Site or the Information. If, at any time, you are issued a username and/or password or other positive identifiers of the user issued and authorized by PingCAP and you learn or suspect that such identifiers have been disclosed or otherwise made known to any person other than yourself, you agree to immediately change your password to prevent unauthorized access to your account.Privacy We respect the privacy of the users of our Site. Our Site Privacy Policy can be viewed here: pingcap.com/privacy-policy.Modifications to, or Discontinuation of, the Site We reserve the right at any time and from time to time to modify or discontinue, temporarily or permanently, the Site, or any portion thereof, with or without notice. You agree that we will not be liable to you or to any third party for any modification, suspension or discontinuance of the Site or any portion thereof.Access to Our Services and Wireless Carrier Charges You acknowledge and agree that you are responsible for obtaining and maintaining all telecommunications, broadband, and computer hardware, equipment, and services needed to access and use the Site, and for paying all charges related thereto. You agree that your use of the Site will be in accordance with all requirements of your wireless carrier, internet service provider and other method of internet access. PingCAP does not control wireless or internet access. Your use of these networks may not be secure and may expose your personal information sent over such networks. While we implement security measures to help safeguard your data, no physical or electronic security system is impenetrable. We cannot guarantee the security of our servers or databases, nor can we guarantee that information you supply will not be intercepted while being transmitted to us over the Internet.Disclaimers The Site may contain links to other websites. Our linking to such third-party sites does not imply an endorsement or sponsorship of such sites, or the information, products or services offered on or through the sites. PingCAP makes no representations and assumes no responsibility for your use of links provided on the Site.THE INFORMATION, PRODUCTS AND SERVICES OFFERED ON OR THROUGH THE SITE AND ANY THIRD-PARTY SITES ARE PROVIDED “AS IS” AND WITHOUT WARRANTIES OF ANY KIND EITHER EXPRESS OR IMPLIED. TO THE FULLEST EXTENT PERMISSIBLE PURSUANT TO SITELICABLE LAW, WE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. WE DO NOT WARRANT THAT THE SITE OR ANY OF ITS FUNCTIONS WILL BE UNINTERRUPTED OR ERROR-FREE, THAT DEFECTS WILL BE CORRECTED, OR THAT ANY PART OF THIS SITE, OR THE SERVERS THAT MAKE IT AVAILABLE, ARE FREE OF VIRUSES OR OTHER HARMFUL COMPONENTS.WE DO NOT WARRANT OR MAKE ANY REPRESENTATIONS REGARDING THE USE OR THE RESULTS OF THE USE OF THE SITE OR MATERIALS ON THIS SITE OR ON THIRD-PARTY SITES IN TERMS OF THEIR CORRECTNESS, ACCURACY, TIMELINESS, RELIABILITY OR OTHERWISE.You must provide and are solely responsible for all hardware and/or software necessary to access the Site. You assume the entire cost of and responsibility for any damage to, and all necessary maintenance, repair or correction of, that hardware and/or software.The Site should not be used in any high risk activities where damage or injury to persons, property, environment, finances or business may result if an error occurs. You expressly assume all risk for such use.Your interactions with companies, organizations and/or individuals found on or through our Site, including any purchases, transactions, or other dealings, and any terms, conditions, warranties or representations associated with such dealings, are solely between you and such companies, organizations and/or individuals. You agree that we will not be responsible or liable for any loss or damage of any sort incurred as the result of any such dealings. You also agree that, if there is a dispute between users of this Site, or between a user and any third party, we are under no obligation to become involved, and you agree to release us and our affiliates from any claims, demands and damages of every kind or nature, known or unknown, suspected and unsuspected, disclosed and undisclosed, arising out of or in any way related to such dispute and/or our Site.Limitation of Liability UNDER NO CIRCUMSTANCES, INCLUDING, BUT …"}, {"url": "https://pingcap.com/tidb-academy/mysql_dbas/query-optimization/coprocessor/", "title": "The Coprocessor", "content": " The Coprocessor Transcript Welcome back. Now that you’ve had a chance to experiment with EXPLAIN, let’s talk about the coprocessor in more detail. For performance reasons, TiDB pushes parts of the query execution down to TiKV for coprocessing. This saves on copying data around which tends to be inefficient. So to revisit our earlier query, we can say that the coprocessor supports the count(*) function:EXPLAIN SELECT count(*) FROM trips WHERE start_date BETWEEN '2017-07-01 00:00:00' AND '2017-07-01 23:59:59'; I am also going to drop the index start_date which was added earlier.The coprocessor supports most of the functions that TiDB does, but for arguments’ sake let’s use a function which is not supported, which is the RAND() function. So I have two queries:EXPLAIN SELECT count(trip_id + RAND()) FROM trips WHERE start_date BETWEEN '2017-07-01 00:00:00' AND '2017-07-01 23:59:59'; EXPLAIN SELECT count(trip_id) FROM trips WHERE start_date BETWEEN '2017-07-01 00:00:00' AND '2017-07-01 23:59:59'; So in EXPLAIN we can see:Without the coprocessor:MySQL [bikeshare]> EXPLAIN SELECT count(trip_id + RAND()) FROM trips WHERE start_date BETWEEN '2017-07-01 00:00:00' AND '2017-07-01 23:59:59'; +------------------------+------------+------+------------------------------------------------------------------------------------------------------------------------+ | id | count | task | operator info | +------------------------+------------+------+------------------------------------------------------------------------------------------------------------------------+ | StreamAgg_9 | 1.00 | root | funcs:count(plus(cast(bikeshare.trips.trip_id), rand())) | | └─TableReader_19 | 6975.66 | root | data:Selection_18 | | └─Selection_18 | 6975.66 | cop | ge(bikeshare.trips.start_date, 2017-07-01 00:00:00.000000), le(bikeshare.trips.start_date, 2017-07-01 23:59:59.000000) | | └─TableScan_17 | 3757777.00 | cop | table:trips, range:[-inf,+inf], keep order:false | +------------------------+------------+------+------------------------------------------------------------------------------------------------------------------------+ 4 rows in set (0.00 sec) With the coprocessor:MySQL [bikeshare]> EXPLAIN SELECT count(trip_id) FROM trips WHERE start_date BETWEEN '2017-07-01 00:00:00' AND '2017-07-01 23:59:59'; +--------------------------+------------+------+------------------------------------------------------------------------------------------------------------------------+ | id | count | task | operator info | +--------------------------+------------+------+------------------------------------------------------------------------------------------------------------------------+ | StreamAgg_20 | 1.00 | root | funcs:count(col_0) | | └─TableReader_21 | 1.00 | root | data:StreamAgg_9 | | └─StreamAgg_9 | 1.00 | cop | funcs:count(bikeshare.trips.trip_id) | | └─Selection_19 | 6975.66 | cop | ge(bikeshare.trips.start_date, 2017-07-01 00:00:00.000000), le(bikeshare.trips.start_date, 2017-07-01 23:59:59.000000) | | └─TableScan_18 | 3757777.00 | cop | table:trips, range:[-inf,+inf], keep order:false | +--------------------------+------------+------+------------------------------------------------------------------------------------------------------------------------+ 5 rows in set (0.01 sec) Between TiKV and TiDB the data is efficiently encoded in protocol buffers, and the communication layer is based on gRPC, which is also efficient… but in the no-coprocessor case, 8708 rows need to be copied back to TiDB for processing versus one with the coprocessor. On a reference system, this changes query execution time from 3.33 seconds to 3.28 seconds. It’s not significant yet, largely because without the index most of the time is spent scanning the table in TiKV.Let’s now try a second example, which is the performance with the start_date column indexed. I would call this example more typical in that in a production environment you try to avoid tablescans on large amounts of data, and add suitable indexes:mysql> ALTER TABLE trips ADD INDEX (start_date); Without the coprocessor:mysql> EXPLAIN SELECT count(trip_id + RAND()) FROM trips WHERE start_date BETWEEN '2017-07-01 00:00:00' AND '2017-07-01 23:59:59'; +----------------------+---------+------+--------------------------------------------------------------------------------------------------+ | id | count | task | operator info | +----------------------+---------+------+--------------------------------------------------------------------------------------------------+ | StreamAgg_9 | 1.00 | root | funcs:count(plus(cast(bikeshare.trips.trip_id), rand())) | | └─IndexReader_24 | 8708.34 | root | index:IndexScan_23 | | └─IndexScan_23 | 8708.34 | cop | table:trips, index:start_date, range:[2017-07-01 00:00:00,2017-07-01 23:59:59], keep order:false | +----------------------+---------+------+--------------------------------------------------------------------------------------------------+ 3 rows in set (0.00 sec) With the coprocessor:mysql> EXPLAIN SELECT count(trip_id) FROM trips WHERE start_date BETWEEN '2017-07-01 00:00:00' AND '2017-07-01 23:59:59'; +------------------------+---------+------+--------------------------------------------------------------------------------------------------+ | id | count | task | operator info | +------------------------+---------+------+--------------------------------------------------------------------------------------------------+ | StreamAgg_25 | 1.00 | root | funcs:count(col_0) | | └─IndexReader_26 | 1.00 | root | index:StreamAgg_9 | | └─StreamAgg_9 | 1.00 | cop | funcs:count(bikeshare.trips.trip_id) | | └─IndexScan_24 | 8708.34 | cop | table:trips, index:start_date, range:[2017-07-01 00:00:00,2017-07-01 23:59:59], keep order:false | +------------------------+---------+------+--------------------------------------------------------------------------------------------------+ 4 rows in set (0.00 sec) Without: 0.04 sec With: 0.02 secHere we can see an even larger difference in time execution (by percentage). The same 8708 rows need to be copied to TiDB, but the table scan time has efficiently been removed from TiKV’s processing.Another way to look at this, is the efficiency of a distributed system such as the TiDB Platform benefits from the same principles as edge computing, which is to push key parts of the processing closer to the data. If you see a low count of rows for root tasks, as we can see in our coprocessor examples here, then congratulations! This query is working well."}, {"url": "https://pingcap.com/tidb-academy/mysql_dbas/tidb-overview/the-kost-stack/", "title": "The KOST Stack", "content": " The KOST Stack Transcript In MySQL, you have the LAMP stack. With MongoDB there is the MEAN stack. So what is the KOST Stack?Because the TiDB Platform uses a component based architecture, we have some choices as to how we deploy it. KOST is an infrastructure pattern which consists of Kubernetes, Operator, Spark, and TiDB. We have already introduced the last two letters, so in this video I’m going to introduce Kubernetes and Operator: Kubernetes is a container orchestration system that allows you to automate the deployment and management of containerized applications. An Operator is designed to automate certain operations on a Kubernetes cluster. This pattern was first developed by the fine folks at CoreOS. It’s often used to ensure fault tolerance. For TiDB, our operator implementation checks cluster health, ensures that Kubernetes is scheduling containers appropriately and also assists in software upgrades. By being an orchestration system, it means that Kubernetes can help us setup all of the TiDB components in one step, removing the complexity that can come with distributed systems. The configuration system that works with Kubernetes to deploy many components is called Helm. PingCAP offers Helm charts for TiDB Operator, which is what we are going to be using for this course.We will also be using Kubernetes+Operator to practice scaling our TiDB platform by increasing the number of TiDB and TiKV nodes.Don’t worry if some of this sounds like new terminology. We will be going through a tutorial to set everything up in just a second."}, {"url": "https://pingcap.com/docs/v1.0/sql/tidb-specific/", "title": "The Proprietary System Variables and Syntaxes in TiDB", "content": " The Proprietary System Variables and Syntaxes in TiDB On the basis of MySQL variables and syntaxes, TiDB has defined some specific system variables and syntaxes to optimize performance.System variable Variables can be set with the SET statement, for example:set @@tidb_distsql_scan_concurrency = 10 If you need to set the global variable, run:set @@global.tidb_distsql_scan_concurrency = 10 tidb_distsql_scan_concurrency Scope: SESSION | GLOBAL Default value: 10 This variable is used to set the concurrency of the scan operation. Use a bigger value in OLAP scenarios, and a smaller value in OLTP scenarios. For OLAP scenarios, the maximum value cannot exceed the number of CPU cores of all the TiKV nodes.tidb_index_lookup_size Scope: SESSION | GLOBAL Default value: 20000 This variable is used to set the batch size of index lookup operation. Use a bigger value in OLAP scenarios, and a smaller value in OLTP scenarios.tidb_index_lookup_concurrency Scope: SESSION | GLOBAL Default value: 4 This variable is used to set the concurrency of the index lookup operation. Use a bigger value in OLAP scenarios, and a smaller value in OLTP scenarios.tidb_index_serial_scan_concurrency Scope: SESSION | GLOBAL Default value: 1 This variable is used to set the concurrency of the serial scan operation. Use a bigger value in OLAP scenarios, and a smaller value in OLTP scenarios.Optimizer hint On the basis of MySQL’s Optimizer Hint Syntax, TiDB adds some proprietary Hint syntaxes. When using the Hint syntax, the TiDB optimizer will try to use the specific algorithm, which performs better than the default algorithm in some scenarios.The Hint syntax is included in comments like /*+ xxx */, and in MySQL client versions earlier than 5.7.7, the comment is removed by default. If you want to use the Hint syntax in these earlier versions, add the --comments option when starting the client. For example: mysql -h 127.0.0.1 -P 4000 -uroot --comments.TIDB_SMJ(t1, t2) SELECT /*+ TIDB_SMJ(t1, t2) */ * from t1,t2 where t1.id = t2.id This variable is used to remind the optimizer to use the Sort Merge Join algorithm. This algorithm takes up less memory, but takes longer to execute. It is recommended if the data size is too large, or there’s insufficient system memory.TIDB_INLJ(t1, t2) SELECT /*+ TIDB_INLJ(t1, t2) */ * from t1,t2 where t1.id = t2.id This variable is used to remind the optimizer to use the Index Nested Loop Join algorithm. In some scenarios, this algorithm runs faster and takes up fewer system resources, but may be slower and takes up more system resources in some other scenarios. You can try to use this algorithm in scenarios where the result-set is less than 10,000 rows after the outer table is filtered by the WHERE condition. The parameter in TIDB_INLJ() is the candidate table for the driving table (external table) when generating the query plan. That means, TIDB_INLJ (t1) will only consider using t1 as the driving table to create a query plan."}, {"url": "https://pingcap.com/docs/v2.0/sql/tidb-specific/", "title": "The Proprietary System Variables and Syntaxes in TiDB", "content": " The Proprietary System Variables and Syntaxes in TiDB On the basis of MySQL variables and syntaxes, TiDB has defined some specific system variables and syntaxes to optimize performance.System variable Variables can be set with the SET statement, for example:set @@tidb_distsql_scan_concurrency = 10 If you need to set the global variable, run:set @@global.tidb_distsql_scan_concurrency = 10 tidb_snapshot Scope: SESSION Default value: “” This variable is used to set the time point at which the data is read by the session. For example, when you set the variable to “2017-11-11 20:20:20” or a TSO number like “400036290571534337”, the current session reads the data of this moment. tidb_import_data Scope: SESSION Default value: 0 This variable indicates whether to import data from the dump file currently. To speed up importing, the unique index constraint is not checked when the variable is set to 1. This variable is only used by Lightning. Do not modify it. tidb_opt_agg_push_down Scope: SESSION Default value: 0 This variable is used to set whether the optimizer executes the optimization operation of pushing down the aggregate function to the position before Join. When the aggregate operation is slow in query, you can set the variable value to 1. tidb_opt_insubquery_unfold Scope: SESSION Default value: 0 This variable is used to set whether the optimizer executes the optimization operation of unfolding the “in-” subquery. tidb_build_stats_concurrency Scope: SESSION Default value: 4 This variable is used to set the concurrency of executing the ANALYZE statement. When the variable is set to a larger value, the execution performance of other queries is affected. tidb_checksum_table_concurrency Scope: SESSION Default value: 4 This variable is used to set the scan index concurrency of executing the ADMIN CHECKSUM TABLE statement. When the variable is set to a larger value, the execution performance of other queries is affected. tidb_current_ts Scope: SESSION Default value: 0 This variable is read-only. It is used to obtain the timestamp of the current transaction. tidb_config Scope: SESSION Default value: “” This variable is read-only. It is used to obtain the configuration information of the current TiDB server. tidb_distsql_scan_concurrency Scope: SESSION | GLOBAL Default value: 15 This variable is used to set the concurrency of the scan operation. Use a bigger value in OLAP scenarios, and a smaller value in OLTP scenarios. For OLAP scenarios, the maximum value cannot exceed the number of CPU cores of all the TiKV nodes. tidb_index_lookup_size Scope: SESSION | GLOBAL Default value: 20000 This variable is used to set the batch size of the index lookup operation. Use a bigger value in OLAP scenarios, and a smaller value in OLTP scenarios. tidb_index_lookup_concurrency Scope: SESSION | GLOBAL Default value: 4 This variable is used to set the concurrency of the index lookup operation. Use a bigger value in OLAP scenarios, and a smaller value in OLTP scenarios. tidb_index_lookup_join_concurrency Scope: SESSION | GLOBAL Default value: 4 This variable is used to set the concurrency of the index lookup join algorithm. tidb_hash_join_concurrency Scope: SESSION | GLOBAL Default value: 5 This variable is used to set the concurrency of the hash join algorithm. tidb_index_serial_scan_concurrency Scope: SESSION | GLOBAL Default value: 1 This variable is used to set the concurrency of the serial scan operation. Use a bigger value in OLAP scenarios, and a smaller value in OLTP scenarios. tidb_projection_concurrency Scope: SESSION | GLOBAL Default value: 4 This variable is used to set the concurrency of the Projection operator. tidb_hashagg_partial_concurrency Scope: SESSION | GLOBAL Default value: 4 This variable is used to set the concurrency of executing the concurrent hash aggregation algorithm in the partial phase. When the parameter of the aggregate function is not distinct, HashAgg is run concurrently and respectively in two phases - the partial phase and the final phase. tidb_hashagg_final_concurrency Scope: SESSION | GLOBAL Default value: 4 This variable is used to set the concurrency of executing the concurrent hash aggregation algorithm in the final phase. When the parameter of the aggregate function is not distinct, HashAgg is run concurrently and respectively in two phases - the partial phase and the final phase. tidb_index_join_batch_size Scope: SESSION | GLOBAL Default value: 25000 This variable is used to set the batch size of the index lookup join operation. Use a bigger value in OLAP scenarios, and a smaller value in OLTP scenarios. tidb_skip_utf8_check Scope: SESSION | GLOBAL Default value: 0 This variable is used to set whether to skip UTF-8 validation. Validating UTF-8 characters affects the performance. When you are sure that the input characters are valid UTF-8 characters, you can set the variable value to 1. tidb_batch_insert Scope: SESSION Default value: 0 This variable is used to set whether to divide the inserted data automatically. It is valid only when autocommit is enabled. When inserting a large amount of data, you can set the variable value to true. Then the inserted data is automatically divided into multiple batches and each batch is inserted by a single transaction. tidb_batch_delete Scope: SESSION Default value: 0 This variable is used to set whether to divide the data for deletion automatically. It is valid only when autocommit is enabled. When deleting a large amount of data, you can set the variable value to true. Then the data for deletion is automatically divided into multiple batches and each batch is deleted by a single transaction. tidb_dml_batch_size Scope: SESSION Default value: 20000 This variable is used to set the automatically divided batch size of the data for insertion/deletion. It is only valid when tidb_batch_insert or tidb_batch_delete is enabled. When the data size of a single row is very large, the overall data size of 20 thousand rows exceeds the size limit for a single transaction. In this case, set the variable to a smaller value. tidb_max_chunk_size Scope: SESSION | GLOBAL Default value: 1024 This variable is used to set the maximum number of rows in a chunk during the execution process. tidb_mem_quota_query Scope: SESSION Default value: 32 GB This variable is used to set the threshold value of memory quota for a query. If the memory quota of a query during execution exceeds the threshold value, TiDB performs the operation designated by the OOMAction option in the configuration file. tidb_mem_quota_hashjoin Scope: SESSION Default value: 32 GB This variable is used to set the threshold value of memory quota for the HashJoin operator. If the memory quota of the HashJoin operator during execution exceeds the threshold value, TiDB performs the operation designated by the OOMAction option in the configuration file. tidb_mem_quota_mergejoin Scope: SESSION Default value: 32 GB This variable is used to set the threshold value of memory quota for the MergeJoin operator. If the memory quota of the MergeJoin operator during execution exceeds the threshold value, TiDB performs the operation designated by the OOMAction option in the configuration file. tidb_mem_quota_sort Scope: SESSION Default value: 32 GB This variable is used to set the threshold value of memory quota for the Sort operator. If the memory quota of the Sort operator during execution exceeds the threshold value, TiDB performs the operation designated by the OOMAction option in the configuration file. tidb_mem_quota_topn Scope: SESSION Default value: 32 GB This variable is used to set the threshold value of memory quota for the TopN operator. If the memory quota of the TopN operator during execution exceeds the threshold value, TiDB performs the operation designated by the OOMAction option in the configuration file. tidb_mem_quota_indexlookupreader …"}, {"url": "https://pingcap.com/docs/sql/variable/", "title": "The System Variables", "content": " The System Variables The system variables in MySQL are the system parameters that modify the operation of the database runtime. These variables have two types of scope, Global Scope and Session Scope. TiDB supports all the system variables in MySQL 5.7. Most of the variables are only supported for compatibility and do not affect the runtime behaviors.Set the system variables You can use the SET statement to change the value of the system variables. Before you change, consider the scope of the variable. For more information, see MySQL Dynamic System Variables.Set Global variables Add the GLOBAL keyword before the variable or use @@global. as the modifier:SET GLOBAL autocommit = 1; SET @@global.autocommit = 1; Set Session Variables Add the SESSION keyword before the variable, use @@session. as the modifier, or use no modifier:SET SESSION autocommit = 1; SET @@session.autocommit = 1; SET @@autocommit = 1; Note: LOCAL and @@local. are the synonyms for SESSION and @@session. The fully supported MySQL system variables in TiDB The following MySQL system variables are fully supported in TiDB and have the same behaviors as in MySQL. Name Scope Description autocommit GLOBAL | SESSION whether automatically commit a transaction sql_mode GLOBAL | SESSION support some of the MySQL SQL modes time_zone GLOBAL | SESSION the time zone of the database tx_isolation GLOBAL | SESSION the isolation level of a transaction hostname NONE the hostname of the TiDB server TiDB Specific System Variables See TiDB Specific System Variables."}, {"url": "https://pingcap.com/docs/v1.0/sql/variable/", "title": "The System Variables", "content": " The System Variables The system variables in MySQL are the system parameters that modify the operation of the database runtime. These variables have two types of scope, Global Scope and Session Scope. TiDB supports all the system variables in MySQL 5.7. Most of the variables are only supported for compatibility and do not affect the runtime behaviors.Set the system variables You can use the SET statement to change the value of the system variables. Before you change, consider the scope of the variable. For more information, see MySQL Dynamic System Variables.Set Global variables Add the GLOBAL keyword before the variable or use @@global. as the modifier:SET GLOBAL autocommit = 1; SET @@global.autocommit = 1; Set Session Variables Add the SESSION keyword before the variable, use @@session. as the modifier, or use no modifier:SET SESSION autocommit = 1; SET @@session.autocommit = 1; SET @@autocommit = 1; Note: LOCAL and @@local. are the synonyms for SESSION and @@session. The fully supported MySQL system variables in TiDB The following MySQL system variables are fully supported in TiDB and have the same behaviors as in MySQL. Name Scope Description autocommit GLOBAL | SESSION whether automatically commit a transaction sql_mode GLOBAL | SESSION support some of the MySQL SQL modes time_zone GLOBAL | SESSION the time zone of the database tx_isolation GLOBAL | SESSION the isolation level of a transaction The proprietary system variables and syntaxes in TiDB See The Proprietary System Variables and Syntax in TiDB."}, {"url": "https://pingcap.com/docs/v2.0/sql/variable/", "title": "The System Variables", "content": " The System Variables The system variables in MySQL are the system parameters that modify the operation of the database runtime. These variables have two types of scope, Global Scope and Session Scope. TiDB supports all the system variables in MySQL 5.7. Most of the variables are only supported for compatibility and do not affect the runtime behaviors.Set the system variables You can use the SET statement to change the value of the system variables. Before you change, consider the scope of the variable. For more information, see MySQL Dynamic System Variables.Set Global variables Add the GLOBAL keyword before the variable or use @@global. as the modifier:SET GLOBAL autocommit = 1; SET @@global.autocommit = 1; Set Session Variables Add the SESSION keyword before the variable, use @@session. as the modifier, or use no modifier:SET SESSION autocommit = 1; SET @@session.autocommit = 1; SET @@autocommit = 1; Note: LOCAL and @@local. are the synonyms for SESSION and @@session. The fully supported MySQL system variables in TiDB The following MySQL system variables are fully supported in TiDB and have the same behaviors as in MySQL. Name Scope Description autocommit GLOBAL | SESSION whether automatically commit a transaction sql_mode GLOBAL | SESSION support some of the MySQL SQL modes time_zone GLOBAL | SESSION the time zone of the database tx_isolation GLOBAL | SESSION the isolation level of a transaction The proprietary system variables and syntaxes in TiDB See The Proprietary System Variables and Syntax in TiDB."}, {"url": "https://pingcap.com/docs/sql/server-command-option/", "title": "The TiDB Command Options", "content": " The TiDB Command Options This document describes the startup options and TiDB server configuration files.TiDB startup options When you start TiDB processes, you can specify some program options.TiDB supports a lot of startup options. Run the following command to get a brief introduction:./tidb-server --help Run the following command to get the version:./tidb-server -V The complete descriptions of startup options are as follows.-L Log level Default: “info” Optional values: debug, info, warn, error or fatal -P TiDB service monitor port Default: “4000” TiDB uses this port to accept requests from the MySQL client --binlog-socket TiDB uses the unix socket file to accept the internal connection, such as the PUMP service. Default: “” For example, use “/tmp/pump.sock” to accept the PUMP unix socket file communication. --config TiDB configuration files Default: “” The file path of the configuration files --lease The lease time of schema; unit: second Default: “10” The lease of schema is mainly used in online schema changes. This value affects the actual execution time of the DDL statement. In most cases, you do not need to change this value unless you clearly understand the internal implementation mechanism of TiDB DDL. --host TiDB service monitor host Default: “0.0.0.0” TiDB service monitors this host. The 0.0.0.0 port monitors the address of all network cards. You can specify the network card that provides external service, such as 192.168.100.113. --log-file Log file Default: “” If the option is not set, the log is output to “stderr”; if set, the log is output to the corresponding file. In the small hours of every day, the log automatically rotates to use a new file, renames and backups the previous file. --metrics-addr The address of Prometheus Push Gateway Default: “” If the option value is null, TiDB does not push the statistics to Push Gateway. The option format is like --metrics-addr=192.168.100.115:9091. --metrics-intervel The time interval that the statistics are pushed to Prometheus Push Gateway Default: 15s If you set the option value to 0, the statistics are not pushed to Push Gateway. --metrics-interval=2 means the statistics are pushed to Push Gateway every two seconds. --path For the local storage engines such as “goleveldb” or “BoltDB”, path specifies the actual data storage path. For the “memory” storage engine, it is not necessary to set path. For the “TiKV” storage engine, path specifies the actual PD address. For example, if the PD is deployed on 192.168.100.113:2379, 192.168.100.114:2379 and 192.168.100.115:2379, the path is “192.168.100.113:2379, 192.168.100.114:2379, 192.168.100.115:2379”. --report-status Enable (true) or disable (false) the status monitor port Default: true The value is either true or false. The true value means opening the status monitor port. The false value means closing the status monitor port. The status monitor port is used to report some internal service information to the external. --run-ddl Whether the TiDB server runs DDL statements; set the option when more than two TiDB servers are in the cluster Default: true The value is either true or false. The true value means the TiDB server runs DDL statements. The false value means the TiDB server does not run DDL statements. --socket string TiDB uses the unix socket file to accept the external connection. Default: “” For example, use “/tmp/tidb.sock” to open the unix socket file. --status The status monitor port of TiDB Default: “10080” This port is used to display the internal data of TiDB, including the Prometheus statistics and pprof. Access the Prometheus statistics at http://host:status_port/metrics. Access the pprof data at http://host:status_port/debug/pprof. --store To specify the storage engine used by the bottom layer of TiDB Default: “mocktikv” Optional values: “memory”, “goleveldb”, “boltdb”, “mocktikv” or “tikv” (TiKV is a distributed storage engine, while the others are local storage engines) For example, use tidb-server --store=memory to start a TiDB server with a pure memory engine TiDB server configuration files When you start the TiDB server, you can specify the server’s configuration file using --config path. For overlapped options in configuration, the priority of command options is higher than configuration files.See an example of the configuration file.The complete descriptions of startup options are as follows.host Same as the “host” startup optionport Same as the “P” startup optionpath Same as the “path” startup optionsocket Same as the “socket” startup optionbinlog-socket Same as the “binlog-socket” startup optionrun-ddl Same as the “run-ddl” startup optioncross-join Default: true When you execute join on tables without any conditions on both sides, the statement can be run by default. But if you set the value to false, the server does not run such join statement. force-priority The default priority for statements Default: NO_PRIORITY TiDB supports the priorities NO_PRIORITY | LOW_PRIORITY | DELAYED | HIGH_PRIORITY for statements. One use case for changing the priority, is you may choose to dedicate a pool of servers for OLAP queries and set the value to LOW_PRIORITY to ensure that TiKV servers will provide priority to OLTP workloads which are routed to a different pool of TiDB servers. This helps ensure more uniform OLTP performance at the risk of slightly slower OLAP performance. TiDB will automatically set table scans to LOW_PRIORITY and overwriting priority on a per-statement basis is possible by using the HIGH PRIORITY or LOW PRIORITY DML modifier.join-concurrency The goroutine number when the join-concurrency runs join Default: 5 To view the amount of data and data distribution; generally the more the better; a larger value indicates a larger CPU is needed query-log-max-len To record the maximum length of SQL statements in the log Default: 2048 The overlong request is truncated when it is output to the log slow-threshold int To record the SQL statement that has a larger value than this option Default: 300 It is required that the value is an integer (int); unit: millisecond slow-query-file The slow query log file Default: “” The value is the file name. If a non-null string is specified, the slow query log is redirected to the corresponding file. retry-limit The maximum number of commit retries when the transaction meets a conflict Default: 10 Setting a large number of retries can affect the performance of the TiDB cluster skip-grant-table Allow anyone to connect without a password, and all operations do not check privileges Default: false The value is either true or false. The machine’s root privilege is required to enable this option, which is used to reset the password when forgotten. stats-lease Scan the full table incrementally, and analyze the data amount and indexes of the table Default: “3s” To use this option, you need to manually run analyze table name. Update the statistics automatically and store data in TiKV persistently, taking up some memory. tcp-keep-alive To Enable keepalive in the tcp layer of TiDB Default: false ssl-cert The file path of SSL certificate in PEM format Default: “” If this option and the --ssl-key option are set at the same time, the client can (not required) securely connect to TiDB using TLS. If the specified certificate or private key is invalid, TiDB starts as usual but does not support encrypted connections. ssl-key The file path of SSL certificate keys in PEM format, or the private keys specified by --ssl-cert Default: “” …"}, {"url": "https://pingcap.com/docs/v1.0/sql/server-command-option/", "title": "The TiDB Command Options", "content": " The TiDB Command Options TiDB startup options When you star TiDB processes, you can specify some program options.TiDB supports a lot of startup options. Run the following command to get a brief introduction:./tidb-server --help Run the following command to get the version:./tidb-server -V The complete descriptions of startup options are as follows.-L Log level Default: “info” Optional values: debug, info, warn, error or fatal -P TiDB service monitor port Default: “4000” TiDB uses this port to accept requests from the MySQL client --binlog-socket TiDB uses the unix socket file to accept the internal connection, such as the PUMP service. Default: “” For example, use “/tmp/pump.sock” to accept the PUMP unix socket file communication. --config TiDB configuration files Default: “” The file path of the configuration files --lease The lease time of schema; unit: second Default: “10” The lease of schema is mainly used in online schema changes. This value affects the actual execution time of the DDL statement. In most cases, you do not need to change this value unless you clearly understand the internal implementation mechanism of TiDB DDL. --host TiDB service monitor host Default: “0.0.0.0” TiDB service monitors this host. The 0.0.0.0 port monitors the address of all network cards. You can specify the network card that provides external service, such as 192.168.100.113. --log-file Log file Default: “” If the option is not set, the log is output to “stderr”; if set, the log is output to the corresponding file. In the small hours of every day, the log automatically rotates to use a new file, renames and backups the previous file. --metrics-addr The address of Prometheus Push Gateway Default: “” If the option value is null, TiDB does not push the statistics to Push Gateway. The option format is like --metrics-addr=192.168.100.115:9091. --metrics-intervel The time interval that the statistics are pushed to Prometheus Push Gateway Default: 15s If you set the option value to 0, the statistics are not pushed to Push Gateway. --metrics-interval=2 means the statistics are pushed to Push Gateway every two seconds. --path For the local storage engines such as “goleveldb” or “BoltDB”, path specifies the actual data storage path. For the “memory” storage engine, it is not necessary to set path. For the “TiKV” storage engine, path specifies the actual PD address. For example, if the PD is deployed on 192.168.100.113:2379, 192.168.100.114:2379 and 192.168.100.115:2379, the path is “192.168.100.113:2379, 192.168.100.114:2379, 192.168.100.115:2379”. --report-status Enable (true) or disable (false) the status monitor port Default: true The value is either true or false. The true value means opening the status monitor port. The false value means closing the status monitor port. The status monitor port is used to report some internal service information to the external. --run-ddl Whether the TiDB server runs DDL statements; set the option when more than two TiDB servers are in the cluster Default: true The value is either true or false. The true value means the TiDB server runs DDL statements. The false value means the TiDB server does not run DDL statements. --socket string TiDB uses the unix socket file to accept the external connection. Default: “” For example, use “/tmp/tidb.sock” to open the unix socket file. --status The status monitor port of TiDB Default: “10080” This port is used to display the internal data of TiDB, including the Prometheus statistics and pprof. Access the Prometheus statistics at http://host:status_port/metrics. Access the pprof data at http://host:status_port/debug/pprof. --store To specify the storage engine used by the bottom layer of TiDB Default: “mocktikv” Optional values: “memory”, “goleveldb”, “boltdb”, “mocktikv” or “tikv” (TiKV is a distributed storage engine, while the others are local storage engines) For example, use tidb-server --store=memory to start a TiDB server with a pure memory engine TiDB server configuration files When you start the TiDB server, you can specify the server’s configuration file using --config path. For overlapped options in configuration, the priority of command options is higher than configuration files.See an example of the configuration file.The complete descriptions of startup options are as follows.host Same as the “host” startup optionport Same as the “P” startup optionpath Same as the “path” startup optionsocket Same as the “socket” startup optionbinlog-socket Same as the “binlog-socket” startup optionrun-ddl Same as the “run-ddl” startup optioncross-join Default: true When you execute join on tables without any conditions on both sides, the statement can be run by default. But if you set the value to false, the server does not run such join statement. join-concurrency The goroutine number when the join-concurrency runs join Default: 5 To view the amount of data and data distribution; generally the more the better; a larger value indicates a larger CPU is needed query-log-max-len To record the maximum length of SQL statements in the log Default: 2048 The overlong request is truncated when it is output to the log slow-threshold int To record the SQL statement that has a larger value than this option Default: 300 It is required that the value is an integer (int); unit: millisecond slow-query-file The slow query log file Default: “” The value is the file name. If a non-null string is specified, the slow query log is redirected to the corresponding file. retry-limit The maximum number of commit retries when the transaction meets a conflict Default: 10 Setting a large number of retries can affect the performance of the TiDB cluster skip-grant-table Allow anyone to connect without a password, and all operations do not check privileges Default: false The value is either true or false. The machine’s root privilege is required to enable this option, which is used to reset the password when forgotten. stats-lease Scan the full table incrementally, and analyze the data amount and indexes of the table Default: “3s” To use this option, you need to manually run analyze table name. Update the statistics automatically and store data in TiKV persistently, taking up some memory. tcp-keep-alive To Enable keepalive in the tcp layer of TiDB Default: false ssl-cert The file path of SSL certificate in PEM format Default: “” If this option and the --ssl-key option are set at the same time, the client can (not required) securely connect to TiDB using TLS. If the specified certificate or private key is invalid, TiDB starts as usual but does not support encrypted connections. ssl-key The file path of SSL certificate keys in PEM format, or the private keys specified by --ssl-cert Default: “” Currently, you cannot load a password-protected private key in TiDB. ssl-ca The file path of the trusted CA certificate in PEM format Default: “” If this option and the --ssl-cert, --ssl-key options are set at the same time, TiDB authenticates the client certificate based on the trusted CA list specified by the option when the client presents the certificate. If the authentication fails, the connection stops. If this option is set but the client does not present the certificate, the encrypted connection continues but the client certificate is not authenticated. "}, {"url": "https://pingcap.com/docs/v2.0/sql/server-command-option/", "title": "The TiDB Command Options", "content": " The TiDB Command Options This document describes the startup options and TiDB server configuration files.TiDB startup options When you start TiDB processes, you can specify some program options.TiDB supports a lot of startup options. Run the following command to get a brief introduction:./tidb-server --help Run the following command to get the version:./tidb-server -V The complete descriptions of startup options are as follows.-L Log level Default: “info” Optional values: debug, info, warn, error or fatal -P TiDB service monitor port Default: “4000” TiDB uses this port to accept requests from the MySQL client --binlog-socket TiDB uses the unix socket file to accept the internal connection, such as the PUMP service. Default: “” For example, use “/tmp/pump.sock” to accept the PUMP unix socket file communication. --config TiDB configuration files Default: “” The file path of the configuration files --lease The lease time of schema; unit: second Default: “10” The lease of schema is mainly used in online schema changes. This value affects the actual execution time of the DDL statement. In most cases, you do not need to change this value unless you clearly understand the internal implementation mechanism of TiDB DDL. --host TiDB service monitor host Default: “0.0.0.0” TiDB service monitors this host. The 0.0.0.0 port monitors the address of all network cards. You can specify the network card that provides external service, such as 192.168.100.113. --log-file Log file Default: “” If the option is not set, the log is output to “stderr”; if set, the log is output to the corresponding file. In the small hours of every day, the log automatically rotates to use a new file, renames and backups the previous file. --metrics-addr The address of Prometheus Push Gateway Default: “” If the option value is null, TiDB does not push the statistics to Push Gateway. The option format is like --metrics-addr=192.168.100.115:9091. --metrics-intervel The time interval that the statistics are pushed to Prometheus Push Gateway Default: 15s If you set the option value to 0, the statistics are not pushed to Push Gateway. --metrics-interval=2 means the statistics are pushed to Push Gateway every two seconds. --path For the local storage engines such as “goleveldb” or “BoltDB”, path specifies the actual data storage path. For the “memory” storage engine, it is not necessary to set path. For the “TiKV” storage engine, path specifies the actual PD address. For example, if the PD is deployed on 192.168.100.113:2379, 192.168.100.114:2379 and 192.168.100.115:2379, the path is “192.168.100.113:2379, 192.168.100.114:2379, 192.168.100.115:2379”. --report-status Enable (true) or disable (false) the status monitor port Default: true The value is either true or false. The true value means opening the status monitor port. The false value means closing the status monitor port. The status monitor port is used to report some internal service information to the external. --run-ddl Whether the TiDB server runs DDL statements; set the option when more than two TiDB servers are in the cluster Default: true The value is either true or false. The true value means the TiDB server runs DDL statements. The false value means the TiDB server does not run DDL statements. --socket string TiDB uses the unix socket file to accept the external connection. Default: “” For example, use “/tmp/tidb.sock” to open the unix socket file. --status The status monitor port of TiDB Default: “10080” This port is used to display the internal data of TiDB, including the Prometheus statistics and pprof. Access the Prometheus statistics at http://host:status_port/metrics. Access the pprof data at http://host:status_port/debug/pprof. --store To specify the storage engine used by the bottom layer of TiDB Default: “mocktikv” Optional values: “memory”, “goleveldb”, “boltdb”, “mocktikv” or “tikv” (TiKV is a distributed storage engine, while the others are local storage engines) For example, use tidb-server --store=memory to start a TiDB server with a pure memory engine TiDB server configuration files When you start the TiDB server, you can specify the server’s configuration file using --config path. For overlapped options in configuration, the priority of command options is higher than configuration files.See an example of the configuration file.The complete descriptions of startup options are as follows.host Same as the “host” startup optionport Same as the “P” startup optionpath Same as the “path” startup optionsocket Same as the “socket” startup optionbinlog-socket Same as the “binlog-socket” startup optionrun-ddl Same as the “run-ddl” startup optioncross-join Default: true When you execute join on tables without any conditions on both sides, the statement can be run by default. But if you set the value to false, the server does not run such join statement. join-concurrency The goroutine number when the join-concurrency runs join Default: 5 To view the amount of data and data distribution; generally the more the better; a larger value indicates a larger CPU is needed query-log-max-len To record the maximum length of SQL statements in the log Default: 2048 The overlong request is truncated when it is output to the log slow-threshold int To record the SQL statement that has a larger value than this option Default: 300 It is required that the value is an integer (int); unit: millisecond slow-query-file The slow query log file Default: “” The value is the file name. If a non-null string is specified, the slow query log is redirected to the corresponding file. retry-limit The maximum number of commit retries when the transaction meets a conflict Default: 10 Setting a large number of retries can affect the performance of the TiDB cluster skip-grant-table Allow anyone to connect without a password, and all operations do not check privileges Default: false The value is either true or false. The machine’s root privilege is required to enable this option, which is used to reset the password when forgotten. stats-lease Scan the full table incrementally, and analyze the data amount and indexes of the table Default: “3s” To use this option, you need to manually run analyze table name. Update the statistics automatically and store data in TiKV persistently, taking up some memory. tcp-keep-alive To Enable keepalive in the tcp layer of TiDB Default: false ssl-cert The file path of SSL certificate in PEM format Default: “” If this option and the --ssl-key option are set at the same time, the client can (not required) securely connect to TiDB using TLS. If the specified certificate or private key is invalid, TiDB starts as usual but does not support encrypted connections. ssl-key The file path of SSL certificate keys in PEM format, or the private keys specified by --ssl-cert Default: “” Currently, you cannot load a password-protected private key in TiDB. ssl-ca The file path of the trusted CA certificate in PEM format Default: “” If this option and the --ssl-cert, --ssl-key options are set at the same time, TiDB authenticates the client certificate based on the trusted CA list specified by the option when the client presents the certificate. If the authentication fails, the connection stops. If this option is set but the client does not present the certificate, the encrypted connection continues but the client certificate is not authenticated. "}, {"url": "https://pingcap.com/docs/sql/tidb-server/", "title": "The TiDB Server", "content": " The TiDB Server TiDB refers to the TiDB database management system. This document describes the basic management functions of the TiDB cluster.TiDB cluster startup configuration You can set the service parameters using the command line or the configuration file, or both. The priority of the command line parameters is higher than the configuration file. If the same parameter is set in both ways, TiDB uses the value set using command line parameters. For more information, see The TiDB Command Options.TiDB system variable TiDB is compatible with MySQL system variables, and defines some unique system variables to adjust the database behavior. For more information, see TiDB Specific System Variables.TiDB system table Similar to MySQL, TiDB also has system tables that store the information needed when TiDB runs. For more information, see The TiDB System Database.TiDB data directory The TiDB data is stored in the storage engine and the data directory depends on the storage engine used. For more information about how to choose the storage engine, see the TiDB startup parameters document.When you use the local storage engine, the data is stored on the local hard disk and the directory location is controlled by the path parameter.When you use the TiKV storage engine, the data is stored on the TiKV node and the directory location is controlled by the data-dir parameter.TiDB server logs The three components of the TiDB cluster (tidb-server, tikv-server and pd-server) outputs the logs to standard errors by default. In each of the three components, you can set the --log-file startup parameter (or the configuration item in the configuration file) and output the log into a file.You can adjust the log behavior using the configuration file. For more details, see the configuration file description of each component. For example, the tidb-server log configuration item."}, {"url": "https://pingcap.com/docs/v1.0/sql/tidb-server/", "title": "The TiDB Server", "content": " The TiDB Server TiDB service TiDB refers to the TiDB database management system. This document describes the basic management functions of the TiDB cluster.TiDB cluster startup configuration You can set the service parameters using the command line or the configuration file, or both. The priority of the command line parameters is higher than the configuration file. If the same parameter is set in both ways, TiDB uses the value set using command line parameters. For more information, see The TiDB Command Options.TiDB system variable TiDB is compatible with MySQL system variables, and defines some unique system variables to adjust the database behavior. For more information, see The Proprietary System Variables and Syntaxes in TiDB.TiDB system table Similar to MySQL, TiDB also has system tables that store the information needed when TiDB runs. For more information, see The TiDB System Database.TiDB data directory The TiDB data is stored in the storage engine and the data directory depends on the storage engine used. For more information about how to choose the storage engine, see the TiDB startup parameters document.When you use the local storage engine, the data is stored on the local hard disk and the directory location is controlled by the path parameter.When you use the TiKV storage engine, the data is stored on the TiKV node and the directory location is controlled by the data-dir parameter.TiDB server logs The three components of the TiDB cluster (tidb-server, tikv-server and pd-server) outputs the logs to standard errors by default. In each of the three components, you can set the --log-file parameter (or the configuration item in the configuration file) and output the log into a file.You can adjust the log behavior using the configuration file. For more details, see the configuration file description of each component. For example, the tidb-server log configuration item."}, {"url": "https://pingcap.com/docs/v2.0/sql/tidb-server/", "title": "The TiDB Server", "content": " The TiDB Server TiDB refers to the TiDB database management system. This document describes the basic management functions of the TiDB cluster.TiDB cluster startup configuration You can set the service parameters using the command line or the configuration file, or both. The priority of the command line parameters is higher than the configuration file. If the same parameter is set in both ways, TiDB uses the value set using command line parameters. For more information, see The TiDB Command Options.TiDB system variable TiDB is compatible with MySQL system variables, and defines some unique system variables to adjust the database behavior. For more information, see The Proprietary System Variables and Syntaxes in TiDB.TiDB system table Similar to MySQL, TiDB also has system tables that store the information needed when TiDB runs. For more information, see The TiDB System Database.TiDB data directory The TiDB data is stored in the storage engine and the data directory depends on the storage engine used. For more information about how to choose the storage engine, see the TiDB startup parameters document.When you use the local storage engine, the data is stored on the local hard disk and the directory location is controlled by the path parameter.When you use the TiKV storage engine, the data is stored on the TiKV node and the directory location is controlled by the data-dir parameter.TiDB server logs The three components of the TiDB cluster (tidb-server, tikv-server and pd-server) outputs the logs to standard errors by default. In each of the three components, you can set the --log-file parameter (or the configuration item in the configuration file) and output the log into a file.You can adjust the log behavior using the configuration file. For more details, see the configuration file description of each component. For example, the tidb-server log configuration item."}, {"url": "https://pingcap.com/docs/sql/system-database/", "title": "The TiDB System Database", "content": " The TiDB System Database The TiDB System Database is similar to MySQL, which contains tables that store information required by the server when it runs.Grant system tables These system tables contain grant information about user accounts and their privileges: user: user accounts, global privileges, and other non-privilege columns db: database-level privileges tables_priv: table-level privileges columns_priv: column-level privileges Server-side help system tables Currently, the help_topic is NULL.Statistics system tables stats_buckets: the buckets of statistics stats_histograms: the histograms of statistics stats_meta: the meta information of tables, such as the total number of rows and updated rows GC worker system tables gc_delete_range: to record the data to be deleted Miscellaneous system tables GLOBAL_VARIABLES: global system variable table tidb: to record the version information when TiDB executes bootstrap INFORMATION_SCHEMA tables To be compatible with MySQL, TiDB supports INFORMATION_SCHEMA tables. Some third-party software queries information in these tables. Currently, most INFORMATION_SCHEMA tables in TiDB are NULL.CHARACTER_SETS table The CHARACTER_SETS table provides information about character sets. The default character set in TiDB is utf8, which behaves similar to utf8mb4 in MySQL. Additional character sets in this table are included for compatibility with MySQL:mysql> SELECT * FROM character_sets; +--------------------+----------------------+---------------+--------+ | CHARACTER_SET_NAME | DEFAULT_COLLATE_NAME | DESCRIPTION | MAXLEN | +--------------------+----------------------+---------------+--------+ | utf8 | utf8_bin | UTF-8 Unicode | 3 | | utf8mb4 | utf8mb4_bin | UTF-8 Unicode | 4 | | ascii | ascii_bin | US ASCII | 1 | | latin1 | latin1_bin | Latin1 | 1 | | binary | binary | binary | 1 | +--------------------+----------------------+---------------+--------+ 5 rows in set (0.00 sec) COLLATIONS table The COLLATIONS table provides a list of collations that correspond to character sets in the CHARACTER_SETS table. Currently this table is included only for compatibility with MySQL, as TiDB only supports binary collation.COLLATION_CHARACTER_SET_APPLICABILITY table This table maps collations to the applicable character set name. Similar to the collations table, it is included only for compatibility with MySQL.COLUMNS table The COLUMNS table provides information about columns in tables. The information in this table is not accurate. To query information, it is recommended to use the SHOW statement:SHOW COLUMNS FROM table_name [FROM db_name] [LIKE 'wild'] COLUMN_PRIVILEGES table NULL.ENGINES table The ENGINES table provides information about storage engines. For compatibility, TiDB will always describe InnoDB as the only supported engine.EVENTS table NULL.FILES table NULL.GLOBAL_STATUS table NULL.GLOBAL_VARIABLES table NULL.KEY_COLUMN_USAGE table The KEY_COLUMN_USAGE table describes the key constraints of the columns, such as the primary key constraint.OPTIMIZER_TRACE table NULL.PARAMETERS table NULL.PARTITIONS table NULL.PLUGINS table NULL.PROFILING table NULL.REFERENTIAL_CONSTRAINTS table NULL.ROUTINES table NULL.SCHEMATA table The SCHEMATA table provides information about databases. The table data is equivalent to the result of the SHOW DATABASES statement.mysql> select * from SCHEMATA; +--------------|--------------------|----------------------------|------------------------|----------+ | CATALOG_NAME | SCHEMA_NAME | DEFAULT_CHARACTER_SET_NAME | DEFAULT_COLLATION_NAME | SQL_PATH | +--------------|--------------------|----------------------------|------------------------|----------+ | def | INFORMATION_SCHEMA | utf8 | utf8_bin | NULL | | def | mysql | utf8 | utf8_bin | NULL | | def | PERFORMANCE_SCHEMA | utf8 | utf8_bin | NULL | | def | test | utf8 | utf8_bin | NULL | +--------------|--------------------|----------------------------|------------------------|----------+ 4 rows in set (0.00 sec) SCHEMA_PRIVILEGES table NULL.SESSION_STATUS table NULL.SESSION_VARIABLES table The SESSION_VARIABLES table provides information about session variables. The table data is similar to the result of the SHOW SESSION VARIABLES statement.STATISTICS table The STATISTICS table provides information about table indexes.mysql> desc statistics; +---------------|---------------------|------|------|---------|-------+ | Field | Type | Null | Key | Default | Extra | +---------------|---------------------|------|------|---------|-------+ | TABLE_CATALOG | varchar(512) | YES | | NULL | | | TABLE_SCHEMA | varchar(64) | YES | | NULL | | | TABLE_NAME | varchar(64) | YES | | NULL | | | NON_UNIQUE | varchar(1) | YES | | NULL | | | INDEX_SCHEMA | varchar(64) | YES | | NULL | | | INDEX_NAME | varchar(64) | YES | | NULL | | | SEQ_IN_INDEX | bigint(2) UNSIGNED | YES | | NULL | | | COLUMN_NAME | varchar(21) | YES | | NULL | | | COLLATION | varchar(1) | YES | | NULL | | | CARDINALITY | bigint(21) UNSIGNED | YES | | NULL | | | SUB_PART | bigint(3) UNSIGNED | YES | | NULL | | | PACKED | varchar(10) | YES | | NULL | | | NULLABLE | varchar(3) | YES | | NULL | | | INDEX_TYPE | varchar(16) | YES | | NULL | | | COMMENT | varchar(16) | YES | | NULL | | | INDEX_COMMENT | varchar(1024) | YES | | NULL | | +---------------|---------------------|------|------|---------|-------+ The following statements are equivalent:SELECT * FROM INFORMATION_SCHEMA.STATISTICS WHERE table_name = 'tbl_name' AND table_schema = 'db_name' SHOW INDEX FROM tbl_name FROM db_name TABLES table The TABLES table provides information about tables in databases.The following statements are equivalent:SELECT table_name FROM INFORMATION_SCHEMA.TABLES WHERE table_schema = 'db_name' [AND table_name LIKE 'wild'] SHOW TABLES FROM db_name [LIKE 'wild'] TABLESPACES table NULL.TABLE_CONSTRAINTS table The TABLE_CONSTRAINTS table describes which tables have constraints. The CONSTRAINT_TYPE value can be UNIQUE, PRIMARY KEY, or FOREIGN KEY. The UNIQUE and PRIMARY KEY information is similar to the result of the SHOW INDEX statement. TABLE_PRIVILEGES table NULL.TRIGGERS table NULL.USER_PRIVILEGES table The USER_PRIVILEGES table provides information about global privileges. This information comes from the mysql.user grant table.mysql> desc USER_PRIVILEGES; +----------------|--------------|------|------|---------|-------+ | Field | Type | Null | Key | Default | Extra | +----------------|--------------|------|------|---------|-------+ | GRANTEE | varchar(81) | YES | | NULL | | | TABLE_CATALOG | varchar(512) | YES | | NULL | | | PRIVILEGE_TYPE | varchar(64) | YES | | NULL | | | IS_GRANTABLE | varchar(3) | YES | | NULL | | +----------------|--------------|------|------|---------|-------+ 4 rows in set (0.00 sec) VIEWS table NULL. Currently, TiDB does not support views."}, {"url": "https://pingcap.com/docs/v1.0/sql/system-database/", "title": "The TiDB System Database", "content": " The TiDB System Database The TiDB System Database is similar to MySQL, which contains tables that store information required by the server when it runs.Grant system tables These system tables contain grant information about user accounts and their privileges: user: user accounts, global privileges, and other non-privilege columns db: database-level privileges tables_priv: table-level privileges columns_priv: column-level privileges Server-side help system tables Currently, the help_topic is NULL.Statistics system tables stats_buckets: the buckets of statistics stats_histograms: the histograms of statistics stats_meta: the meta information of tables, such as the total number of rows and updated rows GC worker system tables gc_delete_range: to record the data to be deleted Miscellaneous system tables GLOBAL_VARIABLES: global system variable table tidb: to record the version information when TiDB executes bootstrap INFORMATION_SCHEMA tables To be compatible with MySQL, TiDB supports INFORMATION_SCHEMA tables. Some third-party software queries information in these tables. Currently, most INFORMATION_SCHEMA tables in TiDB are NULL.CHARACTER_SETS table The CHARACTER_SETS table provides information about character sets. But it contains dummy data. By default, TiDB only supports utf8mb4.mysql> select * from CHARACTER_SETS; +--------------------|----------------------|-----------------------|--------+ | CHARACTER_SET_NAME | DEFAULT_COLLATE_NAME | DESCRIPTION | MAXLEN | +--------------------|----------------------|-----------------------|--------+ | ascii | ascii_general_ci | US ASCII | 1 | | binary | binary | Binary pseudo charset | 1 | | latin1 | latin1_swedish_ci | cp1252 West European | 1 | | utf8 | utf8_general_ci | UTF-8 Unicode | 3 | | utf8mb4 | utf8mb4_general_ci | UTF-8 Unicode | 4 | +--------------------|----------------------|-----------------------|--------+ 5 rows in set (0.00 sec) COLLATIONS table The COLLATIONS table is similar to the CHARACTER_SETS table.COLLATION_CHARACTER_SET_APPLICABILITY table NULL.COLUMNS table The COLUMNS table provides information about columns in tables. The information in this table is not accurate. To query information, it is recommended to use the SHOW statement:SHOW COLUMNS FROM table_name [FROM db_name] [LIKE 'wild'] COLUMNS_PRIVILEGE table NULL.ENGINES table The ENGINES table provides information about storage engines. But it contains dummy data only. In the production environment, use the TiKV engine for TiDB.EVENTS table NULL.FILES table NULL.GLOBAL_STATUS table NULL.GLOBAL_VARIABLES table NULL.KEY_COLUMN_USAGE table The KEY_COLUMN_USAGE table describes the key constraints of the columns, such as the primary key constraint.OPTIMIZER_TRACE table NULL.PARAMETERS table NULL.PARTITIONS table NULL.PLUGINS table NULL.PROFILING table NULL.REFERENTIAL_CONSTRAINTS table NULL.ROUTINES table NULL.SCHEMATA table The SCHEMATA table provides information about databases. The table data is equivalent to the result of the SHOW DATABASES statement.mysql> select * from SCHEMATA; +--------------|--------------------|----------------------------|------------------------|----------+ | CATALOG_NAME | SCHEMA_NAME | DEFAULT_CHARACTER_SET_NAME | DEFAULT_COLLATION_NAME | SQL_PATH | +--------------|--------------------|----------------------------|------------------------|----------+ | def | INFORMATION_SCHEMA | utf8 | utf8_bin | NULL | | def | mysql | utf8 | utf8_bin | NULL | | def | PERFORMANCE_SCHEMA | utf8 | utf8_bin | NULL | | def | test | utf8 | utf8_bin | NULL | +--------------|--------------------|----------------------------|------------------------|----------+ 4 rows in set (0.00 sec) SCHEMA_PRIVILEGES table NULL.SESSION_STATUS table NULL.SESSION_VARIABLES table The SESSION_VARIABLES table provides information about session variables. The table data is similar to the result of the SHOW SESSION VARIABLES statement.STATISTICS table The STATISTICS table provides information about table indexes.mysql> desc statistics; +---------------|---------------------|------|------|---------|-------+ | Field | Type | Null | Key | Default | Extra | +---------------|---------------------|------|------|---------|-------+ | TABLE_CATALOG | varchar(512) | YES | | NULL | | | TABLE_SCHEMA | varchar(64) | YES | | NULL | | | TABLE_NAME | varchar(64) | YES | | NULL | | | NON_UNIQUE | varchar(1) | YES | | NULL | | | INDEX_SCHEMA | varchar(64) | YES | | NULL | | | INDEX_NAME | varchar(64) | YES | | NULL | | | SEQ_IN_INDEX | bigint(2) UNSIGNED | YES | | NULL | | | COLUMN_NAME | varchar(21) | YES | | NULL | | | COLLATION | varchar(1) | YES | | NULL | | | CARDINALITY | bigint(21) UNSIGNED | YES | | NULL | | | SUB_PART | bigint(3) UNSIGNED | YES | | NULL | | | PACKED | varchar(10) | YES | | NULL | | | NULLABLE | varchar(3) | YES | | NULL | | | INDEX_TYPE | varchar(16) | YES | | NULL | | | COMMENT | varchar(16) | YES | | NULL | | | INDEX_COMMENT | varchar(1024) | YES | | NULL | | +---------------|---------------------|------|------|---------|-------+ The following statements are equivalent:SELECT * FROM INFORMATION_SCHEMA.STATISTICS WHERE table_name = 'tbl_name' AND table_schema = 'db_name' SHOW INDEX FROM tbl_name FROM db_name TABLES table The TABLES table provides information about tables in databases.The following statements are equivalent:SELECT table_name FROM INFORMATION_SCHEMA.TABLES WHERE table_schema = 'db_name' [AND table_name LIKE 'wild'] SHOW TABLES FROM db_name [LIKE 'wild'] TABLESPACES table NULL.TABLE_CONSTRAINTS table The TABLE_CONSTRAINTS table describes which tables have constraints. The CONSTRAINT_TYPE value can be UNIQUE, PRIMARY KEY, or FOREIGN KEY. The UNIQUE and PRIMARY KEY information is similar to the result of the SHOW INDEX statement. TABLE_PRIVILEGES table NULL.TRIGGERS table NULL.USER_PRIVILEGES table The USER_PRIVILEGES table provides information about global privileges. This information comes from the mysql.user grant table.mysql> desc USER_PRIVILEGES; +----------------|--------------|------|------|---------|-------+ | Field | Type | Null | Key | Default | Extra | +----------------|--------------|------|------|---------|-------+ | GRANTEE | varchar(81) | YES | | NULL | | | TABLE_CATALOG | varchar(512) | YES | | NULL | | | PRIVILEGE_TYPE | varchar(64) | YES | | NULL | | | IS_GRANTABLE | varchar(3) | YES | | NULL | | +----------------|--------------|------|------|---------|-------+ 4 rows in set (0.00 sec) VIEWS table NULL. Currently, TiDB does not support views."}, {"url": "https://pingcap.com/docs/v2.0/sql/system-database/", "title": "The TiDB System Database", "content": " The TiDB System Database The TiDB System Database is similar to MySQL, which contains tables that store information required by the server when it runs.Grant system tables These system tables contain grant information about user accounts and their privileges: user: user accounts, global privileges, and other non-privilege columns db: database-level privileges tables_priv: table-level privileges columns_priv: column-level privileges Server-side help system tables Currently, the help_topic is NULL.Statistics system tables stats_buckets: the buckets of statistics stats_histograms: the histograms of statistics stats_meta: the meta information of tables, such as the total number of rows and updated rows GC worker system tables gc_delete_range: to record the data to be deleted Miscellaneous system tables GLOBAL_VARIABLES: global system variable table tidb: to record the version information when TiDB executes bootstrap INFORMATION_SCHEMA tables To be compatible with MySQL, TiDB supports INFORMATION_SCHEMA tables. Some third-party software queries information in these tables. Currently, most INFORMATION_SCHEMA tables in TiDB are NULL.CHARACTER_SETS table The CHARACTER_SETS table provides information about character sets. But it contains dummy data. By default, TiDB only supports utf8mb4.mysql> select * from CHARACTER_SETS; +--------------------|----------------------|-----------------------|--------+ | CHARACTER_SET_NAME | DEFAULT_COLLATE_NAME | DESCRIPTION | MAXLEN | +--------------------|----------------------|-----------------------|--------+ | ascii | ascii_general_ci | US ASCII | 1 | | binary | binary | Binary pseudo charset | 1 | | latin1 | latin1_swedish_ci | cp1252 West European | 1 | | utf8 | utf8_general_ci | UTF-8 Unicode | 3 | | utf8mb4 | utf8mb4_general_ci | UTF-8 Unicode | 4 | +--------------------|----------------------|-----------------------|--------+ 5 rows in set (0.00 sec) COLLATIONS table The COLLATIONS table is similar to the CHARACTER_SETS table.COLLATION_CHARACTER_SET_APPLICABILITY table NULL.COLUMNS table The COLUMNS table provides information about columns in tables. The information in this table is not accurate. To query information, it is recommended to use the SHOW statement:SHOW COLUMNS FROM table_name [FROM db_name] [LIKE 'wild'] COLUMN_PRIVILEGES table NULL.ENGINES table The ENGINES table provides information about storage engines. But it contains dummy data only. In the production environment, use the TiKV engine for TiDB.EVENTS table NULL.FILES table NULL.GLOBAL_STATUS table NULL.GLOBAL_VARIABLES table NULL.KEY_COLUMN_USAGE table The KEY_COLUMN_USAGE table describes the key constraints of the columns, such as the primary key constraint.OPTIMIZER_TRACE table NULL.PARAMETERS table NULL.PARTITIONS table NULL.PLUGINS table NULL.PROFILING table NULL.REFERENTIAL_CONSTRAINTS table NULL.ROUTINES table NULL.SCHEMATA table The SCHEMATA table provides information about databases. The table data is equivalent to the result of the SHOW DATABASES statement.mysql> select * from SCHEMATA; +--------------|--------------------|----------------------------|------------------------|----------+ | CATALOG_NAME | SCHEMA_NAME | DEFAULT_CHARACTER_SET_NAME | DEFAULT_COLLATION_NAME | SQL_PATH | +--------------|--------------------|----------------------------|------------------------|----------+ | def | INFORMATION_SCHEMA | utf8 | utf8_bin | NULL | | def | mysql | utf8 | utf8_bin | NULL | | def | PERFORMANCE_SCHEMA | utf8 | utf8_bin | NULL | | def | test | utf8 | utf8_bin | NULL | +--------------|--------------------|----------------------------|------------------------|----------+ 4 rows in set (0.00 sec) SCHEMA_PRIVILEGES table NULL.SESSION_STATUS table NULL.SESSION_VARIABLES table The SESSION_VARIABLES table provides information about session variables. The table data is similar to the result of the SHOW SESSION VARIABLES statement.STATISTICS table The STATISTICS table provides information about table indexes.mysql> desc statistics; +---------------|---------------------|------|------|---------|-------+ | Field | Type | Null | Key | Default | Extra | +---------------|---------------------|------|------|---------|-------+ | TABLE_CATALOG | varchar(512) | YES | | NULL | | | TABLE_SCHEMA | varchar(64) | YES | | NULL | | | TABLE_NAME | varchar(64) | YES | | NULL | | | NON_UNIQUE | varchar(1) | YES | | NULL | | | INDEX_SCHEMA | varchar(64) | YES | | NULL | | | INDEX_NAME | varchar(64) | YES | | NULL | | | SEQ_IN_INDEX | bigint(2) UNSIGNED | YES | | NULL | | | COLUMN_NAME | varchar(21) | YES | | NULL | | | COLLATION | varchar(1) | YES | | NULL | | | CARDINALITY | bigint(21) UNSIGNED | YES | | NULL | | | SUB_PART | bigint(3) UNSIGNED | YES | | NULL | | | PACKED | varchar(10) | YES | | NULL | | | NULLABLE | varchar(3) | YES | | NULL | | | INDEX_TYPE | varchar(16) | YES | | NULL | | | COMMENT | varchar(16) | YES | | NULL | | | INDEX_COMMENT | varchar(1024) | YES | | NULL | | +---------------|---------------------|------|------|---------|-------+ The following statements are equivalent:SELECT * FROM INFORMATION_SCHEMA.STATISTICS WHERE table_name = 'tbl_name' AND table_schema = 'db_name' SHOW INDEX FROM tbl_name FROM db_name TABLES table The TABLES table provides information about tables in databases.The following statements are equivalent:SELECT table_name FROM INFORMATION_SCHEMA.TABLES WHERE table_schema = 'db_name' [AND table_name LIKE 'wild'] SHOW TABLES FROM db_name [LIKE 'wild'] TABLESPACES table NULL.TABLE_CONSTRAINTS table The TABLE_CONSTRAINTS table describes which tables have constraints. The CONSTRAINT_TYPE value can be UNIQUE, PRIMARY KEY, or FOREIGN KEY. The UNIQUE and PRIMARY KEY information is similar to the result of the SHOW INDEX statement. TABLE_PRIVILEGES table NULL.TRIGGERS table NULL.USER_PRIVILEGES table The USER_PRIVILEGES table provides information about global privileges. This information comes from the mysql.user grant table.mysql> desc USER_PRIVILEGES; +----------------|--------------|------|------|---------|-------+ | Field | Type | Null | Key | Default | Extra | +----------------|--------------|------|------|---------|-------+ | GRANTEE | varchar(81) | YES | | NULL | | | TABLE_CATALOG | varchar(512) | YES | | NULL | | | PRIVILEGE_TYPE | varchar(64) | YES | | NULL | | | IS_GRANTABLE | varchar(3) | YES | | NULL | | +----------------|--------------|------|------|---------|-------+ 4 rows in set (0.00 sec) VIEWS table NULL. Currently, TiDB does not support views."}, {"url": "https://pingcap.com/tidb-academy/mysql_dbas/htap/spark/", "title": "TiDB + Apache Spark", "content": " TiDB + Apache Spark Transcript For those that are confused with the overlap between the TiDB Server and Apache Spark, which can both execute SQL queries, here is a general rule to differentiate the two: TiDB aims to handle 100% of OLTP queries. TiDB aims to handle 80% of adhoc OLAP queries. Spark has some advantages for very long running queries from its managed execution environment. Jobs can be automatically re-run on failure. Additionally, a job that contains multiple queries in a map-reduce form can be scheduled amongst a pool of workers. If an individual worker fails, the work can be rescheduled on another node. For OLAP queries on TiDB, the TiDB server needs to remain healthy for the duration of query execution, and failures will not be retried.Over time the engineering team plans to increase the percentage of queries that the TiDB Server can handle directly, while also enhancing Spark support through the TiSpark driver. Why both?Spark is a unified analytics engine for large-scale data processing. So if we think beyond SQL, there are use cases that involve both machine learning and graphs which Apache Spark is well suited for. By using the TiSpark driver, you can make use of these without having to ETL data between systems."}, {"url": "https://pingcap.com/docs-cn/releases/ga/", "title": "TiDB 1.0 release notes", "content": " TiDB 1.0 Release Notes 2017 年 10 月 16 日,TiDB 发布 GA 版(TiDB 1.0)。该版本对 MySQL 兼容性、SQL 优化器、系统稳定性、性能做了大量的工作。TiDB: SQL 查询优化器 调整代价模型 Analyze 下推 函数签名下推 优化内部数据格式,减小中间结果大小 提升 MySQL 兼容性 支持 NO_SQL_CACHE 语法,控制存储引擎对缓存的使用 重构 Hash Aggregator 算子,降低内存使用 支持 Stream Aggragator 算子 PD: 支持基于读流量的热点调度 支持设置 Store 权重,以及基于权重的调度 TiKV: Coprocessor 支持更多下推函数 支持取样操作下推 支持手动触发数据 Compact,用于快速回收空间 提升性能和稳定性 增加 Debug API,方便调试 TiSpark Beta Release: 支持可配置框架 支持 ThriftSever/JDBC 和 Spark SQL 脚本入口 源码地址 源码地址鸣谢 特别感谢参与项目的企业和团队 Archon Mobike SpeedyCloud UCloud 腾讯云 韩国三星研究院 感谢以下组织/个人提供出色的开源软件/服务: Asta Xie CNCF CoreOS Databricks Docker Github Grafana gRPC Jepsen Kubernetes Namazu Prometheus RedHat RocksDB Team Rust Team 感谢社区个人贡献者 TiDB Contributor 8cbx Akihiro Suda aliyx alston111111 andelf Andy Librian Arthur Yang astaxie Bai, Yang bailaohe Bin Liu Blame cosmos Breezewish Carlos Ferreira Ce Gao Changjian Zhang Cheng Lian Cholerae Hu Chu Chao coldwater Cole R Lawrence cuiqiu cuiyuan Cwen Dagang David Chen David Ding dawxy dcadevil Deshi Xiao Di Tang disksing dongxu dreamquster Drogon Du Chuan Dylan Wen eBoyy Eric Romano Ewan Chou Fiisio follitude Fred Wang follitude fud fudali gaoyangxiaozhu Gogs goroutine Gregory Ian Guanqun Lu Guilherme Hübner Franco Haibin Xie Han Fei Hiroaki Nakamura hiwjd Hongyuan Wang Hu Ming Hu Ziming Huachao Huang HuaiyuXu Huxley Hu iamxy Ian insion iroi44 Ivan.Yang Jack Yu jacky liu Jan Mercl Jason W Jay Jay Lee Jianfei Wang Jiaxing Liang Jie Zhou jinhelin Jonathan Boulle Karl Ostendorf knarfeh Kuiba leixuechun li Li Shihai Liao Qiang Light lijian Lilian Lee Liqueur Librazy Liu Cong Liu Shaohui liubo0127 liyanan lkk2003rty Louis louishust luckcolors Lynn Mae Huang maiyang maxwell mengshangqi Michael Belenchenko mo2zie morefreeze MQ mxlxm Neil Shen netroby ngaut Nicole Nie nolouch onlymellb overvenus PaladinTyrion paulg Priya Seth qgxiaozhan qhsong Qiannan qiuyesuifeng queenypingcap qupeng Rain Li ranxiaolong Ray Rick Yu shady ShawnLi Shen Li Sheng Tang Shirly Shuai Li ShuNing ShuYu Wang siddontang silenceper Simon J Mudd Simon Xia skimmilk6877 sllt soup Sphinx Steffen sumBug sunhao2017 Tao Meng Tao Zhou tennix tiancaiamao TianGuangyu Tristan Su ueizhou UncP Unknwon v01dstar Van WangXiangUSTC wangyisong1996 weekface wegel Wei Fu Wenbin Xiao Wenting Li Wenxuan Shi winkyao woodpenker wuxuelian Xiang Li xiaojian cai Xuanjia Yang Xuanwo XuHuaiyu Yang Zhexuan Yann Autissier Yanzhe Chen Yiding Cui Yim youyouhu Yu Jun Yuwen Shen Zejun Li Zhang Yuning zhangjinpeng1987 ZHAO Yijun ZhengQian ZhengQianFang zhengwanbo Zhe-xuan Yang ZhiFeng Hu Zhiyuan Zheng Zhou Tao Zhoubirdblue zhouningnan Ziyi Yan zs634134578 zyguan zz-jason qiukeren hawkingrei wangyanjun zxylvlp "}, {"url": "https://pingcap.com/docs-cn/v1.0/releases/ga/", "title": "TiDB 1.0 release notes", "content": " TiDB 1.0 release notes 10 月 16 日,TiDB 发布 GA 版(TiDB 1.0)。该版本对 MySQL 兼容性、SQL 优化器、系统稳定性、性能做了大量的工作。TiDB: SQL 查询优化器 调整代价模型 Analyze 下推 函数签名下推 优化内部数据格式,减小中间结果大小 提升 MySQL 兼容性 支持 NO_SQL_CACHE 语法,控制存储引擎对缓存的使用 重构 Hash Aggregator 算子,降低内存使用 支持 Stream Aggragator 算子 PD: 支持基于读流量的热点调度 支持设置 Store 权重,以及基于权重的调度 TiKV: Coprocessor 支持更多下推函数 支持取样操作下推 支持手动触发数据 Compact,用于快速回收空间 提升性能和稳定性 增加 Debug API,方便调试 TiSpark Beta Release: 支持可配置框架 支持 ThriftSever/JDBC 和 Spark SQL 脚本入口 源码地址 源码地址鸣谢 特别感谢参与项目的企业和团队 Archon Mobike SpeedyCloud UCloud 腾讯云 韩国三星研究院 感谢以下组织/个人提供出色的开源软件/服务: Asta Xie CNCF CoreOS Databricks Docker Github Grafana gRPC Jepsen Kubernetes Namazu Prometheus RedHat RocksDB Team Rust Team 感谢社区个人贡献者 TiDB Contributor 8cbx Akihiro Suda aliyx alston111111 andelf Andy Librian Arthur Yang astaxie Bai, Yang bailaohe Bin Liu Blame cosmos Breezewish Carlos Ferreira Ce Gao Changjian Zhang Cheng Lian Cholerae Hu Chu Chao coldwater Cole R Lawrence cuiqiu cuiyuan Cwen Dagang David Chen David Ding dawxy dcadevil Deshi Xiao Di Tang disksing dongxu dreamquster Drogon Du Chuan Dylan Wen eBoyy Eric Romano Ewan Chou Fiisio follitude Fred Wang follitude fud fudali gaoyangxiaozhu Gogs goroutine Gregory Ian Guanqun Lu Guilherme Hübner Franco Haibin Xie Han Fei Hiroaki Nakamura hiwjd Hongyuan Wang Hu Ming Hu Ziming Huachao Huang HuaiyuXu Huxley Hu iamxy Ian insion iroi44 Ivan.Yang Jack Yu jacky liu Jan Mercl Jason W Jay Jay Lee Jianfei Wang Jiaxing Liang Jie Zhou jinhelin Jonathan Boulle Karl Ostendorf knarfeh Kuiba leixuechun li Li Shihai Liao Qiang Light lijian Lilian Lee Liqueur Librazy Liu Cong Liu Shaohui liubo0127 liyanan lkk2003rty Louis louishust luckcolors Lynn Mae Huang maiyang maxwell mengshangqi Michael Belenchenko mo2zie morefreeze MQ mxlxm Neil Shen netroby ngaut Nicole Nie nolouch onlymellb overvenus PaladinTyrion paulg Priya Seth qgxiaozhan qhsong Qiannan qiuyesuifeng queenypingcap qupeng Rain Li ranxiaolong Ray Rick Yu shady ShawnLi Shen Li Sheng Tang Shirly Shuai Li ShuNing ShuYu Wang siddontang silenceper Simon J Mudd Simon Xia skimmilk6877 sllt soup Sphinx Steffen sumBug sunhao2017 Tao Meng Tao Zhou tennix tiancaiamao TianGuangyu Tristan Su ueizhou UncP Unknwon v01dstar Van WangXiangUSTC wangyisong1996 weekface wegel Wei Fu Wenbin Xiao Wenting Li Wenxuan Shi winkyao woodpenker wuxuelian Xiang Li xiaojian cai Xuanjia Yang Xuanwo XuHuaiyu Yang Zhexuan Yann Autissier Yanzhe Chen Yiding Cui Yim youyouhu Yu Jun Yuwen Shen Zejun Li Zhang Yuning zhangjinpeng1987 ZHAO Yijun ZhengQian ZhengQianFang zhengwanbo Zhe-xuan Yang ZhiFeng Hu Zhiyuan Zheng Zhou Tao Zhoubirdblue zhouningnan Ziyi Yan zs634134578 zyguan zz-jason qiukeren hawkingrei wangyanjun zxylvlp "}, {"url": "https://pingcap.com/docs-cn/v2.0/releases/ga/", "title": "TiDB 1.0 release notes", "content": " TiDB 1.0 Release Notes 10 月 16 日,TiDB 发布 GA 版(TiDB 1.0)。该版本对 MySQL 兼容性、SQL 优化器、系统稳定性、性能做了大量的工作。TiDB: SQL 查询优化器 调整代价模型 Analyze 下推 函数签名下推 优化内部数据格式,减小中间结果大小 提升 MySQL 兼容性 支持 NO_SQL_CACHE 语法,控制存储引擎对缓存的使用 重构 Hash Aggregator 算子,降低内存使用 支持 Stream Aggragator 算子 PD: 支持基于读流量的热点调度 支持设置 Store 权重,以及基于权重的调度 TiKV: Coprocessor 支持更多下推函数 支持取样操作下推 支持手动触发数据 Compact,用于快速回收空间 提升性能和稳定性 增加 Debug API,方便调试 TiSpark Beta Release: 支持可配置框架 支持 ThriftSever/JDBC 和 Spark SQL 脚本入口 源码地址 源码地址鸣谢 特别感谢参与项目的企业和团队 Archon Mobike SpeedyCloud UCloud 腾讯云 韩国三星研究院 感谢以下组织/个人提供出色的开源软件/服务: Asta Xie CNCF CoreOS Databricks Docker Github Grafana gRPC Jepsen Kubernetes Namazu Prometheus RedHat RocksDB Team Rust Team 感谢社区个人贡献者 TiDB Contributor 8cbx Akihiro Suda aliyx alston111111 andelf Andy Librian Arthur Yang astaxie Bai, Yang bailaohe Bin Liu Blame cosmos Breezewish Carlos Ferreira Ce Gao Changjian Zhang Cheng Lian Cholerae Hu Chu Chao coldwater Cole R Lawrence cuiqiu cuiyuan Cwen Dagang David Chen David Ding dawxy dcadevil Deshi Xiao Di Tang disksing dongxu dreamquster Drogon Du Chuan Dylan Wen eBoyy Eric Romano Ewan Chou Fiisio follitude Fred Wang follitude fud fudali gaoyangxiaozhu Gogs goroutine Gregory Ian Guanqun Lu Guilherme Hübner Franco Haibin Xie Han Fei Hiroaki Nakamura hiwjd Hongyuan Wang Hu Ming Hu Ziming Huachao Huang HuaiyuXu Huxley Hu iamxy Ian insion iroi44 Ivan.Yang Jack Yu jacky liu Jan Mercl Jason W Jay Jay Lee Jianfei Wang Jiaxing Liang Jie Zhou jinhelin Jonathan Boulle Karl Ostendorf knarfeh Kuiba leixuechun li Li Shihai Liao Qiang Light lijian Lilian Lee Liqueur Librazy Liu Cong Liu Shaohui liubo0127 liyanan lkk2003rty Louis louishust luckcolors Lynn Mae Huang maiyang maxwell mengshangqi Michael Belenchenko mo2zie morefreeze MQ mxlxm Neil Shen netroby ngaut Nicole Nie nolouch onlymellb overvenus PaladinTyrion paulg Priya Seth qgxiaozhan qhsong Qiannan qiuyesuifeng queenypingcap qupeng Rain Li ranxiaolong Ray Rick Yu shady ShawnLi Shen Li Sheng Tang Shirly Shuai Li ShuNing ShuYu Wang siddontang silenceper Simon J Mudd Simon Xia skimmilk6877 sllt soup Sphinx Steffen sumBug sunhao2017 Tao Meng Tao Zhou tennix tiancaiamao TianGuangyu Tristan Su ueizhou UncP Unknwon v01dstar Van WangXiangUSTC wangyisong1996 weekface wegel Wei Fu Wenbin Xiao Wenting Li Wenxuan Shi winkyao woodpenker wuxuelian Xiang Li xiaojian cai Xuanjia Yang Xuanwo XuHuaiyu Yang Zhexuan Yann Autissier Yanzhe Chen Yiding Cui Yim youyouhu Yu Jun Yuwen Shen Zejun Li Zhang Yuning zhangjinpeng1987 ZHAO Yijun ZhengQian ZhengQianFang zhengwanbo Zhe-xuan Yang ZhiFeng Hu Zhiyuan Zheng Zhou Tao Zhoubirdblue zhouningnan Ziyi Yan zs634134578 zyguan zz-jason qiukeren hawkingrei wangyanjun zxylvlp "}, {"url": "https://pingcap.com/docs/releases/ga/", "title": "TiDB 1.0 release notes", "content": " TiDB 1.0 Release Notes On October 16, 2017, TiDB 1.0 is now released! This release is focused on MySQL compatibility, SQL optimization, stability, and performance.TiDB: The SQL query optimizer: Adjust the cost model Analyze pushdown Function signature pushdown Optimize the internal data format to reduce the interim data size Enhance the MySQL compatibility Support the NO_SQL_CACHE syntax and limit the cache usage in the storage engine Refactor the Hash Aggregator operator to reduce the memory usage Support the Stream Aggregator operator PD: Support read flow based balancing Support setting the Store weight and weight based balancing TiKV: Coprocessor now supports more pushdown functions Support pushing down the sampling operation Support manually triggering data compact to collect space quickly Improve the performance and stability Add a Debug API for debugging TiSpark Beta Release: Support configuration framework Support ThriftSever/JDBC and Spark SQL Acknowledgement Special thanks to the following enterprises and teams! Archon Mobike Samsung Electronics SpeedyCloud Tencent Cloud UCloud Thanks to the open source software and services from the following organizations and individuals: Asta Xie CNCF CoreOS Databricks Docker Github Grafana gRPC Jepsen Kubernetes Namazu Prometheus RedHat RocksDB Team Rust Team Thanks to the individual contributors: 8cbx Akihiro Suda aliyx alston111111 andelf Andy Librian Arthur Yang astaxie Bai, Yang bailaohe Bin Liu Blame cosmos Breezewish Carlos Ferreira Ce Gao Changjian Zhang Cheng Lian Cholerae Hu Chu Chao coldwater Cole R Lawrence cuiqiu cuiyuan Cwen Dagang David Chen David Ding dawxy dcadevil Deshi Xiao Di Tang disksing dongxu dreamquster Drogon Du Chuan Dylan Wen eBoyy Eric Romano Ewan Chou Fiisio follitude Fred Wang fud fudali gaoyangxiaozhu Gogs goroutine Gregory Ian Guanqun Lu Guilherme Hübner Franco Haibin Xie Han Fei hawkingrei Hiroaki Nakamura hiwjd Hongyuan Wang Hu Ming Hu Ziming Huachao Huang HuaiyuXu Huxley Hu iamxy Ian insion iroi44 Ivan.Yang Jack Yu jacky liu Jan Mercl Jason W Jay Jay Lee Jianfei Wang Jiaxing Liang Jie Zhou jinhelin Jonathan Boulle Karl Ostendorf knarfeh Kuiba leixuechun li Li Shihai Liao Qiang Light lijian Lilian Lee Liqueur Librazy Liu Cong Liu Shaohui liubo0127 liyanan lkk2003rty Louis louishust luckcolors Lynn Mae Huang maiyang maxwell mengshangqi Michael Belenchenko mo2zie morefreeze MQ mxlxm Neil Shen netroby ngaut Nicole Nie nolouch onlymellb overvenus PaladinTyrion paulg Priya Seth qgxiaozhan qhsong Qiannan qiukeren qiuyesuifeng queenypingcap qupeng Rain Li ranxiaolong Ray Rick Yu shady ShawnLi Shen Li Sheng Tang Shirly Shuai Li ShuNing ShuYu Wang siddontang silenceper Simon J Mudd Simon Xia skimmilk6877 sllt soup Sphinx Steffen sumBug sunhao2017 Tao Meng Tao Zhou tennix tiancaiamao TianGuangyu Tristan Su ueizhou UncP Unknwon v01dstar Van WangXiangUSTC wangyanjun wangyisong1996 weekface wegel Wei Fu Wenbin Xiao Wenting Li Wenxuan Shi winkyao woodpenker wuxuelian Xiang Li xiaojian cai Xuanjia Yang Xuanwo XuHuaiyu Yang Zhexuan Yann Autissier Yanzhe Chen Yiding Cui Yim youyouhu Yu Jun Yuwen Shen Zejun Li Zhang Yuning zhangjinpeng1987 ZHAO Yijun Zhe-xuan Yang ZhengQian ZhengQianFang zhengwanbo ZhiFeng Hu Zhiyuan Zheng Zhou Tao Zhoubirdblue zhouningnan Ziyi Yan zs634134578 zxylvlp zyguan zz-jason "}, {"url": "https://pingcap.com/docs/v1.0/releases/ga/", "title": "TiDB 1.0 release notes", "content": " TiDB 1.0 Release Notes On October 16, 2017, TiDB 1.0 is now released! This release is focused on MySQL compatibility, SQL optimization, stability, and performance.TiDB: The SQL query optimizer: Adjust the cost model Analyze pushdown Function signature pushdown Optimize the internal data format to reduce the interim data size Enhance the MySQL compatibility Support the NO_SQL_CACHE syntax and limit the cache usage in the storage engine Refactor the Hash Aggregator operator to reduce the memory usage Support the Stream Aggregator operator PD: Support read flow based balancing Support setting the Store weight and weight based balancing TiKV: Coprocessor now supports more pushdown functions Support pushing down the sampling operation Support manually triggering data compact to collect space quickly Improve the performance and stability Add a Debug API for debugging TiSpark Beta Release: Support configuration framework Support ThriftSever/JDBC and Spark SQL Acknowledgement Special thanks to the following enterprises and teams! Archon Mobike Samsung Electronics SpeedyCloud Tencent Cloud UCloud Thanks to the open source software and services from the following organizations and individuals: Asta Xie CNCF CoreOS Databricks Docker Github Grafana gRPC Jepsen Kubernetes Namazu Prometheus RedHat RocksDB Team Rust Team Thanks to the individual contributors: 8cbx Akihiro Suda aliyx alston111111 andelf Andy Librian Arthur Yang astaxie Bai, Yang bailaohe Bin Liu Blame cosmos Breezewish Carlos Ferreira Ce Gao Changjian Zhang Cheng Lian Cholerae Hu Chu Chao coldwater Cole R Lawrence cuiqiu cuiyuan Cwen Dagang David Chen David Ding dawxy dcadevil Deshi Xiao Di Tang disksing dongxu dreamquster Drogon Du Chuan Dylan Wen eBoyy Eric Romano Ewan Chou Fiisio follitude Fred Wang fud fudali gaoyangxiaozhu Gogs goroutine Gregory Ian Guanqun Lu Guilherme Hübner Franco Haibin Xie Han Fei hawkingrei Hiroaki Nakamura hiwjd Hongyuan Wang Hu Ming Hu Ziming Huachao Huang HuaiyuXu Huxley Hu iamxy Ian insion iroi44 Ivan.Yang Jack Yu jacky liu Jan Mercl Jason W Jay Jay Lee Jianfei Wang Jiaxing Liang Jie Zhou jinhelin Jonathan Boulle Karl Ostendorf knarfeh Kuiba leixuechun li Li Shihai Liao Qiang Light lijian Lilian Lee Liqueur Librazy Liu Cong Liu Shaohui liubo0127 liyanan lkk2003rty Louis louishust luckcolors Lynn Mae Huang maiyang maxwell mengshangqi Michael Belenchenko mo2zie morefreeze MQ mxlxm Neil Shen netroby ngaut Nicole Nie nolouch onlymellb overvenus PaladinTyrion paulg Priya Seth qgxiaozhan qhsong Qiannan qiukeren qiuyesuifeng queenypingcap qupeng Rain Li ranxiaolong Ray Rick Yu shady ShawnLi Shen Li Sheng Tang Shirly Shuai Li ShuNing ShuYu Wang siddontang silenceper Simon J Mudd Simon Xia skimmilk6877 sllt soup Sphinx Steffen sumBug sunhao2017 Tao Meng Tao Zhou tennix tiancaiamao TianGuangyu Tristan Su ueizhou UncP Unknwon v01dstar Van WangXiangUSTC wangyanjun wangyisong1996 weekface wegel Wei Fu Wenbin Xiao Wenting Li Wenxuan Shi winkyao woodpenker wuxuelian Xiang Li xiaojian cai Xuanjia Yang Xuanwo XuHuaiyu Yang Zhexuan Yann Autissier Yanzhe Chen Yiding Cui Yim youyouhu Yu Jun Yuwen Shen Zejun Li Zhang Yuning zhangjinpeng1987 ZHAO Yijun Zhe-xuan Yang ZhengQian ZhengQianFang zhengwanbo ZhiFeng Hu Zhiyuan Zheng Zhou Tao Zhoubirdblue zhouningnan Ziyi Yan zs634134578 zxylvlp zyguan zz-jason "}, {"url": "https://pingcap.com/docs/v2.0/releases/ga/", "title": "TiDB 1.0 release notes", "content": " TiDB 1.0 Release Notes On October 16, 2017, TiDB 1.0 is now released! This release is focused on MySQL compatibility, SQL optimization, stability, and performance.TiDB: The SQL query optimizer: Adjust the cost model Analyze pushdown Function signature pushdown Optimize the internal data format to reduce the interim data size Enhance the MySQL compatibility Support the NO_SQL_CACHE syntax and limit the cache usage in the storage engine Refactor the Hash Aggregator operator to reduce the memory usage Support the Stream Aggregator operator PD: Support read flow based balancing Support setting the Store weight and weight based balancing TiKV: Coprocessor now supports more pushdown functions Support pushing down the sampling operation Support manually triggering data compact to collect space quickly Improve the performance and stability Add a Debug API for debugging TiSpark Beta Release: Support configuration framework Support ThriftSever/JDBC and Spark SQL Acknowledgement Special thanks to the following enterprises and teams! Archon Mobike Samsung Electronics SpeedyCloud Tencent Cloud UCloud Thanks to the open source software and services from the following organizations and individuals: Asta Xie CNCF CoreOS Databricks Docker Github Grafana gRPC Jepsen Kubernetes Namazu Prometheus RedHat RocksDB Team Rust Team Thanks to the individual contributors: 8cbx Akihiro Suda aliyx alston111111 andelf Andy Librian Arthur Yang astaxie Bai, Yang bailaohe Bin Liu Blame cosmos Breezewish Carlos Ferreira Ce Gao Changjian Zhang Cheng Lian Cholerae Hu Chu Chao coldwater Cole R Lawrence cuiqiu cuiyuan Cwen Dagang David Chen David Ding dawxy dcadevil Deshi Xiao Di Tang disksing dongxu dreamquster Drogon Du Chuan Dylan Wen eBoyy Eric Romano Ewan Chou Fiisio follitude Fred Wang fud fudali gaoyangxiaozhu Gogs goroutine Gregory Ian Guanqun Lu Guilherme Hübner Franco Haibin Xie Han Fei hawkingrei Hiroaki Nakamura hiwjd Hongyuan Wang Hu Ming Hu Ziming Huachao Huang HuaiyuXu Huxley Hu iamxy Ian insion iroi44 Ivan.Yang Jack Yu jacky liu Jan Mercl Jason W Jay Jay Lee Jianfei Wang Jiaxing Liang Jie Zhou jinhelin Jonathan Boulle Karl Ostendorf knarfeh Kuiba leixuechun li Li Shihai Liao Qiang Light lijian Lilian Lee Liqueur Librazy Liu Cong Liu Shaohui liubo0127 liyanan lkk2003rty Louis louishust luckcolors Lynn Mae Huang maiyang maxwell mengshangqi Michael Belenchenko mo2zie morefreeze MQ mxlxm Neil Shen netroby ngaut Nicole Nie nolouch onlymellb overvenus PaladinTyrion paulg Priya Seth qgxiaozhan qhsong Qiannan qiukeren qiuyesuifeng queenypingcap qupeng Rain Li ranxiaolong Ray Rick Yu shady ShawnLi Shen Li Sheng Tang Shirly Shuai Li ShuNing ShuYu Wang siddontang silenceper Simon J Mudd Simon Xia skimmilk6877 sllt soup Sphinx Steffen sumBug sunhao2017 Tao Meng Tao Zhou tennix tiancaiamao TianGuangyu Tristan Su ueizhou UncP Unknwon v01dstar Van WangXiangUSTC wangyanjun wangyisong1996 weekface wegel Wei Fu Wenbin Xiao Wenting Li Wenxuan Shi winkyao woodpenker wuxuelian Xiang Li xiaojian cai Xuanjia Yang Xuanwo XuHuaiyu Yang Zhexuan Yann Autissier Yanzhe Chen Yiding Cui Yim youyouhu Yu Jun Yuwen Shen Zejun Li Zhang Yuning zhangjinpeng1987 ZHAO Yijun Zhe-xuan Yang ZhengQian ZhengQianFang zhengwanbo ZhiFeng Hu Zhiyuan Zheng Zhou Tao Zhoubirdblue zhouningnan Ziyi Yan zs634134578 zxylvlp zyguan zz-jason "}, {"url": "https://pingcap.com/docs/releases/101/", "title": "TiDB 1.0.1 Release Notes", "content": " TiDB 1.0.1 Release Notes On November 1, 2017, TiDB 1.0.1 is released with the following updates:TiDB: Support canceling DDL Job. Optimize the IN expression. Correct the result type of the Show statement. Support log slow query into a separate log file. Fix bugs. TiKV: Support flow control with write bytes. Reduce Raft allocation. Increase coprocessor stack size to 10MB. Remove the useless log from the coprocessor. "}, {"url": "https://pingcap.com/docs/v1.0/releases/101/", "title": "TiDB 1.0.1 Release Notes", "content": " TiDB 1.0.1 Release Notes On November 1, 2017, TiDB 1.0.1 is released with the following updates:TiDB: Support canceling DDL Job. Optimize the IN expression. Correct the result type of the Show statement. Support log slow query into a separate log file. Fix bugs. TiKV: Support flow control with write bytes. Reduce Raft allocation. Increase coprocessor stack size to 10MB. Remove the useless log from the coprocessor. "}, {"url": "https://pingcap.com/docs/v2.0/releases/101/", "title": "TiDB 1.0.1 Release Notes", "content": " TiDB 1.0.1 Release Notes On November 1, 2017, TiDB 1.0.1 is released with the following updates:TiDB: Support canceling DDL Job. Optimize the IN expression. Correct the result type of the Show statement. Support log slow query into a separate log file. Fix bugs. TiKV: Support flow control with write bytes. Reduce Raft allocation. Increase coprocessor stack size to 10MB. Remove the useless log from the coprocessor. "}, {"url": "https://pingcap.com/docs/releases/102/", "title": "TiDB 1.0.2 Release Notes", "content": " TiDB 1.0.2 Release Notes On November 13, 2017, TiDB 1.0.2 is released with the following updates:TiDB: Optimize the cost estimation of index point query Support the Alter Table Add Column (ColumnDef ColumnPosition) syntax Optimize the queries whose where conditions are contradictory Optimize the Add Index operation to rectify the progress and reduce repetitive operations Optimize the Index Look Join operator to accelerate the query speed for small data size Fix the issue with prefix index judgment Placement Driver (PD): Improve the stability of scheduling under exceptional situations TiKV: Support splitting table to ensure one region does not contain data from multiple tables Limit the length of a key to be no more than 4 KB More accurate read traffic statistics Implement deep protection on the coprocessor stack Fix the LIKE behavior and the do_div_mod bug "}, {"url": "https://pingcap.com/docs/v1.0/releases/102/", "title": "TiDB 1.0.2 Release Notes", "content": " TiDB 1.0.2 Release Notes On November 13, 2017, TiDB 1.0.2 is released with the following updates:TiDB: Optimize the cost estimation of index point query Support the Alter Table Add Column (ColumnDef ColumnPosition) syntax Optimize the queries whose where conditions are contradictory Optimize the Add Index operation to rectify the progress and reduce repetitive operations Optimize the Index Look Join operator to accelerate the query speed for small data size Fix the issue with prefix index judgment Placement Driver (PD): Improve the stability of scheduling under exceptional situations TiKV: Support splitting table to ensure one region does not contain data from multiple tables Limit the length of a key to be no more than 4 KB More accurate read traffic statistics Implement deep protection on the coprocessor stack Fix the LIKE behavior and the do_div_mod bug "}, {"url": "https://pingcap.com/docs/v2.0/releases/102/", "title": "TiDB 1.0.2 Release Notes", "content": " TiDB 1.0.2 Release Notes On November 13, 2017, TiDB 1.0.2 is released with the following updates:TiDB: Optimize the cost estimation of index point query Support the Alter Table Add Column (ColumnDef ColumnPosition) syntax Optimize the queries whose where conditions are contradictory Optimize the Add Index operation to rectify the progress and reduce repetitive operations Optimize the Index Look Join operator to accelerate the query speed for small data size Fix the issue with prefix index judgment Placement Driver (PD): Improve the stability of scheduling under exceptional situations TiKV: Support splitting table to ensure one region does not contain data from multiple tables Limit the length of a key to be no more than 4 KB More accurate read traffic statistics Implement deep protection on the coprocessor stack Fix the LIKE behavior and the do_div_mod bug "}, {"url": "https://pingcap.com/docs/releases/103/", "title": "TiDB 1.0.3 Release Notes", "content": " TiDB 1.0.3 Release Notes On November 28, 2017, TiDB 1.0.3 is released with the following updates:TiDB Optimize the performance in transaction conflicts scenario Add the TokenLimit option in the config file Output the default database in slow query logs Remove the DDL statement from query duration metrics Optimize the query cost estimation Fix the index prefix issue when creating tables Support pushing down the expressions for the Float type to TiKV Fix the issue that it is slow to add index for tables with discrete integer primary index Reduce the unnecessary statistics updates Fix a potential issue during the transaction retry PD Support adding more types of schedulers using API TiKV Fix the deadlock issue with the PD client Fix the issue that the wrong leader value is prompted for NotLeader Fix the issue that the chunk size is too large in the coprocessor To upgrade from 1.0.2 to 1.0.3, follow the rolling upgrade order of PD -> TiKV -> TiDB."}, {"url": "https://pingcap.com/docs/v1.0/releases/103/", "title": "TiDB 1.0.3 Release Notes", "content": " TiDB 1.0.3 Release Notes On November 28, 2017, TiDB 1.0.3 is released with the following updates:TiDB Optimize the performance in transaction conflicts scenario Add the TokenLimit option in the config file Output the default database in slow query logs Remove the DDL statement from query duration metrics Optimize the query cost estimation Fix the index prefix issue when creating tables Support pushing down the expressions for the Float type to TiKV Fix the issue that it is slow to add index for tables with discrete integer primary index Reduce the unnecessary statistics updates Fix a potential issue during the transaction retry PD Support adding more types of schedulers using API TiKV Fix the deadlock issue with the PD client Fix the issue that the wrong leader value is prompted for NotLeader Fix the issue that the chunk size is too large in the coprocessor To upgrade from 1.0.2 to 1.0.3, follow the rolling upgrade order of PD -> TiKV -> TiDB."}, {"url": "https://pingcap.com/docs/v2.0/releases/103/", "title": "TiDB 1.0.3 Release Notes", "content": " TiDB 1.0.3 Release Notes On November 28, 2017, TiDB 1.0.3 is released with the following updates:TiDB Optimize the performance in transaction conflicts scenario Add the TokenLimit option in the config file Output the default database in slow query logs Remove the DDL statement from query duration metrics Optimize the query cost estimation Fix the index prefix issue when creating tables Support pushing down the expressions for the Float type to TiKV Fix the issue that it is slow to add index for tables with discrete integer primary index Reduce the unnecessary statistics updates Fix a potential issue during the transaction retry PD Support adding more types of schedulers using API TiKV Fix the deadlock issue with the PD client Fix the issue that the wrong leader value is prompted for NotLeader Fix the issue that the chunk size is too large in the coprocessor To upgrade from 1.0.2 to 1.0.3, follow the rolling upgrade order of PD -> TiKV -> TiDB."}, {"url": "https://pingcap.com/docs/releases/104/", "title": "TiDB 1.0.4 Release Notes", "content": " TiDB 1.0.4 Release Notes On December 11, 2017, TiDB 1.0.4 is released with the following updates:TiDB Speed up the loading of the statistics when starting the tidb-server Improve the performance of the show variables statement Fix a potential issue when using the Add Index statement to handle the combined indexes Fix a potential issue when using the Rename Table statement to move a table to another database Accelerate the effectiveness for the Alter/Drop User statement TiKV Fix a possible performance issue when a snapshot is applied Fix the performance issue for reverse scan after removing a lot of data Fix the wrong encoded result for the Decimal type under special circumstances To upgrade from 1.0.3 to 1.0.4, follow the rolling upgrade order of PD -> TiKV -> TiDB."}, {"url": "https://pingcap.com/docs/v1.0/releases/104/", "title": "TiDB 1.0.4 Release Notes", "content": " TiDB 1.0.4 Release Notes On December 11, 2017, TiDB 1.0.4 is released with the following updates:TiDB Speed up the loading of the statistics when starting the tidb-server Improve the performance of the show variables statement Fix a potential issue when using the Add Index statement to handle the combined indexes Fix a potential issue when using the Rename Table statement to move a table to another database Accelerate the effectiveness for the Alter/Drop User statement TiKV Fix a possible performance issue when a snapshot is applied Fix the performance issue for reverse scan after removing a lot of data Fix the wrong encoded result for the Decimal type under special circumstances To upgrade from 1.0.3 to 1.0.4, follow the rolling upgrade order of PD -> TiKV -> TiDB."}, {"url": "https://pingcap.com/docs/v2.0/releases/104/", "title": "TiDB 1.0.4 Release Notes", "content": " TiDB 1.0.4 Release Notes On December 11, 2017, TiDB 1.0.4 is released with the following updates:TiDB Speed up the loading of the statistics when starting the tidb-server Improve the performance of the show variables statement Fix a potential issue when using the Add Index statement to handle the combined indexes Fix a potential issue when using the Rename Table statement to move a table to another database Accelerate the effectiveness for the Alter/Drop User statement TiKV Fix a possible performance issue when a snapshot is applied Fix the performance issue for reverse scan after removing a lot of data Fix the wrong encoded result for the Decimal type under special circumstances To upgrade from 1.0.3 to 1.0.4, follow the rolling upgrade order of PD -> TiKV -> TiDB."}, {"url": "https://pingcap.com/docs/releases/105/", "title": "TiDB 1.0.5 Release Notes", "content": " TiDB 1.0.5 Release Notes On December 26, 2017, TiDB 1.0.5 is released with the following updates:TiDB Add the max value for the current Auto_Increment ID in the Show Create Table statement. Fix a potential goroutine leak. Support outputting slow queries into a separate file. Load the TimeZone variable from TiKV when creating a new session. Support the schema state check so that the Show Create Tableand Analyze statements process the public table/index only. The set transaction read only should affect the tx_read_only variable. Clean up incremental statistic data when rolling back. Fix the issue of missing index length in the Show Create Table statement. PD Fix the issue that the leaders stop balancing under some circumstances. 869 874 Fix potential panic during bootstrapping. TiKV Fix the issue that it is slow to get the CPU ID using the get_cpuid function. Support the dynamic-level-bytes parameter to improve the space collection situation. To upgrade from 1.0.4 to 1.0.5, follow the rolling upgrade order of PD -> TiKV -> TiDB."}, {"url": "https://pingcap.com/docs/v1.0/releases/105/", "title": "TiDB 1.0.5 Release Notes", "content": " TiDB 1.0.5 Release Notes On December 26, 2017, TiDB 1.0.5 is released with the following updates:TiDB Add the max value for the current Auto_Increment ID in the Show Create Table statement. Fix a potential goroutine leak. Support outputting slow queries into a separate file. Load the TimeZone variable from TiKV when creating a new session. Support the schema state check so that the Show Create Tableand Analyze statements process the public table/index only. The set transaction read only should affect the tx_read_only variable. Clean up incremental statistic data when rolling back. Fix the issue of missing index length in the Show Create Table statement. PD Fix the issue that the leaders stop balancing under some circumstances. 869 874 Fix potential panic during bootstrapping. TiKV Fix the issue that it is slow to get the CPU ID using the get_cpuid function. Support the dynamic-level-bytes parameter to improve the space collection situation. To upgrade from 1.0.4 to 1.0.5, follow the rolling upgrade order of PD -> TiKV -> TiDB."}, {"url": "https://pingcap.com/docs/v2.0/releases/105/", "title": "TiDB 1.0.5 Release Notes", "content": " TiDB 1.0.5 Release Notes On December 26, 2017, TiDB 1.0.5 is released with the following updates:TiDB Add the max value for the current Auto_Increment ID in the Show Create Table statement. Fix a potential goroutine leak. Support outputting slow queries into a separate file. Load the TimeZone variable from TiKV when creating a new session. Support the schema state check so that the Show Create Tableand Analyze statements process the public table/index only. The set transaction read only should affect the tx_read_only variable. Clean up incremental statistic data when rolling back. Fix the issue of missing index length in the Show Create Table statement. PD Fix the issue that the leaders stop balancing under some circumstances. 869 874 Fix potential panic during bootstrapping. TiKV Fix the issue that it is slow to get the CPU ID using the get_cpuid function. Support the dynamic-level-bytes parameter to improve the space collection situation. To upgrade from 1.0.4 to 1.0.5, follow the rolling upgrade order of PD -> TiKV -> TiDB."}, {"url": "https://pingcap.com/docs/releases/106/", "title": "TiDB 1.0.6 Release Notes", "content": " TiDB 1.0.6 Release Notes On January 08, 2018, TiDB 1.0.6 is released with the following updates:TiDB: Support the Alter Table Auto_Increment syntax Fix the bug in Cost Based computation and the Null Json issue in statistics Support the extension syntax to shard the implicit row ID to avoid write hot spot for a single table Fix a potential DDL issue Consider the timezone setting in the curtime, sysdate and curdate functions Support the SEPARATOR syntax in the GROUP_CONCAT function Fix the wrong return type issue of the GROUP_CONCAT function. PD: Fix store selection problem of hot-region scheduler TiKV: None.To upgrade from 1.0.5 to 1.0.6, follow the rolling upgrade order of PD -> TiKV -> TiDB."}, {"url": "https://pingcap.com/docs/v1.0/releases/106/", "title": "TiDB 1.0.6 Release Notes", "content": " TiDB 1.0.6 Release Notes On January 08, 2018, TiDB 1.0.6 is released with the following updates:TiDB: Support the Alter Table Auto_Increment syntax Fix the bug in Cost Based computation and the Null Json issue in statistics Support the extension syntax to shard the implicit row ID to avoid write hot spot for a single table Fix a potential DDL issue Consider the timezone setting in the curtime, sysdate and curdate functions Support the SEPARATOR syntax in the GROUP_CONCAT function Fix the wrong return type issue of the GROUP_CONCAT function. PD: Fix store selection problem of hot-region scheduler TiKV: None.To upgrade from 1.0.5 to 1.0.6, follow the rolling upgrade order of PD -> TiKV -> TiDB."}, {"url": "https://pingcap.com/docs/v2.0/releases/106/", "title": "TiDB 1.0.6 Release Notes", "content": " TiDB 1.0.6 Release Notes On January 08, 2018, TiDB 1.0.6 is released with the following updates:TiDB: Support the Alter Table Auto_Increment syntax Fix the bug in Cost Based computation and the Null Json issue in statistics Support the extension syntax to shard the implicit row ID to avoid write hot spot for a single table Fix a potential DDL issue Consider the timezone setting in the curtime, sysdate and curdate functions Support the SEPARATOR syntax in the GROUP_CONCAT function Fix the wrong return type issue of the GROUP_CONCAT function. PD: Fix store selection problem of hot-region scheduler TiKV: None.To upgrade from 1.0.5 to 1.0.6, follow the rolling upgrade order of PD -> TiKV -> TiDB."}, {"url": "https://pingcap.com/docs/releases/107/", "title": "TiDB 1.0.7 Release Notes", "content": " TiDB 1.0.7 Release Notes On January 22, 2018, TiDB 1.0.7 is released with the following updates:TiDB: Optimize the FIELD_LIST command Fix data race of the information schema Avoid adding read-only statements to history Add the session variable to control the log query Fix the resource leak issue in statistics Fix the goroutine leak issue Add schema info API for the http status server Fix an issue about IndexJoin Update the behavior when RunWorker is false in DDL Improve the stability of test results in statistics Support PACK_KEYS syntax for the CREATE TABLE statement Add row_id column for the null pushdown schema to optimize performance PD: Fix possible scheduling loss issue in abnormal conditions Fix the compatibility issue with proto3 Add the log TiKV: Support Table Scan Support the remote mode in tikv-ctl Fix the format compatibility issue of tikv-ctl proto Fix the loss of scheduling command from PD Add timeout in Push metric To upgrade from 1.0.6 to 1.0.7, follow the rolling upgrade order of PD -> TiKV -> TiDB."}, {"url": "https://pingcap.com/docs/v1.0/releases/107/", "title": "TiDB 1.0.7 Release Notes", "content": " TiDB 1.0.7 Release Notes On January 22, 2018, TiDB 1.0.7 is released with the following updates:TiDB: Optimize the FIELD_LIST command Fix data race of the information schema Avoid adding read-only statements to history Add the session variable to control the log query Fix the resource leak issue in statistics Fix the goroutine leak issue Add schema info API for the http status server Fix an issue about IndexJoin Update the behavior when RunWorker is false in DDL Improve the stability of test results in statistics Support PACK_KEYS syntax for the CREATE TABLE statement Add row_id column for the null pushdown schema to optimize performance PD: Fix possible scheduling loss issue in abnormal conditions Fix the compatibility issue with proto3 Add the log TiKV: Support Table Scan Support the remote mode in tikv-ctl Fix the format compatibility issue of tikv-ctl proto Fix the loss of scheduling command from PD Add timeout in Push metric To upgrade from 1.0.6 to 1.0.7, follow the rolling upgrade order of PD -> TiKV -> TiDB."}, {"url": "https://pingcap.com/docs/v2.0/releases/107/", "title": "TiDB 1.0.7 Release Notes", "content": " TiDB 1.0.7 Release Notes On January 22, 2018, TiDB 1.0.7 is released with the following updates:TiDB: Optimize the FIELD_LIST command Fix data race of the information schema Avoid adding read-only statements to history Add the session variable to control the log query Fix the resource leak issue in statistics Fix the goroutine leak issue Add schema info API for the http status server Fix an issue about IndexJoin Update the behavior when RunWorker is false in DDL Improve the stability of test results in statistics Support PACK_KEYS syntax for the CREATE TABLE statement Add row_id column for the null pushdown schema to optimize performance PD: Fix possible scheduling loss issue in abnormal conditions Fix the compatibility issue with proto3 Add the log TiKV: Support Table Scan Support the remote mode in tikv-ctl Fix the format compatibility issue of tikv-ctl proto Fix the loss of scheduling command from PD Add timeout in Push metric To upgrade from 1.0.6 to 1.0.7, follow the rolling upgrade order of PD -> TiKV -> TiDB."}, {"url": "https://pingcap.com/docs/releases/108/", "title": "TiDB 1.0.8 Release Notes", "content": " TiDB 1.0.8 Release Notes On February 11, 2018, TiDB 1.0.8 is released with the following updates:TiDB: Fix issues in the Outer Join result in some scenarios Optimize the performance of the InsertIntoIgnore statement Fix the issue in the ShardRowID option Add limitation (Configurable, the default value is 5000) to the DML statements number within a transaction Fix an issue in the Table/Column aliases returned by the Prepare statement Fix an issue in updating statistics delta Fix a panic error in the Drop Column statement Fix an DML issue when running the Add Column After statement Improve the stability of the GC process by ignoring the regions with GC errors Run GC concurrently to accelerate the GC process Provide syntax support for the CREATE INDEX statement PD: Reduce the lock overheat of the region heartbeats Fix the issue that a hot region scheduler selects the wrong Leader TiKV: Use DeleteFilesInRanges to clear stale data and improve the TiKV starting speed Using Decimal in Coprocessor sum Sync the metadata of the received Snapshot compulsorily to ensure its safety To upgrade from 1.0.7 to 1.0.8, follow the rolling upgrade order of PD -> TiKV -> TiDB."}, {"url": "https://pingcap.com/docs/v1.0/releases/108/", "title": "TiDB 1.0.8 Release Notes", "content": " TiDB 1.0.8 Release Notes On February 11, 2018, TiDB 1.0.8 is released with the following updates:TiDB: Fix issues in the Outer Join result in some scenarios Optimize the performance of the InsertIntoIgnore statement Fix the issue in the ShardRowID option Add limitation (Configurable, the default value is 5000) to the DML statements number within a transaction Fix an issue in the Table/Column aliases returned by the Prepare statement Fix an issue in updating statistics delta Fix a panic error in the Drop Column statement Fix an DML issue when running the Add Column After statement Improve the stability of the GC process by ignoring the regions with GC errors Run GC concurrently to accelerate the GC process Provide syntax support for the CREATE INDEX statement PD: Reduce the lock overheat of the region heartbeats Fix the issue that a hot region scheduler selects the wrong Leader TiKV: Use DeleteFilesInRanges to clear stale data and improve the TiKV starting speed Using Decimal in Coprocessor sum Sync the metadata of the received Snapshot compulsorily to ensure its safety To upgrade from 1.0.7 to 1.0.8, follow the rolling upgrade order of PD -> TiKV -> TiDB."}, {"url": "https://pingcap.com/docs/v2.0/releases/108/", "title": "TiDB 1.0.8 Release Notes", "content": " TiDB 1.0.8 Release Notes On February 11, 2018, TiDB 1.0.8 is released with the following updates:TiDB: Fix issues in the Outer Join result in some scenarios Optimize the performance of the InsertIntoIgnore statement Fix the issue in the ShardRowID option Add limitation (Configurable, the default value is 5000) to the DML statements number within a transaction Fix an issue in the Table/Column aliases returned by the Prepare statement Fix an issue in updating statistics delta Fix a panic error in the Drop Column statement Fix an DML issue when running the Add Column After statement Improve the stability of the GC process by ignoring the regions with GC errors Run GC concurrently to accelerate the GC process Provide syntax support for the CREATE INDEX statement PD: Reduce the lock overheat of the region heartbeats Fix the issue that a hot region scheduler selects the wrong Leader TiKV: Use DeleteFilesInRanges to clear stale data and improve the TiKV starting speed Using Decimal in Coprocessor sum Sync the metadata of the received Snapshot compulsorily to ensure its safety To upgrade from 1.0.7 to 1.0.8, follow the rolling upgrade order of PD -> TiKV -> TiDB."}, {"url": "https://pingcap.com/docs-cn/releases/11alpha/", "title": "TiDB 1.1 Alpha Release Notes", "content": " TiDB 1.1 Alpha Release Notes 2018 年 1 月 19 日,TiDB 发布 1.1 Alpha 版。该版本对 MySQL 兼容性、SQL 优化器、系统稳定性、性能做了大量的工作。TiDB: SQL parser 兼容更多语法 SQL 查询优化器 统计信息减小内存占用 优化统计信息启动时载入的时间 更精确的代价估算 使用 Count-Min Sketch 更精确地估算点查的代价 支持更复杂的条件,更充分使用索引 SQL 执行器 使用 Chunk 结构重构所有执行器算子,提升分析型语句执行性能,减少内存占用 优化 INSERT IGNORE 语句性能 下推更多的类型和函数 支持更多的 SQL_MODE 优化 Load Data 性能,速度提升 10 倍 优化 Use Database 性能 支持对物理算子内存使用进行统计 Server 支持 PROXY protocol PD: 增加更多的 API 支持 TLS 给 Simulator 增加更多的 case 调度适应不同的 Region size Fix 了一些调度的 bug TiKV: 支持 Raft learner 优化 Raft Snapshot,减少 I/O 开销 支持 TLS 优化 RocksDB 配置,提升性能 优化 Coprocessor count (*) 和点查 unique index 的性能 增加更多的 Failpoint 以及稳定性测试 case 解决 PD 和 TiKV 之间重连的问题 增强数据恢复工具 tikv-ctl 的功能 Region 支持按 table 进行分裂 支持 Delete Range 功能 支持设置 snapshot 导致的 I/O 上限 完善流控机制 "}, {"url": "https://pingcap.com/docs-cn/v1.0/releases/11alpha/", "title": "TiDB 1.1 Alpha Release Notes", "content": " TiDB 1.1 Alpha Release Notes 2018 年 1 月 19 日,TiDB 发布 1.1 Alpha 版。该版本对 MySQL 兼容性、SQL 优化器、系统稳定性、性能做了大量的工作。TiDB: SQL parser 兼容更多语法 SQL 查询优化器 统计信息减小内存占用 优化统计信息启动时载入的时间 更精确的代价估算 使用 Count-Min Sketch 更精确地估算点查的代价 支持更复杂的条件,更充分使用索引 SQL 执行器 使用 Chunk 结构重构所有执行器算子,提升分析型语句执行性能,减少内存占用 优化 INSERT INGORE 语句性能 下推更多的类型和函数 支持更多的 SQL_MODE 优化 Load Data 性能,速度提升 10 倍 优化 Use Database 性能 支持对物理算子内存使用进行统计 Server 支持 PROXY protocol PD: 增加更多的 API 支持 TLS 给 Simulator 增加更多的 case 调度适应不同的 Region size Fix 了一些调度的 bug TiKV: 支持 Raft learner 优化 Raft Snapshot,减少 IO 开销 支持 TLS 优化 RocksDB 配置,提升性能 优化 Coprocessor count (*) 和点查 unique index 的性能 增加更多的 Failpoint 以及稳定性测试 case 解决 PD 和 TiKV 之间重连的问题 增强数据恢复工具 TiKV-CTL 的功能 Region 支持按 table 进行分裂 支持 Delete Range 功能 支持设置 snapshot 导致的 IO 上限 完善流控机制 "}, {"url": "https://pingcap.com/docs-cn/v2.0/releases/11alpha/", "title": "TiDB 1.1 Alpha Release Notes", "content": " TiDB 1.1 Alpha Release Notes 2018 年 1 月 19 日,TiDB 发布 1.1 Alpha 版。该版本对 MySQL 兼容性、SQL 优化器、系统稳定性、性能做了大量的工作。TiDB: SQL parser 兼容更多语法 SQL 查询优化器 统计信息减小内存占用 优化统计信息启动时载入的时间 更精确的代价估算 使用 Count-Min Sketch 更精确地估算点查的代价 支持更复杂的条件,更充分使用索引 SQL 执行器 使用 Chunk 结构重构所有执行器算子,提升分析型语句执行性能,减少内存占用 优化 INSERT INGORE 语句性能 下推更多的类型和函数 支持更多的 SQL_MODE 优化 Load Data 性能,速度提升 10 倍 优化 Use Database 性能 支持对物理算子内存使用进行统计 Server 支持 PROXY protocol PD: 增加更多的 API 支持 TLS 给 Simulator 增加更多的 case 调度适应不同的 Region size Fix 了一些调度的 bug TiKV: 支持 Raft learner 优化 Raft Snapshot,减少 IO 开销 支持 TLS 优化 RocksDB 配置,提升性能 优化 Coprocessor count (*) 和点查 unique index 的性能 增加更多的 Failpoint 以及稳定性测试 case 解决 PD 和 TiKV 之间重连的问题 增强数据恢复工具 TiKV-CTL 的功能 Region 支持按 table 进行分裂 支持 Delete Range 功能 支持设置 snapshot 导致的 IO 上限 完善流控机制 "}, {"url": "https://pingcap.com/docs/releases/11alpha/", "title": "TiDB 1.1 Alpha Release Notes", "content": " TiDB 1.1 Alpha Release Notes On January 19, 2018, TiDB 1.1 Alpha is released. This release has great improvement in MySQL compatibility, SQL optimization, stability, and performance.TiDB: SQL parser Support more syntax SQL query optimizer Use more compact structure to reduce statistics info memory usage Speed up loading statistics info when starting tidb-server Provide more accurate query cost evaluation Use Count-Min Sketch to estimate the cost of queries using unique index more accurately Support more complex conditions to make full use of index SQL executor Refactor all executor operators using Chunk architecture, improve the execution performance of analytical statements and reduce memory usage Optimize performance of the INSERT IGNORE statement Push down more types and functions to TiKV Support more SQL_MODE Optimize the Load Data performance to increase the speed by 10 times Optimize the Use Database performance Support statistics on the memory usage of physical operators Server Support the PROXY protocol PD: Add more APIs Support TLS Add more cases for scheduling Simulator Schedule to adapt to different Region sizes Fix some bugs about scheduling TiKV: Support Raft learner Optimize Raft Snapshot and reduce the I/O overhead Support TLS Optimize the RocksDB configuration to improve performance Optimize count (*) and query performance of unique index in Coprocessor Add more failpoints and stability test cases Solve the reconnection issue between PD and TiKV Enhance the features of the data recovery tool tikv-ctl Support splitting according to table in Region Support the Delete Range feature Support setting the I/O limit caused by snapshot Improve the flow control mechanism "}, {"url": "https://pingcap.com/docs/v1.0/releases/11alpha/", "title": "TiDB 1.1 Alpha Release Notes", "content": " TiDB 1.1 Alpha Release Notes On January 19, 2018, TiDB 1.1 Alpha is released. This release has great improvement in MySQL compatibility, SQL optimization, stability, and performance.TiDB: SQL parser Support more syntax SQL query optimizer Use more compact structure to reduce statistics info memory usage Speed up loading statistics info when starting tidb-server Provide more accurate query cost evaluation Use Count-Min Sketch to evaluate the cost of queries using unique index more accurately Support more complex conditions to make full use of index SQL executor Refactor all executor operators using Chunk architecture, improve the execution performance of analytical statements and reduce memory usage Optimize performance of the INSERT INGORE statement Push down more types and functions to TiKV Support more SQL_MODE Optimize the Load Data performance to increase the speed by 10 times Optimize the Use Database performance Support statistics on the memory usage of physical operators Server Support the PROXY protocol PD: Add more APIs Support TLS Add more cases for scheduling Simulator Schedule to adapt to different Region sizes Fix some bugs about scheduling TiKV: Support Raft learner Optimize Raft Snapshot and reduce the IO overhead Support TLS Optimize the RocksDB configuration to improve performance Optimize count (*) and query performance of unique index in Coprocessor Add more failpoints and stability test cases Solve the reconnection issue between PD and TiKV Enhance the features of the data recovery tool TiKV-CTL Support splitting according to table in Region Support the Delete Range feature Support setting the IO limit caused by snapshot Improve the flow control mechanism "}, {"url": "https://pingcap.com/docs/v2.0/releases/11alpha/", "title": "TiDB 1.1 Alpha Release Notes", "content": " TiDB 1.1 Alpha Release Notes On January 19, 2018, TiDB 1.1 Alpha is released. This release has great improvement in MySQL compatibility, SQL optimization, stability, and performance.TiDB: SQL parser Support more syntax SQL query optimizer Use more compact structure to reduce statistics info memory usage Speed up loading statistics info when starting tidb-server Provide more accurate query cost evaluation Use Count-Min Sketch to estimate the cost of queries using unique index more accurately Support more complex conditions to make full use of index SQL executor Refactor all executor operators using Chunk architecture, improve the execution performance of analytical statements and reduce memory usage Optimize performance of the INSERT IGNORE statement Push down more types and functions to TiKV Support more SQL_MODE Optimize the Load Data performance to increase the speed by 10 times Optimize the Use Database performance Support statistics on the memory usage of physical operators Server Support the PROXY protocol PD: Add more APIs Support TLS Add more cases for scheduling Simulator Schedule to adapt to different Region sizes Fix some bugs about scheduling TiKV: Support Raft learner Optimize Raft Snapshot and reduce the I/O overhead Support TLS Optimize the RocksDB configuration to improve performance Optimize count (*) and query performance of unique index in Coprocessor Add more failpoints and stability test cases Solve the reconnection issue between PD and TiKV Enhance the features of the data recovery tool tikv-ctl Support splitting according to table in Region Support the Delete Range feature Support setting the I/O limit caused by snapshot Improve the flow control mechanism "}, {"url": "https://pingcap.com/docs-cn/releases/11beta/", "title": "TiDB 1.1 Beta Release Notes", "content": " TiDB 1.1 Beta Release Notes 2018 年 2 月 24 日,TiDB 发布 1.1 Beta 版。该版本在 1.1 Alpha 版的基础上,对 MySQL 兼容性、系统稳定性做了很多改进。TiDB 添加更多监控项, 优化日志 兼容更多 MySQL 语法 在 information_schema 中支持显示建表时间 提速包含 MaxOneRow 算子的查询 控制 Join 产生的中间结果集大小,进一步减少 Join 的内存使用 增加 tidb_config session 变量,输出当前 TiDB 配置 修复 Union 和 Index Join 算子中遇到的 panic 问题 修复 Sort Merge Join 算子在部分场景下结果错误的问题 修复 Show Index 语句显示正在添加过程中的索引的问题 修复 Drop Stats 语句失败的问题 优化 SQL 引擎查询性能,Sysbench 的 Select/OLTP 测试结果提升 10% 使用新的执行引擎提升优化器中的子查询计算速度;相比 1.0 版本,在 TPC-H 以及 TPC-DS 等测试中有显著提升 PD 增加 Drop Region 调试接口 支持设置 PD leader 优先级 支持配置特定 label 的节点不调度 Raft leader 增加枚举各个 PD health 状态的接口 添加更多 metrics PD leader 尽量与 etcd leader 保持同步 提高 TiKV 宕机时数据恢复优先级和恢复速度 完善 data-dir 配置项的合法性较验 优化 Region heartbeat 性能 修复热点调度破坏 label 约束的问题 其他稳定性问题修复 TiKV 使用 offset + limit 遍历 lock,消除潜在的 GC 问题 支持批量 resolve lock,提升 GC 速度 支持并行 GC,提升 GC 速度 使用 RocksDB compaction listener 更新 Region Size,让 PD 更精确的进行调度 使用 DeleteFilesInRanges 批量删除过期数据,提高 TiKV 启动速度 设置 Raft snapshot max size,防止遗留文件占用太多空间 tikv-ctl 支持更多修复操作 优化有序流式聚合操作 完善 metrics,修复 bug "}, {"url": "https://pingcap.com/docs-cn/v1.0/releases/11beta/", "title": "TiDB 1.1 Beta Release Notes", "content": " TiDB 1.1 Beta Release Notes 2018 年 2 月 24 日,TiDB 发布 1.1 Beta 版。该版本在 1.1 Alpha 版的基础上,对 MySQL 兼容性、系统稳定性做了很多改进。TiDB 添加更多监控项, 优化日志 兼容更多 MySQL 语法 在 information_schema 中支持显示建表时间 提速包含 MaxOneRow 算子的查询 控制 Join 产生的中间结果集大小,进一步减少 Join 的内存使用 增加 tidb_config session 变量,输出当前 TiDB 配置 修复 Union 和 Index Join 算子中遇到的 panic 问题 修复 Sort Merge Join 算子在部分场景下结果错误的问题 修复 Show Index 语句显示正在添加过程中的索引的问题 修复 Drop Stats 语句失败的问题 优化 SQL 引擎查询性能,Sysbench 的 Select/OLTP 测试结果提升 10% 使用新的执行引擎提升优化器中的子查询计算速度;相比 1.0 版本,在 TPC-H 以及 TPC-DS 等测试中有显著提升 PD 增加 Drop Region 调试接口 支持设置 PD leader 优先级 支持配置特定 label 的节点不调度 Raft leader 增加枚举各个 PD health 状态的接口 添加更多 metrics PD leader 尽量与 etcd leader 保持同步 提高 TiKV 宕机时数据恢复优先级和恢复速度 完善 data-dir 配置项的合法性较验 优化 Region heartbeat 性能 修复热点调度破坏 label 约束的问题 其他稳定性问题修复 TiKV 使用 offset + limit 遍历 lock,消除潜在的 GC 问题 支持批量 resolve lock,提升 GC 速度 支持并行 GC,提升 GC 速度 使用 RocksDB compaction listener 更新 Region Size,让 PD 更精确的进行调度 使用 DeleteFilesInRanges 批量删除过期数据,提高 TiKV 启动速度 设置 Raft snapshot max size,防止遗留文件占用太多空间 tikv-ctl 支持更多修复操作 优化有序流式聚合操作 完善 metrics,修复 bug "}, {"url": "https://pingcap.com/docs-cn/v2.0/releases/11beta/", "title": "TiDB 1.1 Beta Release Notes", "content": " TiDB 1.1 Beta Release Notes 2018 年 2 月 24 日,TiDB 发布 1.1 Beta 版。该版本在 1.1 Alpha 版的基础上,对 MySQL 兼容性、系统稳定性做了很多改进。TiDB 添加更多监控项, 优化日志 兼容更多 MySQL 语法 在 information_schema 中支持显示建表时间 提速包含 MaxOneRow 算子的查询 控制 Join 产生的中间结果集大小,进一步减少 Join 的内存使用 增加 tidb_config session 变量,输出当前 TiDB 配置 修复 Union 和 Index Join 算子中遇到的 panic 问题 修复 Sort Merge Join 算子在部分场景下结果错误的问题 修复 Show Index 语句显示正在添加过程中的索引的问题 修复 Drop Stats 语句失败的问题 优化 SQL 引擎查询性能,Sysbench 的 Select/OLTP 测试结果提升 10% 使用新的执行引擎提升优化器中的子查询计算速度;相比 1.0 版本,在 TPC-H 以及 TPC-DS 等测试中有显著提升 PD 增加 Drop Region 调试接口 支持设置 PD leader 优先级 支持配置特定 label 的节点不调度 Raft leader 增加枚举各个 PD health 状态的接口 添加更多 metrics PD leader 尽量与 etcd leader 保持同步 提高 TiKV 宕机时数据恢复优先级和恢复速度 完善 data-dir 配置项的合法性较验 优化 Region heartbeat 性能 修复热点调度破坏 label 约束的问题 其他稳定性问题修复 TiKV 使用 offset + limit 遍历 lock,消除潜在的 GC 问题 支持批量 resolve lock,提升 GC 速度 支持并行 GC,提升 GC 速度 使用 RocksDB compaction listener 更新 Region Size,让 PD 更精确的进行调度 使用 DeleteFilesInRanges 批量删除过期数据,提高 TiKV 启动速度 设置 Raft snapshot max size,防止遗留文件占用太多空间 tikv-ctl 支持更多修复操作 优化有序流式聚合操作 完善 metrics,修复 bug "}, {"url": "https://pingcap.com/docs/releases/11beta/", "title": "TiDB 1.1 Beta Release Notes", "content": " TiDB 1.1 Beta Release Notes On February 24, 2018, TiDB 1.1 Beta is released. This release has great improvement in MySQL compatibility, SQL optimization, stability, and performance.TiDB: Add more monitoring metrics and refine the log Compatible with more MySQL syntax Support displaying the table creating time in information_schema Optimize queries containing the MaxOneRow operator Configure the size of intermediate result sets generated by Join, to further reduce the memory used by Join Add the tidb_config session variable to output the current TiDB configuration Fix the panic issue in the Union and Index Join operators Fix the wrong result issue of the Sort Merge Join operator in some scenarios Fix the issue that the Show Index statement shows indexes that are in the process of adding Fix the failure of the Drop Stats statement Optimize the query performance of the SQL engine to improve the test result of the Sysbench Select/OLTP by 10% Improve the computing speed of subqueries in the optimizer using the new execution engine; compared with TiDB 1.0, TiDB 1.1 Beta has great improvement in tests like TPC-H and TPC-DS PD: Add the Drop Region debug interface Support setting priority of the PD leader Support configuring stores with a specific label not to schedule Raft leaders Add the interfaces to enumerate the health status of each PD Add more metrics Keep the PD leader and the etcd leader together as much as possible in the same node Improve the priority and speed of restoring data when TiKV goes down Enhance the validity check of the data-dir configuration item Optimize the performance of Region heartbeat Fix the issue that hot spot scheduling violates label constraint Fix other stability issues TiKV: Traverse locks using offset + limit to avoid potential GC problems Support resolving locks in batches to improve GC speed Support GC concurrency to improve GC speed Update the Region size using the RocksDB compaction listener for more accurate PD scheduling Delete the outdated data in batches using DeleteFilesInRanges, to make TiKV start faster Configure the Raft snapshot max size to avoid the retained files taking up too much space Support more recovery operations in tikv-ctl Optimize the ordered flow aggregation operation Improve metrics and fix bugs "}, {"url": "https://pingcap.com/docs/v1.0/releases/11beta/", "title": "TiDB 1.1 Beta Release Notes", "content": " TiDB 1.1 Beta Release Notes On February 24, 2018, TiDB 1.1 Beta is released. This release has great improvement in MySQL compatibility, SQL optimization, stability, and performance.TiDB: Add more monitoring metrics and refine the log Compatible with more MySQL syntax Support displaying the table creating time in information_schema Optimize queries containing the MaxOneRow operator Configure the size of intermediate result sets generated by Join, to further reduce the memory used by Join Add the tidb_config session variable to output the current TiDB configuration Fix the panic issue in the Union and Index Join operators Fix the wrong result issue of the Sort Merge Join operator in some scenarios Fix the issue that the Show Index statement shows indexes that are in the process of adding Fix the failure of the Drop Stats statement Optimize the query performance of the SQL engine to improve the test result of the Sysbench Select/OLTP by 10% Improve the computing speed of subqueries in the optimizer using the new execution engine; compared with TiDB 1.0, TiDB 1.1 Beta has great improvement in tests like TPC-H and TPC-DS PD: Add the Drop Region debug interface Support setting priority of the PD leader Support configuring stores with a specific label not to schedule Raft leaders Add the interfaces to enumerate the health status of each PD Add more metrics Keep the PD leader and the etcd leader together as much as possible in the same node Improve the priority and speed of restoring data when TiKV goes down Enhance the validity check of the data-dir configuration item Optimize the performance of Region heartbeat Fix the issue that hot spot scheduling violates label constraint Fix other stability issues TiKV: Traverse locks using offset + limit to avoid potential GC problems Support resolving locks in batches to improve GC speed Support GC concurrency to improve GC speed Update the Region size using the RocksDB compaction listener for more accurate PD scheduling Delete the outdated data in batches using DeleteFilesInRanges, to make TiKV start faster Configure the Raft snapshot max size to avoid the retained files taking up too much space Support more recovery operations in tikv-ctl Optimize the ordered flow aggregation operation Improve metrics and fix bugs "}, {"url": "https://pingcap.com/docs/v2.0/releases/11beta/", "title": "TiDB 1.1 Beta Release Notes", "content": " TiDB 1.1 Beta Release Notes On February 24, 2018, TiDB 1.1 Beta is released. This release has great improvement in MySQL compatibility, SQL optimization, stability, and performance.TiDB: Add more monitoring metrics and refine the log Compatible with more MySQL syntax Support displaying the table creating time in information_schema Optimize queries containing the MaxOneRow operator Configure the size of intermediate result sets generated by Join, to further reduce the memory used by Join Add the tidb_config session variable to output the current TiDB configuration Fix the panic issue in the Union and Index Join operators Fix the wrong result issue of the Sort Merge Join operator in some scenarios Fix the issue that the Show Index statement shows indexes that are in the process of adding Fix the failure of the Drop Stats statement Optimize the query performance of the SQL engine to improve the test result of the Sysbench Select/OLTP by 10% Improve the computing speed of subqueries in the optimizer using the new execution engine; compared with TiDB 1.0, TiDB 1.1 Beta has great improvement in tests like TPC-H and TPC-DS PD: Add the Drop Region debug interface Support setting priority of the PD leader Support configuring stores with a specific label not to schedule Raft leaders Add the interfaces to enumerate the health status of each PD Add more metrics Keep the PD leader and the etcd leader together as much as possible in the same node Improve the priority and speed of restoring data when TiKV goes down Enhance the validity check of the data-dir configuration item Optimize the performance of Region heartbeat Fix the issue that hot spot scheduling violates label constraint Fix other stability issues TiKV: Traverse locks using offset + limit to avoid potential GC problems Support resolving locks in batches to improve GC speed Support GC concurrency to improve GC speed Update the Region size using the RocksDB compaction listener for more accurate PD scheduling Delete the outdated data in batches using DeleteFilesInRanges, to make TiKV start faster Configure the Raft snapshot max size to avoid the retained files taking up too much space Support more recovery operations in tikv-ctl Optimize the ordered flow aggregation operation Improve metrics and fix bugs "}, {"url": "https://pingcap.com/docs-cn/releases/2rc1/", "title": "TiDB 2.0 RC1 Release Notes", "content": " TiDB 2.0 RC1 Release Notes 2018 年 3 月 9 日,TiDB 发布 2.0 RC1 版。该版本在上一版的基础上,对 MySQL 兼容性、系统稳定性和优化器做了很多改进。TiDB 支持限制单条 SQL 语句使用内存的大小,减少程序 OOM 风险 支持下推流式聚合算子到 TiKV 支持配置文件的合法性检测 支持 HTTP API 获取 TiDB 参数信息 Parser 兼容更多 MySQL 语法 提升对 Navicat 的兼容性 优化器提升,提取多个 OR 条件的公共表达式,选取更优执行计划 优化器提升,在更多场景下将子查询转换成 Join 算子,选取更优查询计划 使用 Batch 方式 Resolve Lock,提升垃圾回收速度 修复 Boolean 类型的字段长度,提升兼容性 优化 Add Index 操作,所有的读写操作采用低优先级,减小对在线业务的影响 PD 优化检查 Region 状态的代码逻辑,提升程序性能 优化异常情况下日志信息输出,便于调试 修复监控中关于 TiKV 节点磁盘空间不足情况的统计 修复开启 TLS 时健康检查接口误报的问题 修复同时添加副本数量可能超过配置阈值的问题,提升程序稳定性 TiKV 修复 PD leader 切换,gRPC call 没被 cancel 的问题 对重要配置进行保护,第一次设置之后不允许变更 增加获取 metrics 的 gRPC API 启动时候,检查是否使用 SSD 使用 ReadPool 优化读性能,raw get 测试性能提升 30% 完善 metrics,优化 metrics 的使用 "}, {"url": "https://pingcap.com/docs-cn/v2.0/releases/2rc1/", "title": "TiDB 2.0 RC1 Release Notes", "content": " TiDB 2.0 RC1 Release Notes 2018 年 3 月 9 日,TiDB 发布 2.0 RC1 版。该版本在上一版的基础上,对 MySQL 兼容性、系统稳定性和优化器做了很多改进。TiDB 支持限制单条 SQL 语句使用内存的大小,减少程序 OOM 风险 支持下推流式聚合算子到 TiKV 支持配置文件的合法性检测 支持 HTTP API 获取 TiDB 参数信息 Parser 兼容更多 MySQL 语法 提升对 Navicat 的兼容性 优化器提升,提取多个 OR 条件的公共表达式,选取更优执行计划 优化器提升,在更多场景下将子查询转换成 Join 算子,选取更优查询计划 使用 Batch 方式 Resolve Lock,提升垃圾回收速度 修复 Boolean 类型的字段长度,提升兼容性 优化 Add Index 操作,所有的读写操作采用低优先级,减小对在线业务的影响 PD 优化检查 Region 状态的代码逻辑,提升程序性能 优化异常情况下日志信息输出,便于调试 修复监控中关于 TiKV 节点磁盘空间不足情况的统计 修复开启 TLS 时健康检查接口误报的问题 修复同时添加副本数量可能超过配置阈值的问题,提升程序稳定性 TiKV 修复 PD leader 切换,gRPC call 没被 cancel 的问题 对重要配置进行保护,第一次设置之后不允许变更 增加获取 metrics 的 gRPC API 启动时候,检查是否使用 SSD 使用 ReadPool 优化读性能,raw get 测试性能提升 30% 完善 metrics,优化 metrics 的使用 "}, {"url": "https://pingcap.com/docs/releases/2rc1/", "title": "TiDB 2.0 RC1 Release Notes", "content": " TiDB 2.0 RC1 Release Notes On March 9, 2018, TiDB 2.0 RC1 is released. This release has great improvement in MySQL compatibility, SQL optimization and stability.TiDB: Support limiting the memory usage by a single SQL statement, to reduce the risk of OOM Support pushing the Stream Aggregate operator down to TiKV Support validating the configuration file Support obtaining the information of TiDB configuration through HTTP API Compatible with more MySQL syntax in Parser Improve the compatibility with Navicat Improve the optimizer and extract common expressions with multiple OR conditions, to choose better query plan Improve the optimizer and convert subqueries to Join operators in more scenarios, to choose better query plan Resolve Lock in the Batch mode to increase the garbage collection speed Fix the length of Boolean field to improve compatibility Optimize the Add Index operation and give lower priority to all write and read operations, to reduce the impact on online business PD: Optimize the logic of code used to check the Region status to improve performance Optimize the output of log information in abnormal conditions to facilitate debugging Fix the monitor statistics that the disk space of TiKV nodes is not enough Fix the wrong reporting issue of the health interface when TLS is enabled Fix the issue that concurrent addition of replicas might exceed the threshold value of configuration, to improve stability TiKV: Fix the issue that gRPC call is not cancelled when PD leaders switch Protect important configuration which cannot be changed after initial configuration Add gRPC APIs used to obtain metrics Check whether SSD is used when you start the cluster Optimize the read performance using ReadPool, and improve the performance by 30% in the raw get test Improve metrics and optimize the usage of metrics "}, {"url": "https://pingcap.com/docs/v1.0/releases/2rc1/", "title": "TiDB 2.0 RC1 Release Notes", "content": " TiDB 2.0 RC1 Release Notes On March 9, 2018, TiDB 2.0 RC1 is released. This release has great improvement in MySQL compatibility, SQL optimization and stability.TiDB: Support limiting the memory usage by a single SQL statement, to reduce the risk of OOM Support pushing the Stream Aggregate operator down to TiKV Support validating the configuration file Support obtaining the information of TiDB configuration through HTTP API Compatible with more MySQL syntax in Parser Improve the compatibility with Navicat Improve the optimizer and extract common expressions with multiple OR conditions, to choose better query plan Improve the optimizer and convert subqueries to Join operators in more scenarios, to choose better query plan Resolve Lock in the Batch mode to increase the garbage collection speed Fix the length of Boolean field to improve compatibility Optimize the Add Index operation and give lower priority to all write and read operations, to reduce the impact on online business PD: Optimize the logic of code used to check the Region status to improve performance Optimize the output of log information in abnormal conditions to facilitate debugging Fix the monitor statistics that the disk space of TiKV nodes is not enough Fix the wrong reporting issue of the health interface when TLS is enabled Fix the issue that concurrent addition of replicas might exceed the threshold value of configuration, to improve stability TiKV: Fix the issue that gRPC call is not cancelled when PD leaders switch Protect important configuration which cannot be changed after initial configuration Add gRPC APIs used to obtain metrics Check whether SSD is used when you start the cluster Optimize the read performance using ReadPool, and improve the performance by 30% in the raw get test Improve metrics and optimize the usage of metrics "}, {"url": "https://pingcap.com/docs/v2.0/releases/2rc1/", "title": "TiDB 2.0 RC1 Release Notes", "content": " TiDB 2.0 RC1 Release Notes On March 9, 2018, TiDB 2.0 RC1 is released. This release has great improvement in MySQL compatibility, SQL optimization and stability.TiDB: Support limiting the memory usage by a single SQL statement, to reduce the risk of OOM Support pushing the Stream Aggregate operator down to TiKV Support validating the configuration file Support obtaining the information of TiDB configuration through HTTP API Compatible with more MySQL syntax in Parser Improve the compatibility with Navicat Improve the optimizer and extract common expressions with multiple OR conditions, to choose better query plan Improve the optimizer and convert subqueries to Join operators in more scenarios, to choose better query plan Resolve Lock in the Batch mode to increase the garbage collection speed Fix the length of Boolean field to improve compatibility Optimize the Add Index operation and give lower priority to all write and read operations, to reduce the impact on online business PD: Optimize the logic of code used to check the Region status to improve performance Optimize the output of log information in abnormal conditions to facilitate debugging Fix the monitor statistics that the disk space of TiKV nodes is not enough Fix the wrong reporting issue of the health interface when TLS is enabled Fix the issue that concurrent addition of replicas might exceed the threshold value of configuration, to improve stability TiKV: Fix the issue that gRPC call is not cancelled when PD leaders switch Protect important configuration which cannot be changed after initial configuration Add gRPC APIs used to obtain metrics Check whether SSD is used when you start the cluster Optimize the read performance using ReadPool, and improve the performance by 30% in the raw get test Improve metrics and optimize the usage of metrics "}, {"url": "https://pingcap.com/docs-cn/releases/2rc3/", "title": "TiDB 2.0 RC3 Release Notes", "content": " TiDB 2.0 RC3 Release Notes 2018 年 3 月 23 日,TiDB 发布 2.0 RC3 版。该版本在 2.0 RC2 版的基础上,对 MySQL 兼容性、系统稳定性和优化器做了很多改进。TiDB 修复部分场景下 MAX/MIN 结果不正确的问题 修复部分场景下 Sort Merge Join 结果未按照 Join Key 有序的问题 修复边界条件下 uint 和 int 比较的错误 完善浮点数类型的长度和精度检查,提升 MySQL 兼容性 完善时间类型解析报错日志,添加更多错误信息 完善内存控制,新增对 IndexLookupExecutor 的内存统计 优化 ADD INDEX 的执行速度,部分场景下速度大幅度提升 GROUP BY 子句为空时使用 Stream Aggregation 算子,提升速度 支持通过 STRAIGHT_JOIN 来关闭优化器的 Join Reorder 优化 ADMIN SHOW DDL JOBS 输出更详细的 DDL 任务状态信息 支持 ADMIN SHOW DDL JOB QUERIES 查询当前正在运行的 DDL 任务的原始语句 支持 ADMIN RECOVER INDEX 命令,用于灾难恢复情况下修复索引数据 ADD INDEX 操作变更为低优先级,降低对线上业务影响 支持参数为 JSON 类型的 SUM/AVG 等聚合函数 支持配置文件修改 lower_case_table_names 系统变量,用于支持 OGG 数据同步工具 提升对 Navicat 管理工具的兼容性 支持在 CRUD 操作中使用隐式的行 ID PD 支持 Region Merge,合并数据删除后产生的空 Region 或小 Region 添加副本时忽略有大量 pending peer 的节点,提升恢复副本及下线的速度 优化有大量空 Region 时产生的频繁调度问题 优化不同 label 中资源不均衡的场景中 leader balance 调度的速度 添加更多异常 Region 的统计 TiKV 支持 Region Merge Raft snapshot 流程完成之后立刻通知 PD,加速调度 增加 Raw DeleteRange API 增加 GetMetric API 减缓 RocksDB sync 文件造成的 I/O 波动 优化了对 delete 掉数据的空间回收机制 完善数据恢复工具 tikv-ctl 解决了由于 snapshot 导致下线节点慢的问题 Coprocessor 支持 streaming 支持 Readpool,raw_get/get/batch_get 性能提升 30% 支持配置 Coprocessor 请求超时时间 Coprocessor 支持 streaming aggregation 上报 Region heartbeat 时携带时间信息 限制 snapshot 文件的空间使用,防止占用过多磁盘空间 对长时间不能选出 leader 的 Region 进行记录上报 加速启动阶段的垃圾清理工作 根据 compaction 事件及时更新对应 Region 的 size 信息 对 scan lock 的大小进行限制,防止请求超时 使用 DeleteRange 加速 Region 删除 支持在线修改 RocksDB 的参数 "}, {"url": "https://pingcap.com/docs-cn/v2.0/releases/2rc3/", "title": "TiDB 2.0 RC3 Release Notes", "content": " TiDB 2.0 RC3 Release Notes 2018 年 3 月 23 日,TiDB 发布 2.0 RC3 版。该版本在 2.0 RC2 版的基础上,对 MySQL 兼容性、系统稳定性和优化器做了很多改进。TiDB 修复部分场景下 MAX/MIN 结果不正确的问题 修复部分场景下 Sort Merge Join 结果未按照 Join Key 有序的问题 修复边界条件下 uint 和 int 比较的错误 完善浮点数类型的长度和精度检查,提升 MySQL 兼容性 完善时间类型解析报错日志,添加更多错误信息 完善内存控制,新增对 IndexLookupExecutor 的内存统计 优化 ADD INDEX 的执行速度,部分场景下速度大幅度提升 GROUP BY 子句为空时使用 Stream Aggregation 算子,提升速度 支持通过 STRAIGHT_JOIN 来关闭优化器的 Join Reorder 优化 ADMIN SHOW DDL JOBS 输出更详细的 DDL 任务状态信息 支持 ADMIN SHOW DDL JOB QUERIES 查询当前正在运行的 DDL 任务的原始语句 支持 ADMIN RECOVER INDEX 命令,用于灾难恢复情况下修复索引数据 ADD INDEX 操作变更为低优先级,降低对线上业务影响 支持参数为 JSON 类型的 SUM/AVG 等聚合函数 支持配置文件修改 lower_case_table_names 系统变量,用于支持 OGG 数据同步工具 提升对 Navicat 管理工具的兼容性 支持在 CRUD 操作中使用隐式的行 ID PD 支持 Region Merge,合并数据删除后产生的空 Region 或小 Region 添加副本时忽略有大量 pending peer 的节点,提升恢复副本及下线的速度 优化有大量空 Region 时产生的频繁调度问题 优化不同 label 中资源不均衡的场景中 leader balance 调度的速度 添加更多异常 Region 的统计 TiKV 支持 Region Merge Raft snapshot 流程完成之后立刻通知 PD,加速调度 增加 Raw DeleteRange API 增加 GetMetric API 减缓 RocksDB sync 文件造成的 I/O 波动 优化了对 delete 掉数据的空间回收机制 完善数据恢复工具 tikv-ctl 解决了由于 snapshot 导致下线节点慢的问题 Coprocessor 支持 streaming 支持 Readpool,raw_get/get/batch_get 性能提升 30% 支持配置 Coprocessor 请求超时时间 Coprocessor 支持 streaming aggregation 上报 Region heartbeat 时携带时间信息 限制 snapshot 文件的空间使用,防止占用过多磁盘空间 对长时间不能选出 leader 的 Region 进行记录上报 加速启动阶段的垃圾清理工作 根据 compaction 事件及时更新对应 Region 的 size 信息 对 scan lock 的大小进行限制,防止请求超时 使用 DeleteRange 加速 Region 删除 支持在线修改 RocksDB 的参数 "}, {"url": "https://pingcap.com/docs/releases/2rc3/", "title": "TiDB 2.0 RC3 Release Notes", "content": " TiDB 2.0 RC3 Release Notes On March 23, 2018, TiDB 2.0 RC3 is released. This release has great improvement in MySQL compatibility, SQL optimization and stability.TiDB: Fix the wrong result issue of MAX/MIN in some scenarios Fix the issue that the result of Sort Merge Join does not show in order of Join Key in some scenarios Fix the error of comparison between uint and int in boundary conditions Optimize checks on length and precision of the floating point type, to improve compatibility with MySQL Improve the parsing error log of time type and add more error information Improve memory control and add statistics about IndexLookupExecutor memory Optimize the execution speed of ADD INDEX to greatly increase the speed in some scenarios Use the Stream Aggregation operator when the GROUP BY substatement is empty, to increase the speed Support closing the Join Reorder optimization in the optimizer using STRAIGHT_JOIN Output more detailed status information of DDL jobs in ADMIN SHOW DDL JOBS Support querying the original statements of currently running DDL jobs using ADMIN SHOW DDL JOB QUERIES Support recovering the index data using ADMIN RECOVER INDEX for disaster recovery Attach a lower priority to the ADD INDEX operation to reduce the impact on online business Support aggregation functions with JSON type parameters, such as SUM/AVG Support modifying the lower_case_table_names system variable in the configuration file, to support the OGG data synchronization tool Improve compatibility with the Navicat management tool Support using implicit RowID in CRUD operations PD: Support Region Merge, to merge empty Regions or small Regions after deleting data Ignore the nodes that have a lot of pending peers during adding replicas, to improve the speed of restoring replicas or making nodes offline Fix the frequent scheduling issue caused by a large number of empty Regions Optimize the scheduling speed of leader balance in scenarios of unbalanced resources within different labels Add more statistics about abnormal Regions TiKV: Support Region Merge Inform PD immediately once the Raft snapshot process is completed, to speed up balancing Add the Raw DeleteRange API Add the GetMetric API Reduce the I/O fluctuation caused by RocksDB sync files Optimize the space reclaiming mechanism after deleting data Improve the data recovery tool tikv-ctl Fix the issue that it is slow to make nodes down caused by snapshot Support streaming in Coprocessor Support Readpool and increase the raw_get/get/batch_get by 30% Support configuring the request timeout of Coprocessor Support streaming aggregation in Coprocessor Carry time information in Region heartbeats Limit the space usage of snapshot files to avoid consuming too much disk space Record and report the Regions that cannot elect a leader for a long time Speed up garbage cleaning when starting the server Update the size information about the corresponding Region according to compaction events Limit the size of scan lock to avoid request timeout Use DeleteRange to speed up Region deletion Support modifying RocksDB parameters online "}, {"url": "https://pingcap.com/docs/v2.0/releases/2rc3/", "title": "TiDB 2.0 RC3 Release Notes", "content": " TiDB 2.0 RC3 Release Notes On March 23, 2018, TiDB 2.0 RC3 is released. This release has great improvement in MySQL compatibility, SQL optimization and stability.TiDB: Fix the wrong result issue of MAX/MIN in some scenarios Fix the issue that the result of Sort Merge Join does not show in order of Join Key in some scenarios Fix the error of comparison between uint and int in boundary conditions Optimize checks on length and precision of the floating point type, to improve compatibility with MySQL Improve the parsing error log of time type and add more error information Improve memory control and add statistics about IndexLookupExecutor memory Optimize the execution speed of ADD INDEX to greatly increase the speed in some scenarios Use the Stream Aggregation operator when the GROUP BY substatement is empty, to increase the speed Support closing the Join Reorder optimization in the optimizer using STRAIGHT_JOIN Output more detailed status information of DDL jobs in ADMIN SHOW DDL JOBS Support querying the original statements of currently running DDL jobs using ADMIN SHOW DDL JOB QUERIES Support recovering the index data using ADMIN RECOVER INDEX for disaster recovery Attach a lower priority to the ADD INDEX operation to reduce the impact on online business Support aggregation functions with JSON type parameters, such as SUM/AVG Support modifying the lower_case_table_names system variable in the configuration file, to support the OGG data synchronization tool Improve compatibility with the Navicat management tool Support using implicit RowID in CRUD operations PD: Support Region Merge, to merge empty Regions or small Regions after deleting data Ignore the nodes that have a lot of pending peers during adding replicas, to improve the speed of restoring replicas or making nodes offline Fix the frequent scheduling issue caused by a large number of empty Regions Optimize the scheduling speed of leader balance in scenarios of unbalanced resources within different labels Add more statistics about abnormal Regions TiKV: Support Region Merge Inform PD immediately once the Raft snapshot process is completed, to speed up balancing Add the Raw DeleteRange API Add the GetMetric API Reduce the I/O fluctuation caused by RocksDB sync files Optimize the space reclaiming mechanism after deleting data Improve the data recovery tool tikv-ctl Fix the issue that it is slow to make nodes down caused by snapshot Support streaming in Coprocessor Support Readpool and increase the raw_get/get/batch_get by 30% Support configuring the request timeout of Coprocessor Support streaming aggregation in Coprocessor Carry time information in Region heartbeats Limit the space usage of snapshot files to avoid consuming too much disk space Record and report the Regions that cannot elect a leader for a long time Speed up garbage cleaning when starting the server Update the size information about the corresponding Region according to compaction events Limit the size of scan lock to avoid request timeout Use DeleteRange to speed up Region deletion Support modifying RocksDB parameters online "}, {"url": "https://pingcap.com/docs-cn/releases/2rc4/", "title": "TiDB 2.0 RC4 Release Notes", "content": " TiDB 2.0 RC4 Release Notes 2018 年 3 月 30 日,TiDB 发布 2.0 RC4 版。该版本在 2.0 RC3 版的基础上,对 MySQL 兼容性、系统稳定性和优化器做了很多改进。TiDB 支持 SHOW GRANTS FOR CURRENT_USER(); 修复 UnionScan 里的 Expression 没有 Clone 的问题 支持 SET TRANSACTION 语法 修复 copIterator 中潜在的 goroutine 泄露问题 修复 admin check table 对包含 null 的 unique index 误判的问题 支持用科学计数法显示浮点数 修复 binary literal 计算时的类型推导 修复解析 CREATE VIEW 语句的问题 修复语句中同时包含 ORDER BY 和 LIMIT 0 时 panic 的问题 提升 DecodeBytes 执行性能 优化 LIMIT 0 为 TableDual,避免无用的执行计划构建 PD 支持手动 split Region,可用于处理单 Region 热点的问题 修复 pdctl 运行 config show all 不显示 label property 的问题 metrics 及代码结构相关的优化 TiKV 限制接收 snapshot 时的内存使用,解决极端情况下的 OOM 可以配置 Coprocessor 在遇到 warnings 时的行为 TiKV 支持导数据模式 支持 Region 从正中间分裂 提升 CI test 的速度 使用 crossbeam channel 改善 TiKV 在被隔离的情况下由于 leader missing 输出太多日志的问题 "}, {"url": "https://pingcap.com/docs-cn/v2.0/releases/2rc4/", "title": "TiDB 2.0 RC4 Release Notes", "content": " TiDB 2.0 RC4 Release Notes 2018 年 3 月 30 日,TiDB 发布 2.0 RC4 版。该版本在 2.0 RC3 版的基础上,对 MySQL 兼容性、系统稳定性和优化器做了很多改进。TiDB 支持 SHOW GRANTS FOR CURRENT_USER(); 修复 UnionScan 里的 Expression 没有 Clone 的问题 支持 SET TRANSACTION 语法 修复 copIterator 中潜在的 goroutine 泄露问题 修复 admin check table 对包含 null 的 unique index 误判的问题 支持用科学计数法显示浮点数 修复 binary literal 计算时的类型推导 修复解析 CREATE VIEW 语句的问题 修复语句中同时包含 ORDER BY 和 LIMIT 0 时 panic 的问题 提升 DecodeBytes 执行性能 优化 LIMIT 0 为 TableDual,避免无用的执行计划构建 PD 支持手动 split Region,可用于处理单 Region 热点的问题 修复 pdctl 运行 config show all 不显示 label property 的问题 metrics 及代码结构相关的优化 TiKV 限制接收 snapshot 时的内存使用,解决极端情况下的 OOM 可以配置 Coprocessor 在遇到 warnings 时的行为 TiKV 支持导数据模式 支持 Region 从正中间分裂 提升 CI test 的速度 使用 crossbeam channel 改善 TiKV 在被隔离的情况下由于 leader missing 输出太多日志的问题 "}, {"url": "https://pingcap.com/docs/releases/2rc4/", "title": "TiDB 2.0 RC4 Release Notes", "content": " TiDB 2.0 RC4 Release Notes On March 30, 2018, TiDB 2.0 RC4 is released. This release has great improvement in MySQL compatibility, SQL optimization and stability.TiDB: Support SHOW GRANTS FOR CURRENT_USER(); Fix the issue that the Expression in UnionScan is not cloned Support the SET TRANSACTION syntax Fix the potential goroutine leak issue in copIterator Fix the issue that admin check table misjudges the unique index including null Support displaying floating point numbers using scientific notation Fix the type inference issue during binary literal computing Fix the issue in parsing the CREATE VIEW statement Fix the panic issue when one statement contains both ORDER BY and LIMIT 0 Improve the execution performance of DecodeBytes Optimize LIMIT 0 to TableDual, to avoid building useless execution plans PD: Support splitting Region manually to handle the hot spot in a single Region Fix the issue that the label property is not displayed when pdctl runs config show all Optimize metrics and code structure TiKV: Limit the memory usage during receiving snapshots, to avoid OOM in extreme conditions Support configuring the behavior of Coprocessor when it encounters warnings Support importing the data pattern in TiKV Support splitting Region in the middle Increase the speed of CI test Use crossbeam channel Fix the issue that too many logs are output caused by leader missing when TiKV is isolated "}, {"url": "https://pingcap.com/docs/v2.0/releases/2rc4/", "title": "TiDB 2.0 RC4 Release Notes", "content": " TiDB 2.0 RC4 Release Notes On March 30, 2018, TiDB 2.0 RC4 is released. This release has great improvement in MySQL compatibility, SQL optimization and stability.TiDB: Support SHOW GRANTS FOR CURRENT_USER(); Fix the issue that the Expression in UnionScan is not cloned Support the SET TRANSACTION syntax Fix the potential goroutine leak issue in copIterator Fix the issue that admin check table misjudges the unique index including null Support displaying floating point numbers using scientific notation Fix the type inference issue during binary literal computing Fix the issue in parsing the CREATE VIEW statement Fix the panic issue when one statement contains both ORDER BY and LIMIT 0 Improve the execution performance of DecodeBytes Optimize LIMIT 0 to TableDual, to avoid building useless execution plans PD: Support splitting Region manually to handle the hot spot in a single Region Fix the issue that the label property is not displayed when pdctl runs config show all Optimize metrics and code structure TiKV: Limit the memory usage during receiving snapshots, to avoid OOM in extreme conditions Support configuring the behavior of Coprocessor when it encounters warnings Support importing the data pattern in TiKV Support splitting Region in the middle Increase the speed of CI test Use crossbeam channel Fix the issue that too many logs are output caused by leader missing when TiKV is isolated "}, {"url": "https://pingcap.com/docs-cn/releases/2rc5/", "title": "TiDB 2.0 RC5 Release Notes", "content": " TiDB 2.0 RC5 Release Notes 2018 年 4 月 17 日,TiDB 发布 2.0 RC5 版。该版本在 RC4 版的基础上,对 MySQL 兼容性、系统稳定性和优化器做了很多改进。TiDB 修复应用 Top-N 下推规则的问题 修复对包含 NULL 值的列的行数估算 修复 Binary 类型的 0 值 修复事务内的 BatchGet 问题 回滚 Add Index 操作的时候,清除清除已写入的数据,减少空间占用 优化 insert on duplicate key update 语句性能,提升 10 倍以上 修复 UNIX_TIMESTAMP 函数返回结果类型问题返回结果类型问题 修复在添加 NOT NULL 列的过程中,插入 NULL 值的问题 Show Process List 语句支持显示执行语句的内存占用 修复极端情况下 Alter Table Modify Column 出错问题 支持通过 Alter 语句设置 table comment PD 添加 Raft Learner 支持 优化 Balance Region Scheduler,减少调度开销 调整默认 schedule-limit 配置 修复频繁分配 ID 问题 修复添加调度兼容性问题 TiKV tikv-ctl 支持 compact 指定的 Region Raw KV 支持 Batch Put、Batch Get、Batch Delete 和 Batch Scan 解决太多 snapshot 导致的 OOM 问题 Coprocessor 返回更详细的错误信息 支持通过 tikv-ctl 动态修改 TiKV 的 block-cache-size 进一步完善 importer 功能 简化 ImportSST::Upload 接口 设置 gRPC 的 keepalive 属性 tikv-importer 作为独立的 binary 从 TiKV 中分离出来 统计 Coprocessor 每个 scan range 命令扫描了多少行数据 解决在 macOS 系统上的编译问题 优化 metric 相关的内容 解决 snapshot 相关的一个潜在 bug 解决误用了一个 RocksDB metric 的问题 Coprocessor 支持 overflow as warning 选项 "}, {"url": "https://pingcap.com/docs/releases/2rc5/", "title": "TiDB 2.0 RC5 Release Notes", "content": " TiDB 2.0 RC5 Release Notes On April 17, 2018, TiDB 2.0 RC5 is released. This release has great improvement in MySQL compatibility, SQL optimization and stability.TiDB Fix the issue about applying the Top-N pushdown rule Fix the estimation of the number of rows for the columns that contain NULL values Fix the zero value of the Binary type Fix the BatchGet issue within a transaction Clean up the written data while rolling back the Add Index operation, to reduce consumed space Optimize the insert on duplicate key update statement to improve the performance by 10 times Fix the issue about the type of the results returned by the UNIX_TIMESTAMP function Fix the issue that the NULL value is inserted while adding NOT NULL columns Support showing memory usage of the executing statements in the Show Process List statement Fix the issue that Alter Table Modify Column reports an error in extreme conditions Support setting the table comment using the Alter statement PD Add support for Raft Learner Optimize the Balance Region Scheduler to reduce scheduling overhead Adjust the default value of schedule-limit configuration Fix the issue of allocating ID frequently Fix the compatibility issue when adding a new scheduler TiKV Support the Region specified by compact in tikv-ctl Support Batch Put, Batch Get, Batch Delete and Batch Scan in the RawKVClient Fix the OOM issue caused by too many snapshots Return more detailed error information in Coprocessor Support dynamically modifying the block-cache-size in TiKV through tikv-ctl Further improve importer Simplify the ImportSST::Upload interface Configure the keepalive property of gRPC Split tikv-importer from TiKV as an independent binary Provide statistics about the number of rows scanned by each scan range in Coprocessor Fix the compilation issue on the macOS system Fix the issue of misusing a RocksDB metric Support the overflow as warning option in Coprocessor "}, {"url": "https://pingcap.com/docs/v2.0/releases/2rc5/", "title": "TiDB 2.0 RC5 Release Notes", "content": " TiDB 2.0 RC5 Release Notes On April 17, 2018, TiDB 2.0 RC5 is released. This release has great improvement in MySQL compatibility, SQL optimization and stability.TiDB Fix the issue about applying the Top-N pushdown rule Fix the estimation of the number of rows for the columns that contain NULL values Fix the zero value of the Binary type Fix the BatchGet issue within a transaction Clean up the written data while rolling back the Add Index operation, to reduce consumed space Optimize the insert on duplicate key update statement to improve the performance by 10 times Fix the issue about the type of the results returned by the UNIX_TIMESTAMP function Fix the issue that the NULL value is inserted while adding NOT NULL columns Support showing memory usage of the executing statements in the Show Process List statement Fix the issue that Alter Table Modify Column reports an error in extreme conditions Support setting the table comment using the Alter statement PD Add support for Raft Learner Optimize the Balance Region Scheduler to reduce scheduling overhead Adjust the default value of schedule-limit configuration Fix the issue of allocating ID frequently Fix the compatibility issue when adding a new scheduler TiKV Support the Region specified by compact in tikv-ctl Support Batch Put, Batch Get, Batch Delete and Batch Scan in the RawKVClient Fix the OOM issue caused by too many snapshots Return more detailed error information in Coprocessor Support dynamically modifying the block-cache-size in TiKV through tikv-ctl Further improve importer Simplify the ImportSST::Upload interface Configure the keepalive property of gRPC Split tikv-importer from TiKV as an independent binary Provide statistics about the number of rows scanned by each scan range in Coprocessor Fix the compilation issue on the macOS system Fix the issue of misusing a RocksDB metric Support the overflow as warning option in Coprocessor "}, {"url": "https://pingcap.com/docs/releases/2.0ga/", "title": "TiDB 2.0 Release Notes", "content": " TiDB 2.0 Release Notes On April 27, 2018, TiDB 2.0 GA is released! Compared with TiDB 1.0, this release has great improvement in MySQL compatibility, SQL optimizer, executor, and stability.TiDB SQL Optimizer Use more compact data structure to reduce the memory usage of statistics information Speed up loading statistics information when starting a tidb-server process Support updating statistics information dynamically [experimental] Optimize the cost model to provide more accurate query cost evaluation Use Count-Min Sketch to estimate the cost of point queries more accurately Support analyzing more complex conditions to make full use of indexes Support manually specifying the Join order using the STRAIGHT_JOIN syntax Use the Stream Aggregation operator when the GROUP BY clause is empty to improve the performance Support using indexes for the MAX/MIN function Optimize the processing algorithms for correlated subqueries to support decorrelating more types of correlated subqueries and transform them to Left Outer Join Extend IndexLookupJoin to be used in matching the index prefix SQL Execution Engine Refactor all operators using the Chunk architecture, improve the execution performance of analytical queries, and reduce memory usage. There is a significant improvement in the TPC-H benchmark result. Support the Streaming Aggregation operators pushdown Optimize the Insert Into Ignore statement to improve the performance by over 10 times Optimize the Insert On Duplicate Key Update statement to improve the performance by over 10 times Optimize Load Data to improve the performance by over 10 times Push down more data types and functions to TiKV Support computing the memory usage of physical operators, and specifying the processing behavior in the configuration file and system variables when the memory usage exceeds the threshold Support limiting the memory usage by a single SQL statement to reduce the risk of OOM Support using implicit RowID in CRUD operations Improve the performance of point queries Server Support the Proxy Protocol Add more monitoring metrics and refine the log Support validating the configuration files Support obtaining the information of TiDB parameters through HTTP API Resolve Lock in the Batch mode to speed up garbage collection Support multi-threaded garbage collection Support TLS Compatibility Support more MySQL syntaxes Support modifying the lower_case_table_names system variable in the configuration file to support the OGG data synchronization tool Improve compatibility with the Navicat management tool Support displaying the table creating time in Information_Schema Fix the issue that the return types of some functions/expressions differ from MySQL Improve compatibility with JDBC Support more SQL Modes DDL Optimize the Add Index operation to greatly improve the execution speed in some scenarios Attach a lower priority to the Add Index operation to reduce the impact on online business Output more detailed status information of the DDL jobs in Admin Show DDL Jobs Support querying the original statements of currently running DDL jobs using Admin Show DDL Job Queries JobID Support recovering the index data using Admin Recover Index for disaster recovery Support modifying Table Options using the Alter statement PD Support Region Merge, to merge empty Regions after deleting data [experimental] Support Raft Learner [experimental] Optimize the scheduler Make the scheduler to adapt to different Region sizes Improve the priority and speed of restoring data during TiKV outage Speed up data transferring when removing a TiKV node Optimize the scheduling policies to prevent the disks from becoming full when the space of TiKV nodes is insufficient Improve the scheduling efficiency of the balance-leader scheduler Reduce the scheduling overhead of the balance-region scheduler Optimize the execution efficiency of the the hot-region scheduler Operations interface and configuration Support TLS Support prioritizing the PD leaders Support configuring the scheduling policies based on labels Support configuring stores with a specific label not to schedule the Raft leader Support splitting Region manually to handle the hotspot in a single Region Support scattering a specified Region to manually adjust Region distribution in some cases Add check rules for configuration parameters and improve validity check of the configuration items Debugging interface Add the Drop Region debugging interface Add the interfaces to enumerate the health status of each PD Statistics Add statistics about abnormal Regions Add statistics about Region isolation level Add scheduling related metrics Performance Keep the PD leader and the etcd leader together in the same node to improve write performance Optimize the performance of Region heartbeat TiKV Features Protect critical configuration from incorrect modification Support Region Merge [experimental] Add the Raw DeleteRange API Add the GetMetric API Add Raw Batch Put, Raw Batch Get, Raw Batch Delete and Raw Batch Scan Add Column Family options for the RawKV API and support executing operation on a specific Column Family Support Streaming and Streaming Aggregation in Coprocessor Support configuring the request timeout of Coprocessor Carry timestamps with Region heartbeats Support modifying some RocksDB parameters online, such as block-cache-size Support configuring the behavior of Coprocessor when it encounters some warnings or errors Support starting in the importing data mode to reduce write amplification during the data importing process Support manually splitting Region in halves Improve the data recovery tool tikv-ctl Return more statistics in Coprocessor to guide the behavior of TiDB Support the ImportSST API to import SST files [experimental] Add the TiKV Importer binary to integrate with TiDB Lightning to import data quickly [experimental] Performance Optimize read performance using ReadPool and increase the raw_get/get/batch_get by 30% Improve metrics performance Inform PD immediately once the Raft snapshot process is completed to speed up balancing Solve performance jitter caused by RocksDB flushing Optimize the space reclaiming mechanism after deleting data Speed up garbage cleaning while starting the server Reduce the I/O overhead during replica migration using DeleteFilesInRanges Stability Fix the issue that gRPC call does not get returned when the PD leader switches Fix the issue that it is slow to offline nodes caused by snapshots Limit the temporary space usage consumed by migrating replicas Report the Regions that cannot elect a leader for a long time Update the Region size information in time according to compaction events Limit the size of scan lock to avoid request timeout Limit the memory usage when receiving snapshots to avoid OOM Increase the speed of CI test Fix the OOM issue caused by too many snapshots Configure keepalive of gRPC Fix the OOM issue caused by an increase of the Region number TiSpark TiSpark uses a separate version number. The current TiSpark version is 1.0 GA. The components of TiSpark 1.0 provide distributed computing of TiDB data using Apache Spark. Provide a gRPC communication framework to read data from TiKV Provide encoding and decoding of TiKV component data and communication protocol Provide calculation pushdown, which includes: Aggregate pushdown Predicate pushdown TopN pushdown Limit pushdown Provide index related support Transform predicate into Region key range or secondary index Optimize Index Only queries - Adaptively downgrade index scan to table scan per Region Provide cost-based optimization Support statistics Select index Estimate broadcast table cost Provide support for multiple Spark interfaces Support Spark Shell Support ThriftServer/JDBC Support Spark-SQL interaction Support PySpark Shell Support SparkR "}, {"url": "https://pingcap.com/docs/v2.0/releases/2.0ga/", "title": "TiDB 2.0 Release Notes", "content": " TiDB 2.0 Release Notes On April 27, 2018, TiDB 2.0 GA is released! Compared with TiDB 1.0, this release has great improvement in MySQL compatibility, SQL optimizer, executor, and stability.TiDB SQL Optimizer Use more compact data structure to reduce the memory usage of statistics information Speed up loading statistics information when starting a tidb-server process Support updating statistics information dynamically [experimental] Optimize the cost model to provide more accurate query cost evaluation Use Count-Min Sketch to estimate the cost of point queries more accurately Support analyzing more complex conditions to make full use of indexes Support manually specifying the Join order using the STRAIGHT_JOIN syntax Use the Stream Aggregation operator when the GROUP BY clause is empty to improve the performance Support using indexes for the MAX/MIN function Optimize the processing algorithms for correlated subqueries to support decorrelating more types of correlated subqueries and transform them to Left Outer Join Extend IndexLookupJoin to be used in matching the index prefix SQL Execution Engine Refactor all operators using the Chunk architecture, improve the execution performance of analytical queries, and reduce memory usage. There is a significant improvement in the TPC-H benchmark result. Support the Streaming Aggregation operators pushdown Optimize the Insert Into Ignore statement to improve the performance by over 10 times Optimize the Insert On Duplicate Key Update statement to improve the performance by over 10 times Optimize Load Data to improve the performance by over 10 times Push down more data types and functions to TiKV Support computing the memory usage of physical operators, and specifying the processing behavior in the configuration file and system variables when the memory usage exceeds the threshold Support limiting the memory usage by a single SQL statement to reduce the risk of OOM Support using implicit RowID in CRUD operations Improve the performance of point queries Server Support the Proxy Protocol Add more monitoring metrics and refine the log Support validating the configuration files Support obtaining the information of TiDB parameters through HTTP API Resolve Lock in the Batch mode to speed up garbage collection Support multi-threaded garbage collection Support TLS Compatibility Support more MySQL syntaxes Support modifying the lower_case_table_names system variable in the configuration file to support the OGG data synchronization tool Improve compatibility with the Navicat management tool Support displaying the table creating time in Information_Schema Fix the issue that the return types of some functions/expressions differ from MySQL Improve compatibility with JDBC Support more SQL Modes DDL Optimize the Add Index operation to greatly improve the execution speed in some scenarios Attach a lower priority to the Add Index operation to reduce the impact on online business Output more detailed status information of the DDL jobs in Admin Show DDL Jobs Support querying the original statements of currently running DDL jobs using Admin Show DDL Job Queries JobID Support recovering the index data using Admin Recover Index for disaster recovery Support modifying Table Options using the Alter statement PD Support Region Merge, to merge empty Regions after deleting data [experimental] Support Raft Learner [experimental] Optimize the scheduler Make the scheduler to adapt to different Region sizes Improve the priority and speed of restoring data during TiKV outage Speed up data transferring when removing a TiKV node Optimize the scheduling policies to prevent the disks from becoming full when the space of TiKV nodes is insufficient Improve the scheduling efficiency of the balance-leader scheduler Reduce the scheduling overhead of the balance-region scheduler Optimize the execution efficiency of the the hot-region scheduler Operations interface and configuration Support TLS Support prioritizing the PD leaders Support configuring the scheduling policies based on labels Support configuring stores with a specific label not to schedule the Raft leader Support splitting Region manually to handle the hotspot in a single Region Support scattering a specified Region to manually adjust Region distribution in some cases Add check rules for configuration parameters and improve validity check of the configuration items Debugging interface Add the Drop Region debugging interface Add the interfaces to enumerate the health status of each PD Statistics Add statistics about abnormal Regions Add statistics about Region isolation level Add scheduling related metrics Performance Keep the PD leader and the etcd leader together in the same node to improve write performance Optimize the performance of Region heartbeat TiKV Features Protect critical configuration from incorrect modification Support Region Merge [experimental] Add the Raw DeleteRange API Add the GetMetric API Add Raw Batch Put, Raw Batch Get, Raw Batch Delete and Raw Batch Scan Add Column Family options for the RawKV API and support executing operation on a specific Column Family Support Streaming and Streaming Aggregation in Coprocessor Support configuring the request timeout of Coprocessor Carry timestamps with Region heartbeats Support modifying some RocksDB parameters online, such as block-cache-size Support configuring the behavior of Coprocessor when it encounters some warnings or errors Support starting in the importing data mode to reduce write amplification during the data importing process Support manually splitting Region in halves Improve the data recovery tool tikv-ctl Return more statistics in Coprocessor to guide the behavior of TiDB Support the ImportSST API to import SST files [experimental] Add the TiKV Importer binary to integrate with TiDB Lightning to import data quickly [experimental] Performance Optimize read performance using ReadPool and increase the raw_get/get/batch_get by 30% Improve metrics performance Inform PD immediately once the Raft snapshot process is completed to speed up balancing Solve performance jitter caused by RocksDB flushing Optimize the space reclaiming mechanism after deleting data Speed up garbage cleaning while starting the server Reduce the I/O overhead during replica migration using DeleteFilesInRanges Stability Fix the issue that gRPC call does not get returned when the PD leader switches Fix the issue that it is slow to offline nodes caused by snapshots Limit the temporary space usage consumed by migrating replicas Report the Regions that cannot elect a leader for a long time Update the Region size information in time according to compaction events Limit the size of scan lock to avoid request timeout Limit the memory usage when receiving snapshots to avoid OOM Increase the speed of CI test Fix the OOM issue caused by too many snapshots Configure keepalive of gRPC Fix the OOM issue caused by an increase of the Region number TiSpark TiSpark uses a separate version number. The current TiSpark version is 1.0 GA. The components of TiSpark 1.0 provide distributed computing of TiDB data using Apache Spark. Provide a gRPC communication framework to read data from TiKV Provide encoding and decoding of TiKV component data and communication protocol Provide calculation pushdown, which includes: Aggregate pushdown Predicate pushdown TopN pushdown Limit pushdown Provide index related support Transform predicate into Region key range or secondary index Optimize Index Only queries - Adaptively downgrade index scan to table scan per Region Provide cost-based optimization Support statistics Select index Estimate broadcast table cost Provide support for multiple Spark interfaces Support Spark Shell Support ThriftServer/JDBC Support Spark-SQL interaction Support PySpark Shell Support SparkR "}, {"url": "https://pingcap.com/docs/op-guide/tidb-v2.0-upgrade-guide/", "title": "TiDB 2.0 Upgrade Guide", "content": " TiDB 2.0 Upgrade Guide This document describes how to upgrade from TiDB 1.0 or TiDB 2.0 RC version to TiDB 2.0 GA version.Step 1: Install Ansible and dependencies in the Control Machine TiDB-Ansible release-2.0 depends on Ansible 2.4.2 or later, and is compatible with the latest Ansible 2.5. In addition, TiDB-Ansible release-2.0 depends on the Python module: jinja2>=2.9.6 and jmespath>=0.9.0.To make it easy to manage dependencies, use pip to install Ansible and its dependencies. For details, see Install Ansible and its dependencies on the Control Machine. For offline environment, see Install Ansible and its dependencies offline on the Control Machine.After the installation is finished, you can view the version information using the following command:$ ansible --version ansible 2.5.2 $ pip show jinja2 Name: Jinja2 Version: 2.9.6 $ pip show jmespath Name: jmespath Version: 0.9.0 Note: You must install Ansible and its dependencies following the above procedures. Make sure that the Jinja2 version is correct, otherwise an error occurs when you start Grafana. Make sure that the jmespath version is correct, otherwise an error occurs when you perform a rolling update for TiKV. Step 2: Download TiDB-Ansible to the Control Machine Log in to the Control Machine using the tidb user account and enter the /home/tidb directory. Back up the tidb-ansible folders of TiDB 1.0 or TiDB 2.0 RC versions using the following command:$ mv tidb-ansible tidb-ansible-bak Download the latest tidb-ansible release-2.0 branch using the following command. The default folder name is tidb-ansible.$ git clone -b release-2.0 https://github.com/pingcap/tidb-ansible.git Step 3: Edit the inventory.ini file and the configuration file Log in to the Control Machine using the tidb user account and enter the /home/tidb/tidb-ansible directory.Edit the inventory.ini file Edit the inventory.ini file. For IP information, see the /home/tidb/tidb-ansible-bak/inventory.ini backup file.Pay special attention to the following variables configuration. For variable meaning, see Description of other variables. Make sure that ansible_user is the normal user. For unified privilege management, remote installation using the root user is no longer supported. The default configuration uses the tidb user as the SSH remote user and the program running user.## Connection # ssh via normal user ansible_user = tidb You can refer to How to configure SSH mutual trust and sudo rules on the Control Machine to automatically configure the mutual trust among hosts. Keep the process_supervision variable consistent with that in the previous version. It is recommended to use systemd by default.# process supervision, [systemd, supervise] process_supervision = systemd If you need to modify this variable, see How to modify the supervision method of a process from supervise to systemd. Before you upgrade, first use the /home/tidb/tidb-ansible-bak/ backup branch to modify the supervision method of a process. Edit the configuration file of TiDB cluster components If you have previously customized the configuration file of TiDB cluster components, refer to the backup file to modify the corresponding configuration file in /home/tidb/tidb-ansible/conf.In TiKV configuration, end-point-concurrency is changed to three parameters: high-concurrency, normal-concurrency and low-concurrency.readpool: coprocessor: # Notice: if CPU_NUM > 8, default thread pool size for coprocessors # will be set to CPU_NUM * 0.8. # high-concurrency: 8 # normal-concurrency: 8 # low-concurrency: 8 For the cluster topology of multiple TiKV instances on a single machine, you need to modify the three parameters above. Recommended configuration: number of instances * parameter value = number of CPU cores * 0.8.Step 4: Download TiDB 2.0 binary to the Control Machine Make sure that tidb_version = v2.0.4 in the tidb-ansible/inventory.ini file, and then run the following command to download TiDB 2.0 binary to the Control Machine:$ ansible-playbook local_prepare.yml Step 5: Perform a rolling update to TiDB cluster components $ ansible-playbook rolling_update.yml Step 6: Perform a rolling update to TiDB monitoring component To meet the users’ demand on mixed deployment, the systemd service of the monitoring component is distinguished by port. Check the process_supervision variable in the inventory.ini file.# process supervision, [systemd, supervise] process_supervision = systemd If process_supervision = systemd, to make it compatible with versions earlier than v2.0.0-rc.6, you need to run migrate_monitor.yml Playbook.$ ansible-playbook migrate_monitor.yml If process_supervision = supervise, you do not need to run the above command. Perform a rolling update to the TiDB monitoring component using the following command:$ ansible-playbook rolling_update_monitor.yml "}, {"url": "https://pingcap.com/docs/v2.0/op-guide/tidb-v2.0-upgrade-guide/", "title": "TiDB 2.0 Upgrade Guide", "content": " TiDB 2.0 Upgrade Guide This document describes how to upgrade from TiDB 1.0 or TiDB 2.0 RC version to TiDB 2.0 GA version.Install Ansible and dependencies in the Control Machine TiDB-Ansible release-2.0 depends on Ansible 2.4.2 or later, and is compatible with the latest Ansible 2.5. In addition, TiDB-Ansible release-2.0 depends on the Python module: jinja2>=2.9.6 and jmespath>=0.9.0.To make it easy to manage dependencies, use pip to install Ansible and its dependencies. For details, see Install Ansible and its dependencies on the Control Machine. For offline environment, see Install Ansible and its dependencies offline on the Control Machine.After the installation is finished, you can view the version information using the following command:$ ansible --version ansible 2.5.2 $ pip show jinja2 Name: Jinja2 Version: 2.9.6 $ pip show jmespath Name: jmespath Version: 0.9.0 Note: You must install Ansible and its dependencies following the above procedures. Make sure that the Jinja2 version is correct, otherwise an error occurs when you start Grafana. Make sure that the jmespath is correct, otherwise an error occurs when you perform a rolling update for TiKV. Download TiDB-Ansible to the Control Machine Login to the Control Machine using the tidb user account and enter the /home/tidb directory. Back up the tidb-ansible folders of TiDB 1.0 OR TiDB 2.0 RC versions using the following command:$ mv tidb-ansible tidb-ansible-bak Download the latest tidb-ansible release-2.0 branch using the following command. The default folder name is tidb-ansible.$ git clone -b release-2.0 https://github.com/pingcap/tidb-ansible.git Edit the inventory.ini file and the configuration file Login to the Control Machine using the tidb user account and enter the /home/tidb/tidb-ansible directory.Edit the inventory.ini file Edit the inventory.ini file. For IP information, see the /home/tidb/tidb-ansible-bak/inventory.ini backup file.Pay special attention to the following variables configuration. For variable meaning, see Description of other variables. Make sure that ansible_user is the normal user. For unified privilege management, remote installation using the root user is no longer supported. The default configuration uses the tidb user as the SSH remote user and the program running user.## Connection # ssh via normal user ansible_user = tidb You can refer to How to configure SSH mutual trust and sudo rules on the Control Machine to automatically configure the mutual trust among hosts. Keep the process_supervision variable consistent with that in the previous version. It is recommended to use systemd by default.# process supervision, [systemd, supervise] process_supervision = systemd If you need to modify this variable, see How to modify the supervision method of a process from supervise to systemd. Before you upgrade, first use the /home/tidb/tidb-ansible-bak/ backup branch to modify the supervision method of a process. Edit the configuration file of TiDB cluster components If you have previously customized the configuration file of TiDB cluster components, refer to the backup file to modify the corresponding configuration file in /home/tidb/tidb-ansible/conf.In TiKV configuration, end-point-concurrency is changed to three parameters: high-concurrency, normal-concurrency and low-concurrency.readpool: coprocessor: # Notice: if CPU_NUM > 8, default thread pool size for coprocessors # will be set to CPU_NUM * 0.8. # high-concurrency: 8 # normal-concurrency: 8 # low-concurrency: 8 For the cluster topology of multiple TiKV instances on a single machine, you need to modify the three parameters above. Recommended configuration: number of instances * parameter value = number of CPU cores * 0.8.Download TiDB 2.0 binary to the Control Machine Make sure that tidb_version = v2.0.4 in the tidb-ansible/inventory.ini file, and then run the following command to download TiDB 2.0 binary to the Control Machine:$ ansible-playbook local_prepare.yml Perform a rolling update to TiDB cluster components $ ansible-playbook rolling_update.yml Perform a rolling update to TiDB monitoring component To meet the users’ demand on mixed deployment, the systemd service of the monitoring component is distinguished by port. Check the process_supervision variable in the inventory.ini file.# process supervision, [systemd, supervise] process_supervision = systemd If process_supervision = systemd, to make it compatible with versions earlier than v2.0.0-rc.6, you need to run migrate_monitor.yml Playbook.$ ansible-playbook migrate_monitor.yml If process_supervision = supervise, you do not need to run the above command. Perform a rolling update to the TiDB monitoring component using the following command:$ ansible-playbook rolling_update_monitor.yml "}, {"url": "https://pingcap.com/docs-cn/releases/2.0ga/", "title": "TiDB 2.0 release notes", "content": " TiDB 2.0 Release Notes 2018 年 4 月 27 日,TiDB 发布 2.0 GA 版。相比 1.0 版本,该版本对 MySQL 兼容性、系统稳定性、优化器和执行器做了很多改进。TiDB SQL 优化器 精简统计信息数据结构,减小内存占用 加快进程启动时加载统计信息速度 支持统计信息动态更新 [experimental] 优化代价模型,对代价估算更精准 使用 Count-Min Sketch 更精确地估算点查的代价 支持分析更复杂的条件,尽可能充分的使用索引 支持通过 STRAIGHT_JOIN 语法手动指定 Join 顺序 GROUP BY子句为空时使用 Stream Aggregation 算子,提升性能 支持使用索引计算 Max/Min 函数 优化关联子查询处理算法,支持将更多类型的关联子查询解关联并转化成 Left Outer Join 扩大 IndexLookupJoin 的使用范围,索引前缀匹配的场景也可以使用该算法 SQL 执行引擎 使用 Chunk 结构重构所有执行器算子,提升分析型语句执行性能,减少内存占用,显著提升 TPC-H 结果 支持 Streaming Aggregation 算子下推 优化 Insert Into Ignore 语句性能,提升 10 倍以上 优化 Insert On Duplicate Key Update 语句性能,提升 10 倍以上 下推更多的数据类型和函数到 TiKV 计算 优化 Load Data 性能,提升 10 倍以上 支持对物理算子内存使用进行统计,通过配置文件以及系统变量指定超过阈值后的处理行为 支持限制单条 SQL 语句使用内存的大小,减少程序 OOM 风险 支持在 CRUD 操作中使用隐式的行 ID 提升点查性能 Server 支持 Proxy Protocol 添加大量监控项, 优化日志 支持配置文件的合法性检测 支持 HTTP API 获取 TiDB 参数信息 使用 Batch 方式 Resolve Lock,提升垃圾回收速度 支持多线程垃圾回收 支持 TLS 兼容性 支持更多 MySQL 语法 支持配置文件修改 lower_case_table_names 系统变量,用于支持 OGG 数据同步工具 提升对 Navicat 的兼容性 在 Information_Schema 中支持显示建表时间 修复部分函数/表达式返回类型和 MySQL 不同的问题 提升对 JDBC 兼容性 支持更多的 SQL_MODE DDL 优化 Add Index 的执行速度,部分场景下速度大幅度提升 Add Index 操作变更为低优先级,降低对线上业务影响 Admin Show DDL Jobs 输出更详细的 DDL 任务状态信息 支持 Admin Show DDL Job Queries JobID 查询当前正在运行的 DDL 任务的原始语句 支持 Admin Recover Index 命令,用于灾难恢复情况下修复索引数据 支持通过 Alter 语句修改 Table Options PD 增加 Region Merge 支持,合并数据删除后产生的空 Region [experimental] 增加 Raft Learner 支持 [experimental] 调度器优化 调度器适应不同的 Region size 提升 TiKV 宕机时数据恢复的优先级和恢复速度 提升下线 TiKV 节点搬迁数据的速度 优化 TiKV 节点空间不足时的调度策略,尽可能防止空间不足时磁盘被写满 提升 balance-leader scheduler 的调度效率 减少 balance-region scheduler 调度开销 优化 hot-region scheduler 的执行效率 运维接口及配置 增加 TLS 支持 支持设置 PD leader 优先级 支持基于 label 配置属性 支持配置特定 label 的节点不调度 Region leader 支持手动 Split Region,可用于处理单 Region 热点的问题 支持打散指定 Region,用于某些情况下手动调整热点 Region 分布 增加配置参数检查规则,完善配置项的合法性较验 调试接口 增加 Drop Region 调试接口 增加枚举各个 PD health 状态的接口 统计相关 添加异常 Region 的统计 添加 Region 隔离级别的统计 添加调度相关 metrics 性能优化 PD leader 尽量与 etcd leader 保持同步,提升写入性能 优化 Region heartbeat 性能,现可支持超过 100 万 Region TiKV 功能 保护关键配置,防止错误修改 支持 Region Merge [experimental] 添加 Raw DeleteRange API 添加 GetMetric API 添加 Raw Batch Put,Raw Batch Get,Raw Batch Delete 和 Raw Batch Scan 给 Raw KV API 增加 Column Family 参数,能对特定 Column Family 进行操作 Coprocessor 支持 streaming 模式,支持 streaming 聚合 支持配置 Coprocessor 请求的超时时间 心跳包携带时间戳 支持在线修改 RocksDB 的一些参数,包括 block-cache-size 大小等 支持配置 Coprocessor 遇到某些错误时的行为 支持以导数据模式启动,减少导数据过程中的写放大 支持手动对 region 进行对半 split 完善数据修复工具 tikv-ctl Coprocessor 返回更多的统计信息,以便指导 TiDB 的行为 支持 ImportSST API,可以用于 SST 文件导入 [experimental] 新增 TiKV Importer 二进制,与 TiDB Lightning 集成用于快速导入数据 [experimental] 性能 使用 ReadPool 优化读性能,raw_get/get/batch_get 提升 30% 提升 metrics 的性能 Raft snapshot 处理完之后立即通知 PD,加快调度速度 解决 RocksDB 刷盘导致性能抖动问题 提升在数据删除之后的空间回收 加速启动过程中的垃圾清理过程 使用 DeleteFilesInRanges 减少副本迁移时 I/O 开销 稳定性 解决在 PD leader 发送切换的情况下 gRPC call 不返回问题 解决由于 snapshot 导致下线节点慢的问题 限制搬移副本临时占用的空间大小 如果有 Region 长时间没有 Leader,进行上报 根据 compaction 事件及时更新统计的 Region size 限制单次 scan lock 请求的扫描的数据量,防止超时 限制接收 snapshot 过程中的内存占用,防止 OOM 提升 CI test 的速度 解决由于 snapshot 太多导致的 OOM 问题 配置 gRPC 的 keepalive 参数 修复 Region 增多容易 OOM 的问题 TiSpark TiSpark 使用独立的版本号,现为 1.0 GA。TiSpark 1.0 版本组件提供了针对 TiDB 上的数据使用 Apache Spark 进行分布式计算的能力。 提供了针对 TiKV 读取的 gRPC 通信框架 提供了对 TiKV 组件数据的和通信协议部分的编码解码 提供了计算下推功能,包含: 聚合下推 谓词下推 TopN 下推 Limit 下推 提供了索引相关的支持 谓词转化聚簇索引范围 谓词转化次级索引 Index Only 查询优化 运行时索引退化扫表优化 提供了基于代价的优化 统计信息支持 索引选择 广播表代价估算 多种 Spark Interface 的支持 Spark Shell 支持 ThriftServer/JDBC 支持 Spark-SQL 交互支持 PySpark Shell 支持 SparkR 支持 "}, {"url": "https://pingcap.com/docs-cn/op-guide/tidb-v2.0-upgrade-guide/", "title": "TiDB 2.0 升级操作指南", "content": " TiDB 2.0 升级操作指南 本文档适用于从 TiDB 1.0 版本或 TiDB 2.0 rc 版本升级到 TiDB 2.0 GA 版本。在中控机器上安装 Ansible 及其依赖 TiDB-Ansible release-2.0 版本依赖 Ansible 2.4.2 及以上版本,兼容最新的 Ansible 2.5 版本,另依赖 Python 模块:jinja2>=2.9.6 和 jmespath>=0.9.0。为方便管理依赖,新版本使用 pip 安装 Ansible 及其依赖,可参照在中控机器上安装 Ansible 及其依赖 进行安装。离线环境参照在中控机器上离线安装 Ansible 及其依赖。安装完成后,可通过以下命令查看版本:$ ansible --version ansible 2.5.2 $ pip show jinja2 Name: Jinja2 Version: 2.9.6 $ pip show jmespath Name: jmespath Version: 0.9.0 注意:请务必按以上文档安装 Ansible 及其依赖。确认 Jinja2 版本是否正确,否则启动 Grafana 时会报错。确认 jmespath 版本是否正确,否则滚动升级 TiKV 时会报错。 在中控机器上下载 TiDB-Ansible 以 tidb 用户登录中控机并进入 /home/tidb 目录,备份 TiDB 1.0 版本或 TiDB 2.0 rc 版本的 tidb-ansible 文件夹:$ mv tidb-ansible tidb-ansible-bak 下载最新 tidb-ansible release-2.0 分支,默认的文件夹名称为 tidb-ansible。$ git clone -b release-2.0 https://github.com/pingcap/tidb-ansible.git 编辑 inventory.ini 文件和配置文件 以 tidb 用户登录中控机并进入 /home/tidb/tidb-ansible 目录。编辑 inventory.ini 文件 编辑 inventory.ini 文件,IP 信息参照备份文件 /home/tidb/tidb-ansible-bak/inventory.ini。以下变量配置,需要重点确认,变量含义可参考 inventory.ini 变量调整。 请确认 ansible_user 配置的是普通用户。为统一权限管理,不再支持使用 root 用户远程安装。默认配置中使用 tidb 用户作为 SSH 远程用户及程序运行用户。## Connection # ssh via normal user ansible_user = tidb 可参考如何配置 ssh 互信及 sudo 规则 自动配置主机间互信。 process_supervision 变量请与之前版本保持一致,默认推荐使用 systemd。# process supervision, [systemd, supervise] process_supervision = systemd 如需变更,可参考 如何调整进程监管方式从 supervise 到 systemd,先使用备份 /home/tidb/tidb-ansible-bak/ 分支变更进程监管方式再升级。 编辑 TiDB 集群组件配置文件 如之前自定义过 TiDB 集群组件配置文件,请参照备份文件修改 /home/tidb/tidb-ansible/conf 下对应配置文件。TiKV 配置中 end-point-concurrency 变更为 high-concurrency、normal-concurrency 和 low-concurrency 三个参数:readpool: coprocessor: # Notice: if CPU_NUM > 8, default thread pool size for coprocessors # will be set to CPU_NUM * 0.8. # high-concurrency: 8 # normal-concurrency: 8 # low-concurrency: 8 单机多 TiKV 实例情况下,需要修改这三个参数,推荐设置:实例数 * 参数值 = CPU 核数 * 0.8。下载 TiDB 2.0 binary 到中控机 确认 tidb-ansible/inventory.ini 文件中 tidb_version = v2.0.4,然后执行以下命令下载 TiDB 2.0 binary 到中控机。$ ansible-playbook local_prepare.yml 滚动升级 TiDB 集群组件 $ ansible-playbook rolling_update.yml 滚动升级 TiDB 监控组件 为满足客户监控组件混布需求,监控组件 systemd service 开始按端口区分。查看 inventory.ini 文件中 process_supervision 变量:# process supervision, [systemd, supervise] process_supervision = systemd 如果 process_supervision = systemd,为兼容 v2.0.0-rc.6 之前的版本,你需要执行 migrate_monitor.yml Playbook。如果 process_supervision = supervise,此步骤不需要执行。$ ansible-playbook migrate_monitor.yml 滚动升级 TiDB 监控组件:$ ansible-playbook rolling_update_monitor.yml "}, {"url": "https://pingcap.com/docs/releases/201/", "title": "TiDB 2.0.1 Release Notes", "content": " TiDB 2.0.1 Release Notes On May 16, 2018, TiDB 2.0.1 is released. Compared with TiDB 2.0.0 (GA), this release has great improvement in MySQL compatibility and system stability.TiDB Update the progress of Add Index to the DDL job information in real time Add the tidb_auto_analyze_ratio session variable to control the threshold value of automatic statistics update Fix an issue that not all residual states are cleaned up when the transaction commit fails Fix a bug about adding indexes in some conditions Fix the correctness related issue when DDL modifies surface operations in some concurrent scenarios Fix a bug that the result of LIMIT is incorrect in some conditions Fix a capitalization issue of the ADMIN CHECK INDEX statement to make its index name case insensitive Fix a compatibility issue of the UNION statement Fix a compatibility issue when inserting data of TIME type Fix a goroutine leak issue caused by copIteratorTaskSender in some conditions Add an option for TiDB to control the behaviour of Binlog failure Refactor the Coprocessor slow log to distinguish between the scenario of tasks with long processing time and long waiting time Log nothing when meeting MySQL protocol handshake error, to avoid too many logs caused by the load balancer Keep Alive mechanism Refine the “Out of range value for column” error message Fix a bug when there is a subquery in an Update statement Change the behaviour of handling SIGTERM, and do not wait for all queries to terminate anymore PD Add the Scatter Range scheduler to balance Regions with the specified key range Optimize the scheduling of Merge Region to prevent the newly split Region from being merged Add Learner related metrics Fix the issue that the scheduler is mistakenly deleted after restart Fix the error that occurs when parsing the configuration file Fix the issue that the etcd leader and the PD leader are not synchronized Fix the issue that Learner still appears after it is closed Fix the issue that Regions fail to load because the packet size is too large TiKV Fix the issue that SELECT FOR UPDATE prevents others from reading Optimize the slow query log Reduce the number of thread_yield calls Fix the bug that raftstore is accidentally blocked when generating the snapshot Fix the issue that Learner cannot be successfully elected in special conditions Fix the issue that split might cause dirty read in extreme conditions Correct the default value of the read thread pool configuration Speed up Delete Range "}, {"url": "https://pingcap.com/docs/v2.0/releases/201/", "title": "TiDB 2.0.1 Release Notes", "content": " TiDB 2.0.1 Release Notes On May 16, 2018, TiDB 2.0.1 is released. Compared with TiDB 2.0.0 (GA), this release has great improvement in MySQL compatibility and system stability.TiDB Update the progress of Add Index to the DDL job information in real time Add the tidb_auto_analyze_ratio session variable to control the threshold value of automatic statistics update Fix an issue that not all residual states are cleaned up when the transaction commit fails Fix a bug about adding indexes in some conditions Fix the correctness related issue when DDL modifies surface operations in some concurrent scenarios Fix a bug that the result of LIMIT is incorrect in some conditions Fix a capitalization issue of the ADMIN CHECK INDEX statement to make its index name case insensitive Fix a compatibility issue of the UNION statement Fix a compatibility issue when inserting data of TIME type Fix a goroutine leak issue caused by copIteratorTaskSender in some conditions Add an option for TiDB to control the behaviour of Binlog failure Refactor the Coprocessor slow log to distinguish between the scenario of tasks with long processing time and long waiting time Log nothing when meeting MySQL protocol handshake error, to avoid too many logs caused by the load balancer Keep Alive mechanism Refine the “Out of range value for column” error message Fix a bug when there is a subquery in an Update statement Change the behaviour of handling SIGTERM, and do not wait for all queries to terminate anymore PD Add the Scatter Range scheduler to balance Regions with the specified key range Optimize the scheduling of Merge Region to prevent the newly split Region from being merged Add Learner related metrics Fix the issue that the scheduler is mistakenly deleted after restart Fix the error that occurs when parsing the configuration file Fix the issue that the etcd leader and the PD leader are not synchronized Fix the issue that Learner still appears after it is closed Fix the issue that Regions fail to load because the packet size is too large TiKV Fix the issue that SELECT FOR UPDATE prevents others from reading Optimize the slow query log Reduce the number of thread_yield calls Fix the bug that raftstore is accidentally blocked when generating the snapshot Fix the issue that Learner cannot be successfully elected in special conditions Fix the issue that split might cause dirty read in extreme conditions Correct the default value of the read thread pool configuration Speed up Delete Range "}, {"url": "https://pingcap.com/docs-cn/releases/201/", "title": "TiDB 2.0.1 release notes", "content": " TiDB 2.0.1 Release Notes 2018 年 5 月 16 日,TiDB 发布 2.0.1 版。该版本在 2.0.0 (GA) 版的基础上,对 MySQL 兼容性、系统稳定性做出了改进。TiDB 实时更新 Add Index 的进度到 DDL 任务信息中 添加 Session 变量 tidb_auto_analyze_ratio 控制统计信息自动更新阈值 修复当事务提交失败时可能未清理所有的残留状态的问题 修复加索引在部分情况下的 Bug 修复 DDL 修改表面操作在某些并发场景下的正确性问题 修复某些情况下 LIMIT 结果不正确的问题 修复 ADMIN CHECK INDEX 语句索引名字区分大小写问题 修复 UNION 语句的兼容性问题 修复插入 TIME 类型数据的兼容性问题 修复某些情况下 copIteratorTaskSender 导致的 goroutine 泄漏问题 增加一个选项,用于设置 TiDB 在写 Binlog 失败的情况下的行为 优化 Coprocessor 慢请求日志格式,区分处理时间长与排队时间长的任务 MySQL 协议握手阶段发生错误不打印日志,避免 KeepAlive 造成大量日志 优化 Out of range value for column 的错误信息 修复 Update 语句中遇到子查询导致结果错误的问题 调整 TiDB 进程处理 SIGTERM 的行为,不等待正在执行的 Query 完成 PD 添加 Scatter Range 调度,调度指定 Key Range 包含的 Region 优化 Merge Region 调度,使新分裂不久的 Region 不能被合并 添加 learner 相关的 metrics 修复重启误删 scheduler 的问题 修复解析配置文件出错问题 修复 etcd leader 和 PD leader 不同步的问题 修复关闭 learner 情况下还有 learner 出现的问题 修复读取包过大造成 load Regions 失败的问题 TiKV 修复 SELECT FOR UPDATE 阻止其他人读的问题 优化慢查询的日志 减少 thread_yield 的调用次数 修复生成 snapshot 会意外阻塞 raftstore 的 bug 修复特殊情况下开启 learner 无法选举成功的问题 修复极端情况下分裂可能导致的脏读问题 修正读线程池的配置默认值 修正删大数据表会影响写性能的问题 "}, {"url": "https://pingcap.com/docs-cn/releases/2.0.10/", "title": "TiDB 2.0.10 Release Notes", "content": " TiDB 2.0.10 Release Notes 2018 年 12 月 18 日,TiDB 发布 2.0.10 版,TiDB-Ansible 相应发布 2.0.10 版本。该版本在 2.0.9 版的基础上,对系统兼容性、稳定性做出了改进。TiDB 修复取消 DDL 任务的时候可能导致的问题 #8513 修复 ORDER BY,UNION 语句无法引用带表名的列的问题 #8514 修复 UNCOMPRESS 函数没有判断错误输入长度的问题 #8607 修复 ANSI_QUOTES SQL_MODE 在 TiDB 升级的时候遇到的问题 #8575 修复某些情况下 select 返回结果错误的问题 #8570 修复 TiDB 在收到退出信号的时候可能无法退出的问题 #8501 修复某些情况下 IndexLookUpJoin 返回错误结果的问题 #8508 避免下推有 GetVar 或 SetVar 的 filter #8454 修复某些情况下 UNION 语句结果长度错误的问题 #8491 修复 PREPARE FROM @var_name 的问题 #8488 修复某些情况下导出统计信息 panic 的问题 #8464 修复统计信息某些情况下对点查估算的问题 #8493 修复某些情况下返回 Enum 默认值为字符串导致的 panic #8476 修复在宽表场景下,占用太多内存的问题 #8467 修复 Parser 对取模操作错误格式化导致的问题 #8431 修复某些情况下添加外键约束导致的 panic 问题 #8421,#8410 修复 YEAR 类型错误转换零值的问题 #8396 修复 VALUES 函数在参数不为列的时候 panic 的问题 #8404 存在子查询的语句禁用 Plan Cache #8395 PD 修复 RaftCluster 在退出时可能的死锁问题 #1370 TiKV 修复迁移 Leader 到新节点时造成请求延时问题 #3929 修复多余的 Region 心跳 #3930 "}, {"url": "https://pingcap.com/docs/releases/2.0.10/", "title": "TiDB 2.0.10 Release Notes", "content": " TiDB 2.0.10 Release Notes On December 18, 2018, TiDB 2.0.10 is released. The corresponding TiDB-Ansible 2.0.10 is also released. Compared with TiDB 2.0.9, this release has great improvement in system compatibility and stability.TiDB Fix the possible issue caused by canceling a DDL job #8513 Fix the issue that the ORDER BY and UNION clauses cannot quote the column including a table name #8514 Fix the issue that the UNCOMPRESS function does not judge the incorrect input length #8607 Fix the issue encountered by ANSI_QUOTES SQL_MODE when upgrading TiDB #8575 Fix the issue that select returns the wrong result in some cases #8570 Fix the possible issue that TiDB cannot exit when it receives the exit signal #8501 Fix the issue that IndexLookUpJoin returns the wrong result in some cases #8508 Avoid pushing down the filter containing GetVar or SetVar #8454 Fix the issue that the result length of the UNION clauses is incorrect in some cases #8491 Fix the issue of PREPARE FROM @var_name #8488 Fix the panic issue when dumping statistics information in some cases #8464 Fix the statistics estimation issue of point queries in some cases #8493 Fix the panic issue when the returned default enum value is a string #8476 Fix the issue that too much memory is consumed in the scenario of wide tables #8467 Fix the issue encountered when Parser incorrectly formats the mod opcode #8431 Fix the panic issue caused by adding foreign key constraints in some cases #8421, #8410 Fix the issue that the YEAR column type incorrectly converts the zero value #8396 Fix the panic issue occurred when the argument of the VALUES function is not a column #8404 Disable Plan Cache for statements containing subqueries #8395 PD Fix the possible issue that RaftCluster cannot stop caused by deadlock #1370 TiKV Avoid transferring the leader to a newly created peer, to optimize the possible delay #3929 Fix redundant Region heartbeats #3930 "}, {"url": "https://pingcap.com/docs-cn/releases/2.0.11/", "title": "TiDB 2.0.11 Release Notes", "content": " TiDB 2.0.11 Release Notes 2019 年 1 月 3 日,TiDB 发布 2.0.11 版,TiDB-Ansible 相应发布 2.0.11 版本。该版本在 2.0.10 版的基础上,对系统兼容性、稳定性做出了改进。TiDB 修复 PD 发生异常的情况下,Error 没有被正确处理的问题 #8764 修复 Rename 相同表的行为,跟 MySQL 保持一致 #8809 修复 ADMIN CHECK TABLE 在 ADD INDEX 过程中误报的问题 #8750 修复前缀索引在某些情况下,开闭范围区间错误的问题 #8877 修复在某些添加列的情况下,UPDATE 语句 panic 的问题 #8904 TiKV 修复了两个 Region merge 相关的问题 #4003,#4004 "}, {"url": "https://pingcap.com/docs/releases/2.0.11/", "title": "TiDB 2.0.11 Release Notes", "content": " TiDB 2.0.11 Release Notes On January 03, 2019, TiDB 2.0.11 is released. The corresponding TiDB-Ansible 2.0.11 is also released. Compared with TiDB 2.0.10, this release has great improvement in system compatibility and stability.TiDB Fix the issue that the error is not handled properly when PD is in an abnormal condition #8764 Fix the issue that the Rename operation on a table in TiDB is not compatible with that in MySQL #8809 Fix the issue that the error message is wrongly reported when the ADMIN CHECK TABLE operation is performed in the process of executing the ADD INDEX statement #8750 Fix the issue that the prefix index range is incorrect in some cases #8877 Fix the panic issue of the UPDATE statement when columns are added in some cases #8904 TiKV Fix two issues about Region merge #4003, #4004 "}, {"url": "https://pingcap.com/docs/releases/202/", "title": "TiDB 2.0.2 Release Notes", "content": " TiDB 2.0.2 Release Notes On May 21, 2018, TiDB 2.0.2 is released. Compared with TiDB 2.0.1, this release has great improvement in system stability.TiDB Fix the issue of pushing down the Decimal division expression Support using the USE INDEX syntax in the Delete statement Forbid using the shard_row_id_bits feature in columns with Auto-Increment Add the timeout mechanism for writing Binlog PD Make the balance leader scheduler filter the disconnected nodes Modify the timeout of the transfer leader operator to 10s Fix the issue that the label scheduler does not schedule when the cluster Regions are in an unhealthy state Fix the improper scheduling issue of evict leader scheduler TiKV Fix the issue that the Raft log is not printed Support configuring more gRPC related parameters Support configuring the timeout range of leader election Fix the issue that the obsolete learner is not deleted Fix the issue that the snapshot intermediate file is mistakenly deleted "}, {"url": "https://pingcap.com/docs/v2.0/releases/202/", "title": "TiDB 2.0.2 Release Notes", "content": " TiDB 2.0.2 Release Notes On May 21, 2018, TiDB 2.0.2 is released. Compared with TiDB 2.0.1, this release has great improvement in system stability.TiDB Fix the issue of pushing down the Decimal division expression Support using the USE INDEX syntax in the Delete statement Forbid using the shard_row_id_bits feature in columns with Auto-Increment Add the timeout mechanism for writing Binlog PD Make the balance leader scheduler filter the disconnected nodes Modify the timeout of the transfer leader operator to 10s Fix the issue that the label scheduler does not schedule when the cluster Regions are in an unhealthy state Fix the improper scheduling issue of evict leader scheduler TiKV Fix the issue that the Raft log is not printed Support configuring more gRPC related parameters Support configuring the timeout range of leader election Fix the issue that the obsolete learner is not deleted Fix the issue that the snapshot intermediate file is mistakenly deleted "}, {"url": "https://pingcap.com/docs-cn/releases/202/", "title": "TiDB 2.0.2 release notes", "content": " TiDB 2.0.2 Release Notes 2018 年 5 月 21 日,TiDB 发布 2.0.2 版。该版本在 2.0.1 版的基础上,对系统稳定性做出了改进。TiDB 修复 Decimal 除法内置函数下推的问题 支持 Delete 语句中使用 USE INDEX 的语法 禁止在带有 Auto-Increment 的列中使用 shard_row_id_bits 特性 增加写入 Binlog 的超时机制 PD 使 balance leader scheduler 过滤失连节点 更改 transfer leader operator 的超时时间为 10 秒 修复 label scheduler 在集群 Regions 不健康状态下不调度的问题 修复 evict leader scheduler 调度不当的问题 TiKV 修复 Raft 日志没有打出来的问题 支持配置更多 gRPC 相关参数 支持配置选举超时的取值范围 修复过期 learner 没有删掉的问题 修复 snapshot 中间文件被误删的问题 "}, {"url": "https://pingcap.com/docs/releases/203/", "title": "TiDB 2.0.3 Release Notes", "content": " TiDB 2.0.3 Release Notes On June 1, 2018, TiDB 2.0.3 is released. Compared with TiDB 2.0.2, this release has great improvement in system compatibility and stability.TiDB Support modifying the log level online Support the COM_CHANGE_USER command Support using the TIME type parameters under the binary protocol Optimize the cost estimation of query conditions with the BETWEEN expression Do not display the FOREIGN KEY information in the result of SHOW CREATE TABLE Optimize the cost estimation for queries with the LIMIT clause Fix the issue about the YEAR type as the unique index Fix the issue about ON DUPLICATE KEY UPDATE in conditions without the unique index Fix the compatibility issue of the CEIL function Fix the accuracy issue of the DIV calculation in the DECIMAL type Fix the false alarm of ADMIN CHECK TABLE Fix the panic issue of MAX/MIN under specific expression parameters Fix the issue that the result of JOIN is null in special conditions Fix the IN expression issue when building and querying Range Fix a Range calculation issue when using Prepare to query and Plan Cache is enabled Fix the issue that the Schema information is frequently loaded in abnormal conditions PD Fix the panic issue when collecting hot-cache metrics in specific conditions Fix the issue about scheduling of the obsolete Regions TiKV Fix the bug that the learner flag mistakenly reports to PD Report an error instead of getting a result if divisor/dividend is 0 in do_div_mod "}, {"url": "https://pingcap.com/docs/v2.0/releases/203/", "title": "TiDB 2.0.3 Release Notes", "content": " TiDB 2.0.3 Release Notes On June 1, 2018, TiDB 2.0.3 is released. Compared with TiDB 2.0.2, this release has great improvement in system compatibility and stability.TiDB Support modifying the log level online Support the COM_CHANGE_USER command Support using the TIME type parameters under the binary protocol Optimize the cost estimation of query conditions with the BETWEEN expression Do not display the FOREIGN KEY information in the result of SHOW CREATE TABLE Optimize the cost estimation for queries with the LIMIT clause Fix the issue about the YEAR type as the unique index Fix the issue about ON DUPLICATE KEY UPDATE in conditions without the unique index Fix the compatibility issue of the CEIL function Fix the accuracy issue of the DIV calculation in the DECIMAL type Fix the false alarm of ADMIN CHECK TABLE Fix the panic issue of MAX/MIN under specific expression parameters Fix the issue that the result of JOIN is null in special conditions Fix the IN expression issue when building and querying Range Fix a Range calculation issue when using Prepare to query and Plan Cache is enabled Fix the issue that the Schema information is frequently loaded in abnormal conditions PD Fix the panic issue when collecting hot-cache metrics in specific conditions Fix the issue about scheduling of the obsolete Regions TiKV Fix the bug that the learner flag mistakenly reports to PD Report an error instead of getting a result if divisor/dividend is 0 in do_div_mod "}, {"url": "https://pingcap.com/docs-cn/releases/203/", "title": "TiDB 2.0.3 release notes", "content": " TiDB 2.0.3 Release Notes 2018 年 6 月 1 日,TiDB 发布 2.0.3 版。该版本在 2.0.2 版的基础上,对系统兼容性、稳定性做出了改进。TiDB 支持在线更改日志级别 支持 COM_CHANGE_USER 命令 支持二进制协议情况下使用时间类型参数 优化带 BETWEEN 表达式的查询条件代价估算 在 SHOW CREATE TABLE 里不显示 FOREIGN KEY 信息 优化带 LIMIT 子句的查询代价估算 修复 YEAR 类型作为唯一索引的问题 修复在没有唯一索引的情况下 ON DUPLICATE KEY UPDATE 的问题 修复 CEIL 函数的兼容性问题 修复 DECIMAL 类型计算 DIV 的精度问题 修复 ADMIN CHECK TABLE 误报的问题 修复 MAX/MIN 在特定表达式参数下 panic 的问题 修复特殊情况下 JOIN 结果为空的问题 修复 IN 表达式构造查询 Range 的问题 修复使用 Prepare 方式进行查询且启用 Plan Cache 情况下的 Range 计算问题 修复异常情况下频繁加载 Schema 信息的问题 PD 修复在特定条件下收集 hot-cache metrics 会 panic 的问题 修复对旧的 Region 产生调度的问题 TiKV 修复 learner flag 错误上报给 PD 的 bug 在 do_div_mod 中 divisor/dividend 为 0 时返回错误 "}, {"url": "https://pingcap.com/docs/releases/204/", "title": "TiDB 2.0.4 Release Notes", "content": " TiDB 2.0.4 Release Notes On June 15, 2018, TiDB 2.0.4 is released. Compared with TiDB 2.0.3, this release has great improvement in system compatibility and stability.TiDB Support the ALTER TABLE t DROP COLUMN a CASCADE syntax Support configuring the value of tidb_snapshot to TSO Refine the display of statement types in monitoring items Optimize the accuracy of query cost estimation Configure the backoff max delay parameter of gRPC Support configuring the memory threshold of a single statement in the configuration file Refactor the error of Optimizer Fix the side effects of the Cast Decimal data Fix the wrong result issue of the Merge Join operator in specific scenarios Fix the issue of converting the Null object to String Fix the issue of casting the JSON type of data to the JSON type Fix the issue that the result order is not consistent with MySQL in the condition of Union + OrderBy Fix the compliance rules issue when the Union statement checks the Limit/OrderBy clause Fix the compatibility issue of the Union All result Fix a bug in predicate pushdown Fix the compatibility issue of the Union statement with the For Update clause Fix the issue that the concat_ws function mistakenly truncates the result PD Improve the behavior of the unset scheduling argument max-pending-peer-count by changing it to no limit for the maximum number of PendingPeers TiKV Add the RocksDB PerfContext interface for debugging Remove the import-mode parameter Add the region-properties command for tikv-ctl Fix the issue that reverse-seek is slow when many RocksDB tombstones exist Fix the crash issue caused by do_sub Make GC record the log when GC encounters many versions of data "}, {"url": "https://pingcap.com/docs/v2.0/releases/204/", "title": "TiDB 2.0.4 Release Notes", "content": " TiDB 2.0.4 Release Notes On June 15, 2018, TiDB 2.0.4 is released. Compared with TiDB 2.0.3, this release has great improvement in system compatibility and stability.TiDB Support the ALTER TABLE t DROP COLUMN a CASCADE syntax Support configuring the value of tidb_snapshot to TSO Refine the display of statement types in monitoring items Optimize the accuracy of query cost estimation Configure the backoff max delay parameter of gRPC Support configuring the memory threshold of a single statement in the configuration file Refactor the error of Optimizer Fix the side effects of the Cast Decimal data Fix the wrong result issue of the Merge Join operator in specific scenarios Fix the issue of converting the Null object to String Fix the issue of casting the JSON type of data to the JSON type Fix the issue that the result order is not consistent with MySQL in the condition of Union + OrderBy Fix the compliance rules issue when the Union statement checks the Limit/OrderBy clause Fix the compatibility issue of the Union All result Fix a bug in predicate pushdown Fix the compatibility issue of the Union statement with the For Update clause Fix the issue that the concat_ws function mistakenly truncates the result PD Improve the behavior of the unset scheduling argument max-pending-peer-count by changing it to no limit for the maximum number of PendingPeers TiKV Add the RocksDB PerfContext interface for debugging Remove the import-mode parameter Add the region-properties command for tikv-ctl Fix the issue that reverse-seek is slow when many RocksDB tombstones exist Fix the crash issue caused by do_sub Make GC record the log when GC encounters many versions of data "}, {"url": "https://pingcap.com/docs-cn/releases/204/", "title": "TiDB 2.0.4 release notes", "content": " TiDB 2.0.4 Release Notes 2018 年 6 月 15 日,TiDB 发布 2.0.4 版。该版本在 2.0.3 版的基础上,对系统兼容性、稳定性做出了改进。TiDB 支持 ALTER TABLE t DROP COLUMN a CASCADE 语法 支持设置 tidb_snapshot 变量的值为 TSO 优化监控项中语句类型展示 优化查询代价估计精度 设置 gRPC 的 backoff max delay 参数 支持通过配置文件设置单条语句的内存使用阈值 重构 Optimizer 的 error 解决 Cast Decimal 数据的副作用问题 解决特定场景下 Merge Join 算子结果错误的问题 解决转换 Null 对象到 String 的问题 解决 Cast JSON 数据为 JSON 类型的问题 解决 Union + OrderBy 情况下结果顺序和 MySQL 不一致的问题 解决 Union 语句中对 Limit/OrderBy 子句的合法性检查规则问题 解决 Union All 的结果兼容性问题 解决谓词下推中的一个 Bug 解决 Union 语句对 For Update 子句的兼容性问题 解决 concat_ws 函数对结果错误截断的问题 PD 改进 max-pending-peer-count 调度参数未设置时的行为,调整为不限制最大 PendingPeer 的数量 TiKV 新增 RocksDB PerfContext 接口用于调试 移除 import-mode 参数 为 tikv-ctl 添加 region-properties 命令 优化有大量 RocksDB tombstone 时 reverse-seek 过慢的问题 修复 do_sub 导致的崩溃问题 当 GC 遇到有太多版本的数据时记录日志 "}, {"url": "https://pingcap.com/docs/releases/205/", "title": "TiDB 2.0.5 Release Notes", "content": " TiDB 2.0.5 Release Notes On July 6, 2018, TiDB 2.0.5 is released. Compared with TiDB 2.0.4, this release has great improvement in system compatibility and stability.TiDB New Features Add the tidb_disable_txn_auto_retry system variable which is used to disable the automatic retry of transactions #6877 Improvements Optimize the cost calculation of Selection to make the result more accurate #6989 Select the query condition that completely matches the unique index or the primary key as the query path directly #6966 Execute necessary cleanup when failing to start the service #6964 Handle N as NULL in the Load Data statement #6962 Optimize the code structure of CBO #6953 Report the monitoring metrics earlier when starting the service #6931 Optimize the format of slow queries by removing the line breaks in SQL statements and adding user information #6920 Support multiple asterisks in comments #6858 Bug Fixes Fix the issue that KILL QUERY always requires SUPER privilege #7003 Fix the issue that users might fail to login when the number of users exceeds 1024 #6986 Fix an issue about inserting unsigned float/double data #6940 Fix the compatibility of the COM_FIELD_LIST command to resolve the panic issue in some MariaDB clients #6929 Fix the CREATE TABLE IF NOT EXISTS LIKE behavior #6928 Fix an issue in the process of TopN pushdown #6923 Fix the ID record issue of the currently processing row when an error occurs in executing Add Index #6903 PD Fix the issue that replicas migration uses up TiKV disks space in some scenarios Fix the crash issue caused by AdjacentRegionScheduler TiKV Fix the potential overflow issue in decimal operations Fix the dirty read issue that might occur in the process of merging "}, {"url": "https://pingcap.com/docs/v2.0/releases/205/", "title": "TiDB 2.0.5 Release Notes", "content": " TiDB 2.0.5 Release Notes On July 6, 2018, TiDB 2.0.5 is released. Compared with TiDB 2.0.4, this release has great improvement in system compatibility and stability.TiDB New Features Add the tidb_disable_txn_auto_retry system variable which is used to disable the automatic retry of transactions #6877 Improvements Optimize the cost calculation of Selection to make the result more accurate #6989 Select the query condition that completely matches the unique index or the primary key as the query path directly #6966 Execute necessary cleanup when failing to start the service #6964 Handle N as NULL in the Load Data statement #6962 Optimize the code structure of CBO #6953 Report the monitoring metrics earlier when starting the service #6931 Optimize the format of slow queries by removing the line breaks in SQL statements and adding user information #6920 Support multiple asterisks in comments #6858 Bug Fixes Fix the issue that KILL QUERY always requires SUPER privilege #7003 Fix the issue that users might fail to login when the number of users exceeds 1024 #6986 Fix an issue about inserting unsigned float/double data #6940 Fix the compatibility of the COM_FIELD_LIST command to resolve the panic issue in some MariaDB clients #6929 Fix the CREATE TABLE IF NOT EXISTS LIKE behavior #6928 Fix an issue in the process of TopN pushdown #6923 Fix the ID record issue of the currently processing row when an error occurs in executing Add Index #6903 PD Fix the issue that replicas migration uses up TiKV disks space in some scenarios Fix the crash issue caused by AdjacentRegionScheduler TiKV Fix the potential overflow issue in decimal operations Fix the dirty read issue that might occur in the process of merging "}, {"url": "https://pingcap.com/docs-cn/releases/205/", "title": "TiDB 2.0.5 release notes", "content": " TiDB 2.0.5 Release Notes 2018 年 7 月 6 日,TiDB 发布 2.0.5 版。该版本在 2.0.4 版的基础上,对系统兼容性、稳定性做出了改进。TiDB New Features 增加一个系统变量 tidb_disable_txn_auto_retry,用于关闭事务自动重试 #6877 Improvements 调整计算 Selection 代价的方式,结果更准确 #6989 查询条件能够完全匹配唯一索引或者主键时,直接选择作为查询路径 #6966 启动服务失败时,做必要的清理工作 #6964 在 Load Data 语句中,将 N 处理为 NULL #6962 优化 CBO 代码结构 #6953 启动服务时,尽早上报监控数据 #6931 对慢查询日志格式进行优化:去除 SQL 语句中的换行符,增加用户信息 #6920 支持注释中存在多个星号的情况 #6858 Bug Fixes 修复 KILL QUERY 语句权限检查问题 #7003 修复用户数量超过 1024 时可能造成无法登陆的问题 #6986 修复一个写入无符号类型 float/double 数据的问题 #6940 修复 COM_FIELD_LIST 命令的兼容性,解决部分 MariaDB 客户端遇到 Panic 的问题 #6929 修复 CREATE TABLE IF NOT EXISTS LIKE 行为 #6928 修复一个 TopN 下推过程中的问题 #6923 修复 Add Index 过程中遇到错误时当前处理的行 ID 记录问题 #6903 PD 修复某些场景下副本迁移导致 TiKV 磁盘空间耗尽的问题 修复 AdjacentRegionScheduler 导致的崩溃问题 TiKV 修复 decimal 运算中潜在的溢出问题 修复 merge 过程中可能发生的脏读问题 "}, {"url": "https://pingcap.com/docs/releases/206/", "title": "TiDB 2.0.6 Release Notes", "content": " TiDB 2.0.6 Release Notes On August 6, 2018, TiDB 2.0.6 is released. Compared with TiDB 2.0.5, this release has great improvement in system compatibility and stability.TiDB Improvements Make “set system variable” log shorter to save disk space #7031 Record slow operations during the execution of ADD INDEX in the log, to make troubleshooting easier #7083 Reduce transaction conflicts when updating statistics #7138 Improve the accuracy of row count estimation when the values pending to be estimated exceeds the statistics range #7185 Choose the table with a smaller estimated row count as the outer table for Index Join to improve its execution efficiency #7277 Add the recover mechanism for panics occurred during the execution of ANALYZE TABLE, to avoid that the tidb-server is unavailable caused by abnormal behavior in the process of collecting statistics #7228 Return NULL and the corresponding warning when the results of RPAD/LPAD exceed the value of the max_allowed_packet system variable, compatible with MySQL #7244 Set the upper limit of placeholders count in the PREPARE statement to 65535, compatible with MySQL #7250 Bug Fixes Fix the issue that the DROP USER statement is incompatible with MySQL behavior in some cases #7014 Fix the issue that statements like INSERT/LOAD DATA meet OOM aftering opening tidb_batch_insert #7092 Fix the issue that the statistics fail to automatically update when the data of a table keeps updating #7093 Fix the issue that the firewall breaks inactive gPRC connections #7099 Fix the issue that prefix index returns a wrong result in some scenarios #7126 Fix the panic issue caused by outdated statistics in some scenarios #7155 Fix the issue that one piece of index data is missed after the ADD INDEX operation in some scenarios #7156 Fix the wrong result issue when querying NULL values using the unique index in some scenarios #7172 Fix the messy code issue of the DECIMAL multiplication result in some scenarios #7212 Fix the wrong result issue of DECIMAL modulo operation in some scenarios #7245 Fix the issue that the UPDATE/DELETE statement in a transaction returns a wrong result under some special sequence of statements #7219 Fix the panic issue of the UNION ALL/UPDATE statement during the process of building the execution plan in some scenarios #7225 Fix the issue that the range of prefix index is calculated incorrectly in some scenarios #7231 Fix the issue that the LOAD DATA statement fails to write the binlog in some scenarios #7242 Fix the wrong result issue of SHOW CREATE TABLE during the execution process of ADD INDEX in some scenarios #7243 Fix the issue that panic occurs when Index Join does not initialize timestamps in some scenarios #7246 Fix the false alarm issue when ADMIN CHECK TABLE mistakenly uses the timezone in the session #7258 Fix the issue that ADMIN CLEANUP INDEX does not clean up the index in some scenarios #7265 Disable the Read Committed isolation level #7282 TiKV Improvements Enlarge scheduler’s default slots to reduce false conflicts Reduce continuous records of rollback transactions, to improve the Read performance when conflicts are extremely severe Limit the size and number of RocksDB log files, to reduce unnecessary disk usage in long-running condition Bug Fixes Fix the crash issue when converting the data type from string to decimal "}, {"url": "https://pingcap.com/docs/v2.0/releases/206/", "title": "TiDB 2.0.6 Release Notes", "content": " TiDB 2.0.6 Release Notes On August 6, 2018, TiDB 2.0.6 is released. Compared with TiDB 2.0.5, this release has great improvement in system compatibility and stability.TiDB Improvements Make “set system variable” log shorter to save disk space #7031 Record slow operations during the execution of ADD INDEX in the log, to make troubleshooting easier #7083 Reduce transaction conflicts when updating statistics #7138 Improve the accuracy of row count estimation when the values pending to be estimated exceeds the statistics range #7185 Choose the table with a smaller estimated row count as the outer table for Index Join to improve its execution efficiency #7277 Add the recover mechanism for panics occurred during the execution of ANALYZE TABLE, to avoid that the tidb-server is unavailable caused by abnormal behavior in the process of collecting statistics #7228 Return NULL and the corresponding warning when the results of RPAD/LPAD exceed the value of the max_allowed_packet system variable, compatible with MySQL #7244 Set the upper limit of placeholders count in the PREPARE statement to 65535, compatible with MySQL #7250 Bug Fixes Fix the issue that the DROP USER statement is incompatible with MySQL behavior in some cases #7014 Fix the issue that statements like INSERT/LOAD DATA meet OOM aftering opening tidb_batch_insert #7092 Fix the issue that the statistics fail to automatically update when the data of a table keeps updating #7093 Fix the issue that the firewall breaks inactive gPRC connections #7099 Fix the issue that prefix index returns a wrong result in some scenarios #7126 Fix the panic issue caused by outdated statistics in some scenarios #7155 Fix the issue that one piece of index data is missed after the ADD INDEX operation in some scenarios #7156 Fix the wrong result issue when querying NULL values using the unique index in some scenarios #7172 Fix the messy code issue of the DECIMAL multiplication result in some scenarios #7212 Fix the wrong result issue of DECIMAL modulo operation in some scenarios #7245 Fix the issue that the UPDATE/DELETE statement in a transaction returns a wrong result under some special sequence of statements #7219 Fix the panic issue of the UNION ALL/UPDATE statement during the process of building the execution plan in some scenarios #7225 Fix the issue that the range of prefix index is calculated incorrectly in some scenarios #7231 Fix the issue that the LOAD DATA statement fails to write the binlog in some scenarios #7242 Fix the wrong result issue of SHOW CREATE TABLE during the execution process of ADD INDEX in some scenarios #7243 Fix the issue that panic occurs when Index Join does not initialize timestamps in some scenarios #7246 Fix the false alarm issue when ADMIN CHECK TABLE mistakenly uses the timezone in the session #7258 Fix the issue that ADMIN CLEANUP INDEX does not clean up the index in some scenarios #7265 Disable the Read Committed isolation level #7282 TiKV Improvements Enlarge scheduler’s default slots to reduce false conflicts Reduce continuous records of rollback transactions, to improve the Read performance when conflicts are extremely severe Limit the size and number of RocksDB log files, to reduce unnecessary disk usage in long-running condition Bug Fixes Fix the crash issue when converting the data type from string to decimal "}, {"url": "https://pingcap.com/docs-cn/releases/206/", "title": "TiDB 2.0.6 release notes", "content": " TiDB 2.0.6 Release Notes 2018 年 8 月 6 日,TiDB 发布 2.0.6 版。该版本在 2.0.5 版的基础上,对系统兼容性、稳定性做出了改进。TiDB Improvements 精简 “set system variable” 日志的长度,减少日志文件体积 #7031 在日志中记录 ADD INDEX 执行过程中的慢操作,便于定位问题 #7083 减少更新统计信息操作中的事务冲突 #7138 当待估算的值超过统计信息范围时,提高行数估计的准确度 #7185 当使用 Index Join 时,选择行数估计较小的表作为驱动表,提高 Index Join 的执行效率 #7227 为 ANALYZE TABLE 语句执行过程中发生的 panic 添加 recover 机制,避免收集统计信息过程中的异常行为导致 tidb-server 不可用 #7228 当 RPAD/LPAD 的结果超过设置系统变量 max_allowed_packet 时,返回 NULL 和对应的 warning,兼容 MySQL #7244 设置 PREPARE 语句中占位符数量上限为 65535,兼容 MySQL #7250 Bug Fixes 修复某些情况下,DROP USER 语句和 MySQL 行为不兼容的问题 #7014 修复当 tidb_batch_insert 打开后,INSERT/LOAD DATA 等语句在某些场景下 OOM 的问题 #7092 修复某个表的数据持续更新时,其统计信息自动更新失效的问题 #7093 修复防火墙断掉不活跃的 gRPC 连接的问题 #7099 修复某些场景下使用前缀索引结果不正确的问题 #7126 修复某些场景下统计信息过时导致 panic 的问题 #7155 修复某些场景下 ADD INDEX 后索引数据少一条的问题 #7156 修复某些场景下查询唯一索引上的 NULL 值结果不正确的问题 #7172 修复某些场景下 DECIMAL 的乘法结果出现乱码的问题 #7212 修复某些场景下 DECIMAL 的取模运算结果不正确的问题 #7245 修复某些特殊语句序列下在事务中执行 UPDATE/DELETE 语句后结果不正确的问题 #7219 修复某些场景下 UNION ALL/UPDATE 语句在构造执行计划过程中 panic 的问题 #7225 修复某些场景下前缀索引的索引范围计算错误的问题 #7231 修复某些场景下 LOAD DATA 语句不写 binlog 的问题 #7242 修复某些场景下在 ADD INDEX 过程中 SHOW CREATE TABLE 结果不正确的问题 #7243 修复某些场景下 Index Join 因为没有初始化事务时间戳而 panic 的问题 #7246 修复 ADMIN CHECK TABLE 因为误用 session 中的时区而导致误报的问题 #7258 修复 ADMIN CLEANUP INDEX 在某些场景下索引没有清除干净的问题 #7265 禁用 Read Committed 事务隔离级别 #7282 TiKV Improvements 扩大默认 scheduler slots 值以减少假冲突现象 减少回滚事务的连续标记以提升冲突极端严重下的读性能 限制 RocksDB log 文件的大小和个数以减少长时间运行下不必要的磁盘占用 Bug Fixes 修复字符串转 Decimal 时出现的 crash "}, {"url": "https://pingcap.com/docs/releases/207/", "title": "TiDB 2.0.7 Release Notes", "content": " TiDB 2.0.7 Release Notes On September 7, 2018, TiDB 2.0.7 is released. Compared with TiDB 2.0.6, this release has great improvement in system compatibility and stability.TiDB New Feature Add the PROCESSLIST table in information_schema #7286 Improvement Collect more details about SQL statement execution and output the information in the SLOW QUERY log #7364 Drop the partition information in SHOW CREATE TABLE #7388 Improve the execution efficiency of the ANALYZE statement by setting it to the RC isolation level and low priority #7500 Speed up adding a unique index #7562 Add an option of controlling the DDL concurrency #7563 Bug Fixes Fix the issue that USE INDEX(PRIMARY) cannot be used in a table whose primary key is an integer #7298 Fix the issue that Merge Join and Index Join output incorrect results when the inner row is NULL #7301 Fix the issue that Join outputs an incorrect result when the chunk size is set too small #7315 Fix the panic issue caused by a statement of creating a table involving range column #7379 Fix the issue that admin check table mistakenly reports an error of a time-type column #7457 Fix the issue that the data with a default value current_timestamp cannot be queried using the = condition #7467 Fix the issue that the zero-length parameter inserted by using the ComStmtSendLongData command is mistakenly parsed to NULL #7508 Fix the issue that auto analyze is repeatedly executed in specific scenarios #7556 Fix the issue that the parser cannot parse a single line comment ended with a newline character #7635 TiKV Improvement Open the dynamic-level-bytes parameter in an empty cluster by default, to reduce space amplification Bug Fix Update approximate size and approximate keys count of a Region after Region merging "}, {"url": "https://pingcap.com/docs-cn/releases/207/", "title": "TiDB 2.0.7 release notes", "content": " TiDB 2.0.7 Release Notes 2018 年 9 月 7 日,TiDB 发布 2.0.7 版。该版本在 2.0.6 版的基础上,对系统兼容性、稳定性做出了改进。TiDB New Feature 在 information_schema 里添加 PROCESSLIST 表 #7286 Improvements 收集更多语句执行细节,并输出在 SLOW QUERY 日志里 #7364 SHOW CREATE TABLE 不再输出分区信息 #7388 通过设置 RC 隔离级别和低优先级优化 ANALYZE 语句执行效率 #7500 加速 ADD UNIQUE INDEX #7562 增加控制 DDL 并发度的选项 #7563 Bug Fixes 修复 PRIMARY KEY 为整数的表,无法使用 USE INDEX(PRIMARY) 的问题 #7298 修复 Merge Join 和 Index Join 在 inner row 为 NULL 时输出多余结果的问题 #7301 修复 chunk size 设置过小时,Join 输出多余结果的问题 #7315 修复建表语句中包含 range column 语法导致 panic 的问题 #7379 修复 admin check table 对时间类型的列误报的问题 #7457 修复以默认值 current_timestamp 插入的数据无法用 = 条件查询到的问题 #7467 修复以 ComStmtSendLongData 命令插入空字符串参数被误解析为 NULL 的问题 #7508 修复特定场景下 auto analyze 不断重复执行的问题 #7556 修复 parser 无法解析以换行符结尾的单行注释的问题 #7635 TiKV Improvement 空集群默认打开 dynamic-level-bytes 参数减少空间放大 Bug Fix 在 Region merge 之后更新 Region 的 approximate size 和 keys "}, {"url": "https://pingcap.com/docs/releases/208/", "title": "TiDB 2.0.8 Release Notes", "content": " TiDB 2.0.8 Release Notes On October 16, 2018, TiDB 2.0.8 is released. Compared with TiDB 2.0.7, this release has great improvement in system compatibility and stability.TiDB Improvement Slow down the AUTO-ID increasing speed when the Update statement does not modify the corresponding AUTO-INCREMENT column #7846 Bug fixes Quickly create a new etcd session to recover the service when the PD leader goes down #7810 Fix the issue that the time zone is not considered when the default value of the DateTime type is calculated #7672 Fix the issue that duplicate key update inserts values incorrectly in some conditions #7685 Fix the issue that the predicate conditions of UnionScan are not pushed down #7726 Fix the issue that the time zone is not correctly handled when you add the TIMESTAMP index #7812 Fix the memory leak issue caused by the statistics module in some conditions #7864 Fix the issue that the results of ANALYZE cannot be obtained in some abnormal conditions #7871 Do not fold the function SYSDATE, to ensure the returned results are correct #7894 Fix the substring_index panic issue in some conditions #7896 Fix the issue that OUTER JOIN is mistakenly converted to INNER JOIN in some conditions #7899 TiKV Bug fix Fix the issue that the memory consumed by Raftstore EntryCache keeps increasing when a node goes down #3529 "}, {"url": "https://pingcap.com/docs-cn/releases/208/", "title": "TiDB 2.0.8 release notes", "content": " TiDB 2.0.8 Release Notes 2018 年 10 月 16 日,TiDB 发布 2.0.8 版。该版本在 2.0.7 版的基础上,对系统兼容性、稳定性做出了改进。TiDB 功能改进 在 Update 没有更改相应 AUTO-INCREMENT 列情况下,防止 AUTO-ID 被消耗过快 #7846 Bug 修复 在 PD Leader 异常宕机的情况下,TiDB 快速创建 etcd Session 恢复服务 #7810 修复 DateTime 类型使用默认值时候没有考虑时区的问题 #7672 修复 duplicate key update 在某些情况下没有正确插入值的问题 #7685 修复 UnionScan 中谓词条件没有下推的问题 #7726 修复增加 TIMESTAMP 索引没有正确处理时区的问题 #7812 修复某些情况下统计信息模块导致的内存泄露问题 #7864 修复在某些异常情况下,无法获得 ANALYZE 结果的问题 #7871 令 SYSDATE 不做表达式展开,以返回正确的结果 #7894 修复某些情况下,substring_index panic 的问题 #7896 修复某些情况下,错误将 OUTER JOIN 转为 INNER JOIN 的问题 #7899 TiKV Bug 修复 修复节点宕机时 Raftstore EntryCache 占用内存持续上升的问题 #3529 "}, {"url": "https://pingcap.com/docs-cn/releases/209/", "title": "TiDB 2.0.9 Release Notes", "content": " TiDB 2.0.9 Release Notes 2018 年 11 月 19 日,TiDB 发布 2.0.9 版。该版本在 2.0.8 版的基础上,对系统兼容性、稳定性做出了改进。TiDB 修复统计信息直方图为空的时候导致的问题 #7927 修复 UNION ALL 语句在某些情况下 panic 的问题 #7942 修复错误的 DDL JOB 情况下导致的递归溢出问题 #7959 为 Commit 操作加上慢操作日志 #7983 修复 Limit 值太大的情况下导致的 panic 问题 #8004 支持 USING 子句指定 utf8mb4 字符集 #8048 内建函数 TRUNCATE 支持类型为 unsigned int 的参数 #8069 修复统计信息模块在某些情况下主键选择率估算的问题 #8150 增加 Session 变量来控制是否允许写入 _tidb_rowid #8126 修复 PhysicalProjection 在某些情况下 panic 的问题 #8154 修复 Union 语句在某些情况下结果不稳定的问题 #8168 修复在非插入语句下 values 没有返回 NULL 的问题 #8179 修复某些情况下统计信息模块无法清除过期统计数据的问题 #8184 让事务允许的最长运行时间变成一个可配置项 #8209 修复 expression rewriter 某些情况下错误的比较逻辑 #8288 消除 UNION ORDER BY 语句生成的多余列的问题 #8307 支持 admin show next_row_id 语句 #8274 修复 Show Create Table 语句中特殊字符转义的问题 #8321 修复 UNION 语句在某些情况下遇到非预期错误的问题 #8318 修复某些情况下取消 DDL 任务导致的 Schema 没有回滚的问题 #8312 把变量 tidb_max_chunk_size 变成全局环境变量 #8333 ticlient Scan 命令增加边界,解决数据扫出边界的问题 #8309 #8310 PD 修复 etcd 启动失败导致的服务挂起问题 #1267 修复 pd-ctl 读取 Region key 的相关问题 #1298 #1299 #1308 修复 regions/check API 输出错误的问题 #1311 修复 PD join 失败后无法重新 join 的问题 1279 TiKV 增加 kv_scan 接口扫描上界的限制 #3749 废弃配置 max-tasks-xxx 并新增 max-tasks-per-worker-xxx #3093 修复 RocksDB CompactFiles 的问题 #3789 "}, {"url": "https://pingcap.com/docs/releases/209/", "title": "TiDB 2.0.9 Release Notes", "content": " TiDB 2.0.9 Release Notes On November 19, 2018, TiDB 2.0.9 is released. Compared with TiDB 2.0.8, this release has great improvement in system compatibility and stability.TiDB Fix the issue caused by the empty statistics histogram #7927 Fix the panic issue of the UNION ALL statement in some cases #7942 Fix the stack overflow issue caused by wrong DDL Jobs #7959 Add the slow log for the Commit operation #7983 Fix the panic issue caused by the too large Limit value #8004 Support specifying the utf8mb4 character set in the USING clause #8048 Make the TRUNCATE built-in function support parameters of unsigned integer type #8069 Fix the selectivity estimation issue of the primary key for the statistics module in some cases #8150 Add the Session variable to control whether _tidb_rowid is allowed to be written in #8126 Fix the panic issue of PhysicalProjection in some cases #8154 Fix the unstable results of the Union statement in some cases #8168 Fix the issue that NULL is not returned by values in the non-Insert statement #8179 Fix the issue that the statistics module cannot clear the outdated data in some cases #8184 Make the maximum allowed running time for a transaction a configurable option 8209 Fix the wrong comparison algorithm of expression rewriter in some cases #8288 Eliminate the extra columns generated by the UNION ORDER BY statement #8307 Support the admin show next_row_id statement #8274 Fix the escape issue of special characters in the Show Create Table statement #8321 Fix the unexpected errors in the UNION statement in some cases #8318 Fix the issue that canceling a DDL job causes no rollback of a schema in some cases #8312 Change tidb_max_chunk_size to a global variable #8333 Add an upper bound to the Scan command of ticlient, to avoid overbound scan #8309 #8310 PD Fix the issue that the PD server gets stuck caused by etcd startup failure #1267 Fix the issues related to pd-ctl reading the Region key #1298 #1299 #1308 Fix the issue that the regions/check API returns the wrong result #1311 Fix the issue that PD cannot restart join after a PD join failure #1279 TiKV Add the end-key limit to the kv_scan interface #3749 Abandon the max-tasks-xxx configuration and add max-tasks-per-worker-xxx #3093 Fix the CompactFiles issue in RocksDB #3789 "}, {"url": "https://pingcap.com/docs-cn/releases/21beta/", "title": "TiDB 2.1 Beta Release Notes", "content": " TiDB 2.1 Beta Release Notes 2018 年 6 月 29 日,TiDB 发布 2.1 Beta 版。相比 2.0 版本,该版本对系统稳定性、优化器、统计信息以及执行引擎做了很多改进。TiDB SQL 优化器 优化 Index Join 选择范围,提升执行性能 优化关联子查询,下推 Filter 和扩大索引选择范围,部分查询的效率有数量级的提升 在 UPDATE、DELETE 语句中支持 Index Hint 和 Join Hint 优化器 Hint TIDM_SMJ 在没有索引可用的情况下可生效 支持更多函数下推:ABS/CEIL/FLOOR/IS TRUE/IS FALSE 在常量折叠过程中特殊处理函数 IF 和 IFNULL 优化 EXPLAIN 语句输出格式 SQL 执行引擎 实现并行 Hash Aggregate 算子,部分场景下能提高 Hash Aggregate 计算性能 350% 实现并行 Project 算子,部分场景下性能提升达 74% 并发地读取 Hash Join 的 Inner 表和 Outer 表的数据,提升执行性能 修复部分场景下 INSERT … ON DUPLICATE KEY UPDATE … 结果不正确的问题 修复 CONCAT_WS/FLOOR/CEIL/DIV 内建函数的结果不正确的问题 Server 添加 HTTP API 打散 table 的 Regions 在 TiKV 集群中的分布 添加 auto_analyze_ratio 系统变量控制自动 analyze 的阈值 添加 HTTP API 控制是否打开 general log 添加 HTTP API 在线修改日志级别 在 general log 和 slow query log 中添加 user 信息 支持 Server side cursor 兼容性 支持更多 MySQL 语法 BIT 聚合函数支持 ALL 参数 支持 SHOW PRIVILEGES 语句 DML 减少 INSERT INTO SELECT 语句的内存占用 修复 Plan Cache 的性能问题 添加 tidb_retry_limit 系统变量控制事务自动重试的次数 添加 tidb_disable_txn_auto_retry 系统变量控制事务是否自动重试 修复写入 time 类型的数据精度问题 支持本地冲突事务排队,优化冲突事务性能 修复 UPDATE 语句的 Affected Rows 优化 insert ignore on duplicate key update 语句性能 优化 Create Table 语句的执行速度 优化 Add index 的速度,在某些场景下速度大幅提升 修复 Alter table add column 增加列超过表的列数限制的问题 修复在某些异常情况下 DDL 任务重试导致 TiKV 压力增加的问题 修复在某些异常情况下 TiDB 不断重载 Schema 信息的问题 DDL Show Create Table 不再输出外键相关的内容 支持 select tidb_is_ddl_owner() 语句,方便判断 TiDB 是否为 DDL Owner 修复某些场景下 YEAR 类型删除索引的问题 修复并发执行场景下的 Rename table 的问题 支持 ALTER TABLE FORCE 语法 支持 ALTER TABLE RENAME KEY TO 语法 admin show ddl jobs 输出信息中添加表名、库名等信息 PD PD 节点间开启 Raft PreVote,避免网络隔离后恢复时产生的重新选举 优化 Balance Scheduler 频繁调度小 Region 的问题 优化热点调度器,在流量统计信息抖动时适应性更好 region merge 调度时跳过数据行数较多的 Region 默认开启 raft learner 功能,降低调度时出现宕机导致数据不可用的风险 pd-recover 移除 max-replica 参数 增加 Filter相关的 metrics 修复 tikv-ctl unsafe recovery 之后 Region 信息没更新的问题 修复某些场景下副本迁移导致 TiKV 磁盘空间耗尽的问题 兼容性提示 由于新版本存储引擎更新,不支持在升级后回退至 2.0.x 或更旧版本 新版本默认开启 raft learner 功能,如果从 1.x 版本集群升级至 2.1 版本,须停机升级或者先滚动升级 TiKV,完成后再滚动升级 PD TiKV 升级 Rust 到 nightly-2018-06-14 版本 开启 PreVote,避免网络隔离后恢复时产生的重新选举 添加 metric,显示 RocksDB 内部每层的文件数和 ingest 相关的信息 GC 运行时打印版本太多的 key 使用 static metric 优化多 label metric 性能(YCSB raw get 提升 3%) 去掉多个模块的 box,使用范型提升运行时性能(YCSB raw get 提升 3%) 使用 asynchronous log 提升写日志性能 增加收集线程状态的 metric 通过减少程序中 box 的使用来减少内存拷贝的次数,提升性能 "}, {"url": "https://pingcap.com/docs/releases/21beta/", "title": "TiDB 2.1 Beta Release Notes", "content": " TiDB 2.1 Beta Release Notes On June 29, 2018, TiDB 2.1 Beta is released! Compared with TiDB 2.0, this release has great improvement in stability, SQL optimizer, statistics information, and execution engine.TiDB SQL Optimizer Optimize the selection range of Index Join to improve the execution performance Optimize correlated subquery, push down Filter, and extend the index range, to improve the efficiency of some queries by orders of magnitude Support Index Hint and Join Hint in the UPDATE and DELETE statements Validate Hint TIDM_SMJ when no available index exists Support pushdown of the ABS, CEIL, FLOOR, IS TRUE, and IS FALSE functions Handle the IF and IFNULL functions especially in the constant folding process SQL Execution Engine Implement parallel Hash Aggregate operators and improve the computing performance of Hash Aggregate by 350% in some scenarios Implement parallel Project operators and improve the performance by 74% in some scenarios Read the data of the Inner table and Outer table of Hash Join concurrently to improve the execution performance Fix incorrect results of INSERT … ON DUPLICATE KEY UPDATE … in some scenarios Fix incorrect results of the CONCAT_WS, FLOOR, CEIL, and DIV built-in functions Server Add the HTTP API to scatter the distribution of table Regions in the TiKV cluster Add the auto_analyze_ratio system variable to control the threshold value of automatic Analyze Add the HTTP API to control whether to open the general log Add the HTTP API to modify the log level online Add the user information in the general log and the slow query log Support the server side cursor Compatibility Support more MySQL syntax Make the bit aggregate function support the ALL parameter Support the SHOW PRIVILEGES statement DML Decrease the memory usage of the INSERT INTO SELECT statement Fix the performance issue of PlanCache Add the tidb_retry_limit system variable to control the automatic retry times of transactions Add the tidb_disable_txn_auto_retry system variable to control whether the transaction tries automatically Fix the accuracy issue of the written data of the time type Support the queue of locally conflicted transactions to optimize the conflicted transaction performance Fix Affected Rows of the UPDATE statement Optimize the statement performance of insert ignore on duplicate key update DDL Optimize the execution speed of the CreateTable statement Optimize the execution speed of ADD INDEX and improve it greatly in some scenarios Fix the issue that the number of added columns by Alter table add column exceeds the limit of the number of table columns Fix the issue that DDL job retries lead to an increasing pressure on TiKV in abnormal conditions Fix the issue that TiDB continuously reloads the schema information in abnormal conditions Do not output the FOREIGN KEY related information in the result of SHOW CREATE TABLE Support the select tidb_is_ddl_owner() statement to facilitate judging whether TiDB is DDL Owner Fix the issue that the index is deleted in the Year type in some scenarios Fix the renaming table issue in the concurrent execution scenario Support the AlterTableForce syntax Support the AlterTableRenameIndex syntax with FromKey and ToKey Add the table name and database name in the output information of admin show ddl jobs PD Enable Raft PreVote between PD nodes to avoid leader reelection when network recovers after network isolation Optimize the issue that Balance Scheduler schedules small Regions frequently Optimize the hotspot scheduler to improve its adaptability in traffic statistics information jitters Skip the Regions with a large number of rows when scheduling region merge Enable raft learner by default to lower the risk of unavailable data caused by machine failure during scheduling Remove max-replica from pd-recover Add Filter metrics Fix the issue that Region information is not updated after tikv-ctl unsafe recovery Fix the issue that TiKV disk space is used up caused by replica migration in some scenarios Compatibility notes Do not support rolling back to v2.0.x or earlier due to update of the new version storage engine Enable raft learner by default in the new version of PD. If the cluster is upgraded from 1.x to 2.1, the machine should be stopped before upgrade or a rolling update should be first applied to TiKV and then PD TiKV Upgrade Rust to the nightly-2018-06-14 version Enable Raft PreVote to avoid leader reelection generated when network recovers after network isolation Add a metric to display the number of files and ingest related information in each layer of RocksDB Print key with too many versions when GC works Use static metric to optimize multi-label metric performance (YCSB raw get is improved by 3%) Remove box in multiple modules and use patterns to improve the operating performance (YCSB raw get is improved by 3%) Use asynchronous log to improve the performance of writing logs Add a metric to collect the thread status Decease memory copy times by decreasing box used in the application to improve the performance "}, {"url": "https://pingcap.com/docs/v2.0/releases/21beta/", "title": "TiDB 2.1 Beta Release Notes", "content": " TiDB 2.1 Beta Release Notes On June 29, 2018, TiDB 2.1 Beta is released! Compared with TiDB 2.0, this release has great improvement in stability, SQL optimizer, statistics information, and execution engine.TiDB SQL Optimizer Optimize the selection range of Index Join to improve the execution performance Optimize correlated subquery, push down Filter, and extend the index range, to improve the efficiency of some queries by orders of magnitude Support Index Hint and Join Hint in the UPDATE and DELETE statements Validate Hint TIDM_SMJ when no available index exists Support pushdown of the ABS, CEIL, FLOOR, IS TRUE, and IS FALSE functions Handle the IF and IFNULL functions especially in the constant folding process SQL Execution Engine Implement parallel Hash Aggregate operators and improve the computing performance of Hash Aggregate by 350% in some scenarios Implement parallel Project operators and improve the performance by 74% in some scenarios Read the data of the Inner table and Outer table of Hash Join concurrently to improve the execution performance Fix incorrect results of INSERT … ON DUPLICATE KEY UPDATE … in some scenarios Fix incorrect results of the CONCAT_WS, FLOOR, CEIL, and DIV built-in functions Server Add the HTTP API to scatter the distribution of table Regions in the TiKV cluster Add the auto_analyze_ratio system variable to control the threshold value of automatic Analyze Add the HTTP API to control whether to open the general log Add the HTTP API to modify the log level online Add the user information in the general log and the slow query log Support the server side cursor Compatibility Support more MySQL syntax Make the bit aggregate function support the ALL parameter Support the SHOW PRIVILEGES statement DML Decrease the memory usage of the INSERT INTO SELECT statement Fix the performance issue of PlanCache Add the tidb_retry_limit system variable to control the automatic retry times of transactions Add the tidb_disable_txn_auto_retry system variable to control whether the transaction tries automatically Fix the accuracy issue of the written data of the time type Support the queue of locally conflicted transactions to optimize the conflicted transaction performance Fix Affected Rows of the UPDATE statement Optimize the statement performance of insert ignore on duplicate key update DDL Optimize the execution speed of the CreateTable statement Optimize the execution speed of ADD INDEX and improve it greatly in some scenarios Fix the issue that the number of added columns by Alter table add column exceeds the limit of the number of table columns Fix the issue that DDL job retries lead to an increasing pressure on TiKV in abnormal conditions Fix the issue that TiDB continuously reloads the schema information in abnormal conditions Do not output the FOREIGN KEY related information in the result of SHOW CREATE TABLE Support the select tidb_is_ddl_owner() statement to facilitate judging whether TiDB is DDL Owner Fix the issue that the index is deleted in the Year type in some scenarios Fix the renaming table issue in the concurrent execution scenario Support the AlterTableForce syntax Support the AlterTableRenameIndex syntax with FromKey and ToKey Add the table name and database name in the output information of admin show ddl jobs PD Enable Raft PreVote between PD nodes to avoid leader reelection when network recovers after network isolation Optimize the issue that Balance Scheduler schedules small Regions frequently Optimize the hotspot scheduler to improve its adaptability in traffic statistics information jitters Skip the Regions with a large number of rows when scheduling region merge Enable raft learner by default to lower the risk of unavailable data caused by machine failure during scheduling Remove max-replica from pd-recover Add Filter metrics Fix the issue that Region information is not updated after tikv-ctl unsafe recovery Fix the issue that TiKV disk space is used up caused by replica migration in some scenarios Compatibility notes Do not support rolling back to v2.0.x or earlier due to update of the new version storage engine Enable raft learner by default in the new version of PD. If the cluster is upgraded from 1.x to 2.1, the machine should be stopped before upgrade or a rolling update should be first applied to TiKV and then PD TiKV Upgrade Rust to the nightly-2018-06-14 version Enable Raft PreVote to avoid leader reelection generated when network recovers after network isolation Add a metric to display the number of files and ingest related information in each layer of RocksDB Print key with too many versions when GC works Use static metric to optimize multi-label metric performance (YCSB raw get is improved by 3%) Remove box in multiple modules and use patterns to improve the operating performance (YCSB raw get is improved by 3%) Use asynchronous log to improve the performance of writing logs Add a metric to collect the thread status Decease memory copy times by decreasing box used in the application to improve the performance "}, {"url": "https://pingcap.com/docs-cn/releases/2.1ga/", "title": "TiDB 2.1 GA Release Notes", "content": " TiDB 2.1 GA Release Notes 2018 年 11 月 30 日,TiDB 发布 2.1 GA 版。相比 2.0 版本,该版本对系统稳定性、性能、兼容性、易用性做了大量改进。TiDB SQL 优化器 优化 Index Join 选择范围,提升执行性能 优化 Index Join 外表选择,使用估算的行数较少的表作为外表 扩大 Join Hint TIDB_SMJ 的作用范围,在没有合适索引可用的情况下也可使用 Merge Join 加强 Join Hint TIDB_INLJ 的能力,可以指定 Join 中的内表 优化关联子查询,包括下推 Filter 和扩大索引选择范围,部分查询的效率有数量级的提升 支持在 UPDATE 和 DELETE 语句中使用 Index Hint 和 Join Hint 支持更多函数下推:ABS/CEIL/FLOOR/IS TRUE/IS FALSE 优化内建函数 IF 和 IFNULL 的常量折叠算法 优化 EXPLAIN 语句输出格式, 使用层级结构表示算子之间的上下游关系 SQL 执行引擎 重构所有聚合函数,提升 Stream 和 Hash 聚合算子的执行效率 实现并行 Hash Aggregate 算子,部分场景下有 350% 的性能提升 实现并行 Project 算子,部分场景有 74% 的性能提升 并发地读取 Hash Join 的 Inner 表和 Outer 表的数据,提升执行性能 优化 REPLACE INTO 语句的执行速度,性能提升 10x 优化时间类型的内存占用,时间类型数据的内存使用降低为原来的一半 优化点查的查询性能,Sysbench 点查效率提升 60% TiDB 插入和更新宽表,性能提升接近 20 倍 支持在配置文件中设置单个查询的内存使用上限 优化 Hash Join 的执行过程,当 Join 类型为 Inner Join 或者 Semi Join 时,如果内表为空,不再读取外表数据,快速返回结果 支持 EXPLAIN ANALYZE 语句,用于查看 Query 执行过程中各个算子的运行时间,返回结果行数等运行时统计信息 统计信息 支持只在一天中的某个时间段开启统计信息自动 ANALYZE 的功能 支持根据查询的反馈自动更新表的统计信息 支持通过 ANALYZE TABLE WITH BUCKETS 语句配置直方图中桶的个数 优化等值查询和范围查询混合的情况下使用直方图估算 Row Count 的算法 表达式 支持内建函数: json_contains json_contains_path encode/decode Server 支持在单个 tidb-server 实例内部对冲突事务排队,优化事务间冲突频繁的场景下的性能 支持 Server Side Cursor 新增 HTTP 管理接口 打散 table 的 Regions 在 TiKV 集群中的分布 控制是否打开 general log 在线修改日志级别 查询 TiDB 集群信息 添加 auto_analyze_ratio 系统变量控制自动 Analyze 的阈值 添加 tidb_retry_limit 系统变量控制事务自动重试的次数 添加 tidb_disable_txn_auto_retry 系统变量控制事务是否自动重试 支持使用 admin show slow 语句来获取慢查询语句 增加环境变量 tidb_slow_log_threshold 动态设置 slow log 的阈值 增加环境变量 tidb_query_log_max_len 动态设置日志中被截断的原始 SQL 语句的长度 DDL 支持 Add Index 语句与其他 DDL 语句并行执行,避免耗时的 Add Index 操作阻塞其他操作 优化 Add Index 的速度,在某些场景下速度大幅提升 支持 select tidb_is_ddl_owner() 语句,方便判断 TiDB 是否为 DDL Owner 支持 ALTER TABLE FORCE 语法 支持 ALTER TABLE RENAME KEY TO 语法 Admin Show DDL Jobs 输出结果中添加表名、库名等信息 支持使用 ddl/owner/resign HTTP 接口释放 DDL Owner 并开启新一轮 DDL Owner 选举 兼容性 支持更多 MySQL 语法 BIT 聚合函数支持 ALL 参数 支持 SHOW PRIVILEGES 语句 支持 LOAD DATA 语句的 CHARACTER SET 语法 支持 CREATE USER 语句的 IDENTIFIED WITH 语法 支持 LOAD DATA IGNORE LINES 语句 Show ProcessList 语句返回更准确信息 PD (Placement Driver) 可用性优化 引入 TiKV 版本控制机制,支持集群滚动兼容升级 PD 节点间开启 Raft PreVote,避免网络隔离后恢复时产生的重新选举 开启 raft learner 功能,降低调度时出现宕机导致数据不可用的风险 TSO 分配不再受系统时间回退影响 支持 Region merge 功能,减少元数据带来的开销 调度器优化 优化 Down Store 的处理流程,加快发生宕机后补副本的速度 优化热点调度器,在流量统计信息抖动时适应性更好 优化 Coordinator 的启动,减少重启 PD 时带来的不必要调度 优化 Balance Scheduler 频繁调度小 Region 的问题 优化 Region merge,调度时考虑 Region 中数据的行数 新增一些控制调度策略的开关 完善调度模拟器,添加调度场景模拟 API 及运维工具 新增 GetPrevRegion 接口,用于支持 TiDB reverse scan 功能 新增 BatchSplitRegion 接口,用于支持 TiKV 快速 Region 分裂 新增 GCSafePoint 接口,用于支持 TiDB 并发分布式 GC 新增 GetAllStores 接口,用于支持 TiDB 并发分布式 GC pd-ctl 新增: 使用统计信息进行 Region split 调用 jq 来格式化 JSON 输出 查询指定 store 的 Region 信息 查询按 version 排序的 topN 的 Region 列表 查询按 size 排序的 topN 的 Region 列表 更精确的 TSO 解码 pd-recover 不再需要提供 max-replica 参数 监控 增加 Filter相关的监控 新增 etcd Raft 状态机相关监控 性能优化 优化处理 Region heartbeat 的性能,减少 heartbeat 带来的内存开销 优化 Region tree 性能 优化计算热点统计的性能问题 TiKV Coprocessor 新增支持大量内建函数 新增 Coprocessor ReadPool,提高请求处理并发度 修复时间函数解析以及时区相关问题 优化下推聚合计算的内存使用 Transaction 优化 MVCC 读取逻辑以及内存使用效率,提高扫描操作的性能,Count 全表性能比 2.0 版本提升 1 倍 折叠 MVCC 中连续的 Rollback 记录,保证记录的读取性能 新增 UnsafeDestroyRange API 用于在 drop table/index 的情况下快速回收空间 GC 模块独立出来,减少对正常写入的影响 kv_scan 命令支持设置 upper bound Raftstore 优化 snapshot 文件写入流程避免导致 RocksDB stall 增加 LocalReader 线程专门处理读请求,降低读请求的延迟 支持 BatchSplit 避免大量写入导致产生特别大的 Region 支持按照统计信息进行 Region Split,减少 IO 开销 支持按照 Key 的数量进行 Region Split,提高索引扫描的并发度 优化部分 Raft 消息处理流程,避免 Region Split 带来不必要的延迟 启用 PreVote 功能,减少网络隔离对服务的影响 存储引擎 修复 RocksDB CompactFiles 的 bug,可能影响 Lightning 导入的数据 升级 RocksDB 到 v5.15,解决 snapshot 文件可能会被写坏的问题 优化 IngestExternalFile,避免 flush 卡住写入的问题 tikv-ctl 新增 ldb 命令,方便排查 RocksDB 相关问题 compact 命令支持指定是否 compact bottommost 层的数据 Tools 全量数据快速导入工具 TiDB-Lightning 支持新版本 TiDB-Binlog 升级兼容性说明 由于新版本存储引擎更新,不支持在升级后回退至 2.0.x 或更旧版本 从 2.0.6 之前的版本升级到 2.1 之前,最好确认集群中是否存在正在运行中的 DDL 操作,特别是耗时的 Add Index 操作,等 DDL 操作完成后再执行升级操作 因为 2.1 版本启用了并行 DDL,对于早于 2.0.1 版本的集群,无法滚动升级到 2.1,可以选择下面两种方案: 停机升级,直接从早于 2.0.1 的 TiDB 版本升级到 2.1 先滚动升级到 2.0.1 或者之后的 2.0.x 版本,再滚动升级到 2.1 版本 "}, {"url": "https://pingcap.com/docs/releases/2.1ga/", "title": "TiDB 2.1 GA Release Notes", "content": " TiDB 2.1 GA Release Notes On November 30, 2018, TiDB 2.1 GA is released. See the following updates in this release. Compared with TiDB 2.0, this release has great improvements in stability, performance, compatibility, and usability.TiDB SQL Optimizer Optimize the selection range of Index Join to improve the execution performance Optimize the selection of outer table for Index Join and use the table with smaller estimated value of Row Count the as the outer table Optimize Join Hint TIDB_SMJ so that Merge Join can be used even without proper index available Optimize Join Hint TIDB_INLJ to specify the Inner table to Join Optimize correlated subquery, push down Filter, and extend the index selection range, to improve the efficiency of some queries by orders of magnitude Support using Index Hint and Join Hint in the UPDATE and DELETE statement Support pushing down more functions: ABS/CEIL/FLOOR/IS TRUE/IS FALSE Optimize the constant folding algorithm for the IFandIFNULL` built-in functions Optimize the output of the EXPLAIN statement and use hierarchy structure to show the relationship between operators SQL executor Refactor all the aggregation functions and improve execution efficiency of the Stream and Hash aggregation operators Implement the parallel Hash Aggregate operators and improve the computing performance by 350% in some scenarios Implement the parallel Project operators and improve the performance by 74% in some scenarios Read the data of the Inner table and Outer table of Hash Join concurrently to improve the execution performance Optimize the execution speed of the REPLACE INTO statement and increase the performance nearly by 10 times Optimize the memory usage of the time data type and decrease the memory usage of the time data type by fifty percent Optimize the point select performance and improve the point select efficiency result of Sysbench by 60% Improve the performance of TiDB on inserting or updating wide tables by 20 times Support configuring the memory upper limit of a single statement in the configuration file Optimize the execution of Hash Join, if the Join type is Inner Join or Semi Join and the inner table is empty, return the result without reading data from the outer table Support using the EXPLAIN ANALYZE statement to check the runtime statistics including the execution time and the number of returned rows of each operator Statistics Support enabling auto ANALYZE statistics only during certain period of the day Support updating the table statistics automatically according to the feedback of the queries Support configuring the number of buckets in the histogram using the ANALYZE TABLE WITH BUCKETS statement Optimize the Row Count estimation algorithm using histogram for mixed queries of equality query and range queries Expressions Support following built-in function: json_contains json_contains_path encode/decode Server Support queuing the locally conflicted transactions within tidb-server instance to optimize the performance of conflicted transactions Support Server Side Cursor Add the HTTP API Scatter the distribution of table Regions in the TiKV cluster Control whether to open the general log Support modifying the log level online Check the TiDB cluster information Add the auto_analyze_ratio system variables to contorl the ratio of Analyze Add the tidb_retry_limit system variable to control the automatic retry times of transactions Add the tidb_disable_txn_auto_retry system variable to control whether the transaction retries automatically Support usingadmin show slow statement to obtain the slow queries Add the tidb_slow_log_threshold environment variable to set the threshold of slow log automatically Add the tidb_query_log_max_len environment variable to set the length of the SQL statement to be truncated in the log dynamically DDL Support the parallel execution of the Add index statement and other statements to avoid the time consuming Add index operation blocking other operations Optimize the execution speed of ADD INDEX and improve it greatly in some scenarios Support the select tidb_is_ddl_owner() statement to facilitate deciding whether TiDB is DDL Owner Support the ALTER TABLE FORCE syntax Support the ALTER TABLE RENAME KEY TO syntax Add the table name and database name in the output information of admin show ddl jobs Support using the ddl/owner/resign HTTP interface to release the DDL owner and start electing a new DDL owner Compatibility Support more MySQL syntaxes Make the BIT aggregate function support the ALL parameter Support the SHOW PRIVILEGES statement Support the CHARACTER SET syntax in the LOAD DATA statement Support the IDENTIFIED WITH syntax in the CREATE USER statement Support the LOAD DATA IGNORE LINES statement The Show ProcessList statement returns more accurate information Placement Driver (PD) Optimize availability Introduce the version control mechanism and support rolling update of the cluster compatibly Enable Raft PreVote among PD nodes to avoid leader reelection when network recovers after network isolation Enable raft learner by default to lower the risk of unavailable data caused by machine failure during scheduling TSO allocation is no longer affected by the system clock going backwards Support the Region merge feature to reduce the overhead brought by metadata Optimize the scheduler Optimize the processing of Down Store to speed up making up replicas Optimize the hotspot scheduler to improve its adaptability when traffic statistics information jitters Optimize the start of Coordinator to reduce the unnecessary scheduling caused by restarting PD Optimize the issue that Balance Scheduler schedules small Regions frequently Optimize Region merge to consider the number of rows within the Region Add more commands to control the scheduling policy Improve PD simulator to simulate the scheduling scenarios API and operation tools Add the GetPrevRegion interface to support the TiDB reverse scan feature Add the BatchSplitRegion interface to speed up TiKV Region splitting Add the GCSafePoint interface to support distributed GC in TiDB Add the GetAllStores interface, to support distributed GC in TiDB pd-ctl supports: using statistics for Region split calling jq to format the JSON output checking the Region information of the specified store checking topN Region list sorted by versions checking topN Region list sorted by size more precise TSO encoding pd-recover doesn’t need to provide the max-replica parameter Metrics Add related metrics for Filter Add metrics about etcd Raft state machine Performance Optimize the performance of Region heartbeat to reduce the memory overhead brought by heartbeats Optimize the Region tree performance Optimize the performance of computing hotspot statistics TiKV Coprocessor Add more built-in functions Add Coprocessor ReadPool to improve the concurrency in processing the requests Fix the time function parsing issue and the time zone related issues Optimize the memory usage for pushdown aggregation computing Transaction Optimize the read logic and memory usage of MVCC to improve the performance of the scan operation and the performance of full table scan is 1 time better than that in TiDB 2.0 Fold the continuous Rollback records to ensure the read performance Add the UnsafeDestroyRange API to support to collecting space for the dropping table/index Separate the GC module to reduce the impact on write Add the upper bound support in the kv_scan command Raftstore Improve the snapshot writing process to avoid RocksDB stall Add the LocalReader thread to process read requests and reduce the delay for read requests Support BatchSplit to avoid large Region brought by large amounts of write Support Region Split according to statistics to reduce the I/O overhead Support Region Split according to the number of keys to improve the concurrency of index scan Improve the Raft message process to avoid unnecessary delay brought by Region Split Enable the …"}, {"url": "https://pingcap.com/docs-cn/releases/21rc1/", "title": "TiDB 2.1 RC1 Release Notes", "content": " TiDB 2.1 RC1 Release Notes 2018 年 8 月 24 日,TiDB 发布 2.1 RC1 版。相比 2.1 Beta 版本,该版本对系统稳定性、优化器、统计信息以及执行引擎做了很多改进。TiDB SQL 优化器 修复某些情况下关联子查询去关联后结果不正确的问题 #6972 优化 Explain 输出结果 #7011#7041 优化 IndexJoin 驱动表选择策略#7019 去掉非 PREPARE 语句的 Plan Cache #7040 修复某些情况下 INSERT 语句无法正常解析执行的问题 #7068 修复某些情况下 IndexJoin 结果不正确的问题 #7150 修复某些情况下使用唯一索引不能查询到 NULL 值的问题 #7163 修复 UTF-8 编码情况下前缀索引的范围计算不正确的问题 #7194 修复某些情况下 Project 算子消除导致的结果不正确的问题 #7257 修复主键为整数类型时无法使用 USE INDEX(PRIMARY) 的问题 #7316 修复某些情况下使用关联列无法计算索引范围的问题 #7357 SQL 执行引擎 修复某些情况下夏令时时间计算结果不正确的问题 #6823 重构聚合函数框架,提升 Stream 和 Hash 聚合算子的执行效率 #6852 修复某些情况下 Hash 聚合算子不能正常退出的问题 #6982 修复 BIT_AND/BIT_OR/BIT_XOR 没有正确处理非整型数据的问题 #6994 优化 REPLACE INTO 语句的执行速度,性能提升近 10 倍 #7027 优化时间类型的内存占用,时间类型数据的内存使用降低为原来的一半 #7043 修复 UNION 语句整合有符号和无符号型整数结果时与 MySQL 不兼容的问题 #7112 修复 LPAD/RPAD/TO_BASE64/FROM_BASE64/REPEAT 因为申请过多内存导致 TiDB panic 的问题 #7171 #7266 #7409 #7431 修复 MergeJoin/IndexJoin 在处理 NULL 值时结果不正确的问题 #7255 修复某些情况下 Outer Join 结果不正确的问题 #7288 增强 Data Truncated 的报错信息,便于定位出错的数据和表中对应的字段 #7401 修复某些情况下 Decimal 计算结果不正确的问题 #7001 #7113 #7202 #7208 优化点查的查询性能 #6937 禁用 Read Commited 隔离级别,避免潜在的问题 #7211 修复某些情况下 LTRIM/RTRIM/TRIM 结果不正确的问题 #7291 修复 MaxOneRow 算子无法保证返回结果不超过 1 行的问题 #7375 拆分 range 个数过多的 Coprocessor 请求 #7454 统计信息 优化统计信息动态收集机制 #6796 解决数据频繁更新场景下 Auto Analyze 不工作的问题 #7022 减少统计信息动态更新过程中的写入冲突 #7124 优化统计信息不准确情况下的代价估算 #7175 优化 AccessPath 的代价估算策略 #7233 Server 修复加载权限信息时的 bug #6976 修复 Kill 命令对权限的检查过严问题 #6954 解决 Binary 协议中某些数值类型移除的问题 #6922 精简日志输出 #7029 处理 mismatchClusterID 问题 #7053 增加 advertise-address 配置项 #7078 增加 GrpcKeepAlive 选项 #7100 增加连接或者 Token 时间监控 #7110 优化数据解码性能 #7149 INFORMMATION_SCHEMA 中增加 PROCESSLIST 表 #7236 解决权限验证时多条规则可以命中情况下的顺序问题 #7211 将部分编码相关的系统变量默认值改为 UTF-8 #7198 慢查询日志显示更详细的信息 #7302 支持在 PD 注册 tidb-server 的相关信息并通过 HTTP API 获取 #7082 兼容性 支持 Session 变量 warning_count 和 error_count #6945 读取系统变量时增加 Scope 检查 #6958 支持 MAX_EXECUTION_TIME 语法 #7012 支持更多的 SET 语法 #7020 Set 系统变量值过程中增加合法性校验 #7117 增加 Prepare 语句中 PlaceHolder 数量的校验 #7162 支持 set character_set_results = null #7353 支持 flush status 语法 #7369 修复 SET 和 ENUM 类型在 information_schema 里的 column size #7347 支持建表语句里的 NATIONAL CHARACTER 语法 #7378 支持 LOAD DATA 语句的 CHARACTER SET 语法 #7391 修复 SET 和 ENUM类型的 column info #7417 支持 CREATE USER 语句的 IDENTIFIED WITH 语法 #7402 修复 TIMESTAMP 类型计算过程中丢失精度的问题 #7418 支持更多 SYSTEM 变量的合法性验证 #7196 修复 CHAR_LENGTH 函数在计算 binary string 时结果不正确的问题 #7410 修复在包含 GROUP BY 的语句里 CONCAT 结果不正确的问题 #7448 修复 DECIMAL 类型 CAST 到 STRING 类型时,类型长度不准确的问题 #7451 DML 解决 Load Data 语句的稳定性 #6927 解决一些 Batch 操作情况下的内存使用问题 #7086 提升 Replace Into 语句的性能 #7027 修复写入 CURRENT_TIMESTAMP 时,精度不一致的问题 #7355 DDL 改进 DDL 判断 Schema 是否已经同步的方法, 避免某些情况下的误判 #7319 修复在 ADD INDEX 过程中的 SHOW CREATE TABLE 结果 #6993 非严格 sql-mode 模式下, text/blob/json 的默认值可以为空 #7230 修复某些特定场景下 ADD INDEX 的问题 #7142 大幅度提升添加 UNIQUE-KEY 索引操作的速度 #7132 修复 Prefix-index 在 UTF-8 字符集的场景下的截断问题 #7109 增加环境变量 tidb_ddl_reorg_priority 来控制 add-index 操作的优先级 #7116 修复 information_schema.tables 中 AUTO-INCREMENT 的显示问题 #7037 支持 admin show ddl jobs <number> 命令, 支持输出 number 个 DDL jobs #7028 支持并行 DDL 任务执行 #6955 Table Partition(实验性) 支持一级分区 支持 Range Partition PD 新特性 引入版本控制机制,支持集群滚动兼容升级 开启 Region merge 功能 支持 GetPrevRegion 接口 支持批量 split Region 支持存储 GC safepoint 功能改进 优化系统时间回退影响 TSO 分配的问题 优化处理 Region heartbeat 的性能 优化 Region tree 性能 优化计算热点统计的性能问题 优化 API 接口错误码返回 新增一些控制调度策略的开关 禁止在 label 中使用特殊字符 完善调度模拟器 pd-ctl 支持使用统计信息进行 Region split pd-ctl 支持调用 jq 来格式化 JSON 输出 新增 etcd Raft 状态机相关 metrics Bug 修复 修复 leader 切换后 namespace 未重新加载的问题 修复 namespace 调度超出 schedule limit 配置的问题 修复热点调度超出 schedule limit 的问题 修复 PD client 关闭时输出一些错误日志的问题 修复 Region 心跳延迟统计有误的问题 TiKV 新特性 支持 batch split,防止热点 Region 写入产生超大 Region 支持设置根据数据行数 split Region,提升 index scan 效率 性能优化 使用 LocalReader 将 Read 操作从 raftstore 线程分离,减少 Read 延迟 重构 MVCC 框架,优化 memory 使用,提升 scan read 性能 支持基于统计估算进行 Region split,减少 I/O 开销 优化连续写入 Rollback 记录后影响读性能的问题 减少下推聚合计算的内存开销 功能改进 增加大量内建函数下推支持,更完善的 charset 支持 优化 GC 流程,提升 GC 速度并降低 GC 对系统的影响 开启 prevote,加快网络异常时的恢复服务速度 增加 RocksDB 日志文件相关的配置项 调整 scheduler latch 默认配置 使用 tikv-ctl 手动 compact 时可设定是否 compact RocksDB 最底层数据 增加启动时的环境变量检查 支持基于已有数据动态设置 dynamic_level_bytes 参数 支持自定义日志格式 tikv-ctl 整合 tikv-fail 工具 增加 threads IO metrics Bug 修复 修复 decimal 相关问题 修复 gRPC max_send_message_len 设置有误的问题 修复 region_size 配置不当时产生的问题 "}, {"url": "https://pingcap.com/docs/releases/21rc1/", "title": "TiDB 2.1 RC1 Release Notes", "content": " TiDB 2.1 RC1 Release Notes On August 24, 2018, TiDB 2.1 RC1 is released! Compared with TiDB 2.1 Beta, this release has great improvement in stability, SQL optimizer, statistics information, and execution engine.TiDB SQL Optimizer Fix the issue that a wrong result is returned after the correlated subquery is decorrelated in some cases #6972 Optimize the output result of Explain #7011#7041 Optimize the choosing strategy of the outer table for IndexJoin #7019 Remove the Plan Cache of the non-PREPARE statement #7040 Fix the issue that the INSERT statement is not parsed and executed correctly in some cases #7068 Fix the issue that the IndexJoin result is not correct in some cases #7150 Fix the issue that the NULL value cannot be found using the unique index in some cases #7163 Fix the range computing issue of the prefix index in UTF-8 #7194 Fix the issue that result is not correct caused by eliminating the Project operator in some cases #7257 Fix the issue that USE INDEX(PRIMARY) cannot be used when the primary key is an integer #7316 Fix the issue that the index range cannot be computed using the correlated column in some cases #7357 SQL Execution Engine Fix the issue that the daylight saving time is not computed correctly in some cases #6823 Refactor the aggregation function framework to improve the execution efficiency of the Stream and Hash aggregation operators #6852 Fix the issue that the Hash aggregation operator cannot exit normally in some cases #6982 Fix the issue that BIT_AND/BIT_OR/BIT_XOR does not handle the non-integer data correctly #6994 Optimize the execution speed of the REPLACE INTO statement and increase the performance nearly 10 times #7027 Optimize the memory usage of time type data and decrease the memory usage of the time type data by fifty percent #7043 Fix the issue that the returned result is mixed with signed and unsigned integers in the UNION statement is not compatible with MySQL #7112 Fix the panic issue caused by the too much memory applied by LPAD/RPAD/TO_BASE64/FROM_BASE64/REPEAT #7171 #7266 #7409 #7431 Fix the incorrect result when MergeJoin/IndexJoin handles the NULL value #7255 Fix the incorrect result of Outer Join in some cases #7288 Improve the error message of Data Truncated to facilitate locating the wrong data and the corresponding field in the table #7401 Fix the incorrect result for decimal in some cases #7001 #7113 #7202 #7208 Optimize the point select performance #6937 Prohibit the isolation level of Read Commited to avoid the underlying problem #7211 Fix the incorrect result of LTRIM/RTRIM/TRIM in some cases #7291 Fix the issue that the MaxOneRow operator cannot guarantee that the returned result does not exceed one row #7375 Divide the Coprocessor requests with too many ranges #7454 Statistics Optimize the mechanism of statistics dynamic collection #6796 Fix the issue that Auto Analyze does not work when data is updated frequently #7022 Decrease the Write conflicts during the statistics dynamic update process #7124 Optimize the cost estimation when the statistics is incorrect #7175 Optimize the AccessPath cost estimation strategy #7233 Server Fix the bug in loading privilege information #6976 Fix the issue that the Kill command is too strict with privilege check #6954 Fix the issue of removing some binary numeric types #6922 Shorten the output log #7029 Handle the mismatchClusterID issue #7053 Add the advertise-address configuration item #7078 Add the GrpcKeepAlive option #7100 Add the connection or Token time monitor #7110 Optimize the data decoding performance #7149 Add the PROCESSLIST table in INFORMMATION_SCHEMA #7236 Fix the order issue when multiple rules are hit in verifying the privilege #7211 Change some default values of encoding related system variables to UTF-8 #7198 Make the slow query log show more detailed information #7302 Support registering tidb-server related information in PD and obtaining this information by HTTP API #7082 Compatibility Support Session variables warning_count and error_count #6945 Add Scope check when reading the system variables #6958 Support the MAX_EXECUTION_TIME syntax #7012 Support more statements of the SET syntax #7020 Add validity check when setting system variables #7117 Add the verification of the number of PlaceHolders in the Prepare statement #7162 Support set character_set_results = null #7353 Support the flush status syntax #7369 Fix the column size of SET and ENUM types in information_schema #7347 Support the NATIONAL CHARACTER syntax of statements for creating a table #7378 Support the CHARACTER SET syntax in the LOAD DATA statement #7391 Fix the column information of the SET and ENUM types #7417 Support the IDENTIFIED WITH syntax in the CREATE USER statement #7402 Fix the precision losing issue during TIMESTAMP computing process #7418 Support the validity verification of more SYSTEM variables #7196 Fix the incorrect result when the CHAR_LENGTH function computes the binary string #7410 Fix the incorrect CONCAT result in a statement involving GROUP BY #7448 Fix the imprecise type length issue when casting the DECIMAL type to the STRING type #7451 DML Fix the stability issue of the Load Data statement #6927 Fix the memory usage issue when performing some Batch operations #7086 Improve the performance of the Replace Into statement #7027 Fix the inconsistent precision issue when writing CURRENT_TIMESTAMP #7355 DDL Improve the method of DDL judging whether Schema is synchronized to avoid misjudgement in some cases #7319 Fix the SHOW CREATE TABLE result in adding index process #6993 Allow the default value of text/blob/json to be NULL in non-restrict sql-mode #7230 Fix the ADD INDEX issue in some cases #7142 Increase the speed of adding UNIQUE-KEY index operation largely #7132 Fix the truncating issue of the prefix index in UTF-8 character set #7109 Add the environment variable tidb_ddl_reorg_priority to control the priority of the add-index operation #7116 Fix the display issue of AUTO-INCREMENT in information_schema.tables #7037 Support the admin show ddl jobs <number> command and support output specified number of DDL jobs #7028 Support parallel DDL job execution #6955 Table Partition (Experimental) Support top level partition Support Range Partition PD Features Introduce the version control mechanism and support rolling update of the cluster with compatibility Enable the region merge feature Support the GetPrevRegion interface Support splitting Regions in batch Support storing the GC safepoint Improvements Optimize the issue that TSO allocation is affected by the system clock going backwards Optimize the performance of handling Region heartbeats Optimize the Region tree performance Optimize the performance of computing hotspot statistics Optimize returning the error code of API interface Add options of controlling scheduling strategies Prohibit using special characters in label Improve the scheduling simulator Support splitting Regions using statistics in pd-ctl Support formatting JSON output by calling jq in pd-ctl Add metrics about etcd Raft state machine Bug fixes Fix the issue that the namespace is not reloaded after switching Leader Fix the issue that namespace scheduling exceeds the schedule limit Fix the issue that hotspot scheduling exceeds the schedule limit Fix the issue that wrong logs are output when the PD client closes Fix the wrong statistics of Region heartbeat latency TiKV Features Support batch split to avoid too large Regions caused by the Write operation on hot Regions Support splitting Regions based on the number of rows to improve the index scan efficiency Performance Use LocalReader to separate the Read operation from the raftstore thread to lower the Read latency Refactor the MVCC framework, optimize the memory usage and improve the scan Read performance Support splitting Regions based on statistics estimation to reduce the I/O usage Optimize the issue that the Read performance is affected by …"}, {"url": "https://pingcap.com/docs/v2.0/releases/21rc1/", "title": "TiDB 2.1 RC1 Release Notes", "content": " TiDB 2.1 RC1 Release Notes On August 24, 2018, TiDB 2.1 RC1 is released! Compared with TiDB 2.1 Beta, this release has great improvement in stability, SQL optimizer, statistics information, and execution engine.TiDB SQL Optimizer Fix the issue that a wrong result is returned after the correlated subquery is decorrelated in some cases #6972 Optimize the output result of Explain #7011#7041 Optimize the choosing strategy of the outer table for IndexJoin #7019 Remove the Plan Cache of the non-PREPARE statement #7040 Fix the issue that the INSERT statement is not parsed and executed correctly in some cases #7068 Fix the issue that the IndexJoin result is not correct in some cases #7150 Fix the issue that the NULL value cannot be found using the unique index in some cases #7163 Fix the range computing issue of the prefix index in UTF-8 #7194 Fix the issue that result is not correct caused by eliminating the Project operator in some cases #7257 Fix the issue that USE INDEX(PRIMARY) cannot be used when the primary key is an integer #7316 Fix the issue that the index range cannot be computed using the correlated column in some cases #7357 SQL Execution Engine Fix the issue that the daylight saving time is not computed correctly in some cases #6823 Refactor the aggregation function framework to improve the execution efficiency of the Stream and Hash aggregation operators #6852 Fix the issue that the Hash aggregation operator cannot exit normally in some cases #6982 Fix the issue that BIT_AND/BIT_OR/BIT_XOR does not handle the non-integer data correctly #6994 Optimize the execution speed of the REPLACE INTO statement and increase the performance nearly 10 times #7027 Optimize the memory usage of time type data and decrease the memory usage of the time type data by fifty percent #7043 Fix the issue that the returned result is mixed with signed and unsigned integers in the UNION statement is not compatible with MySQL #7112 Fix the panic issue caused by the too much memory applied by LPAD/RPAD/TO_BASE64/FROM_BASE64/REPEAT #7171 #7266 #7409 #7431 Fix the incorrect result when MergeJoin/IndexJoin handles the NULL value #7255 Fix the incorrect result of Outer Join in some cases #7288 Improve the error message of Data Truncated to facilitate locating the wrong data and the corresponding field in the table #7401 Fix the incorrect result for decimal in some cases #7001 #7113 #7202 #7208 Optimize the point select performance #6937 Prohibit the isolation level of Read Commited to avoid the underlying problem #7211 Fix the incorrect result of LTRIM/RTRIM/TRIM in some cases #7291 Fix the issue that the MaxOneRow operator cannot guarantee that the returned result does not exceed one row #7375 Divide the Coprocessor requests with too many ranges #7454 Statistics Optimize the mechanism of statistics dynamic collection #6796 Fix the issue that Auto Analyze does not work when data is updated frequently #7022 Decrease the Write conflicts during the statistics dynamic update process #7124 Optimize the cost estimation when the statistics is incorrect #7175 Optimize the AccessPath cost estimation strategy #7233 Server Fix the bug in loading privilege information #6976 Fix the issue that the Kill command is too strict with privilege check #6954 Fix the issue of removing some binary numeric types #6922 Shorten the output log #7029 Handle the mismatchClusterID issue #7053 Add the advertise-address configuration item #7078 Add the GrpcKeepAlive option #7100 Add the connection or Token time monitor #7110 Optimize the data decoding performance #7149 Add the PROCESSLIST table in INFORMMATION_SCHEMA #7236 Fix the order issue when multiple rules are hit in verifying the privilege #7211 Change some default values of encoding related system variables to UTF-8 #7198 Make the slow query log show more detailed information #7302 Support registering tidb-server related information in PD and obtaining this information by HTTP API #7082 Compatibility Support Session variables warning_count and error_count #6945 Add Scope check when reading the system variables #6958 Support the MAX_EXECUTION_TIME syntax #7012 Support more statements of the SET syntax #7020 Add validity check when setting system variables #7117 Add the verification of the number of PlaceHolders in the Prepare statement #7162 Support set character_set_results = null #7353 Support the flush status syntax #7369 Fix the column size of SET and ENUM types in information_schema #7347 Support the NATIONAL CHARACTER syntax of statements for creating a table #7378 Support the CHARACTER SET syntax in the LOAD DATA statement #7391 Fix the column information of the SET and ENUM types #7417 Support the IDENTIFIED WITH syntax in the CREATE USER statement #7402 Fix the precision losing issue during TIMESTAMP computing process #7418 Support the validity verification of more SYSTEM variables #7196 Fix the incorrect result when the CHAR_LENGTH function computes the binary string #7410 Fix the incorrect CONCAT result in a statement involving GROUP BY #7448 Fix the imprecise type length issue when casting the DECIMAL type to the STRING type #7451 DML Fix the stability issue of the Load Data statement #6927 Fix the memory usage issue when performing some Batch operations #7086 Improve the performance of the Replace Into statement #7027 Fix the inconsistent precision issue when writing CURRENT_TIMESTAMP #7355 DDL Improve the method of DDL judging whether Schema is synchronized to avoid misjudgement in some cases #7319 Fix the SHOW CREATE TABLE result in adding index process #6993 Allow the default value of text/blob/json to be NULL in non-restrict sql-mode #7230 Fix the ADD INDEX issue in some cases #7142 Increase the speed of adding UNIQUE-KEY index operation largely #7132 Fix the truncating issue of the prefix index in UTF-8 character set #7109 Add the environment variable tidb_ddl_reorg_priority to control the priority of the add-index operation #7116 Fix the display issue of AUTO-INCREMENT in information_schema.tables #7037 Support the admin show ddl jobs <number> command and support output specified number of DDL jobs #7028 Support parallel DDL job execution #6955 Table Partition (Experimental) Support top level partition Support Range Partition PD Features Introduce the version control mechanism and support rolling update of the cluster with compatibility Enable the region merge feature Support the GetPrevRegion interface Support splitting Regions in batch Support storing the GC safepoint Improvements Optimize the issue that TSO allocation is affected by the system clock going backwards Optimize the performance of handling Region heartbeats Optimize the Region tree performance Optimize the performance of computing hotspot statistics Optimize returning the error code of API interface Add options of controlling scheduling strategies Prohibit using special characters in label Improve the scheduling simulator Support splitting Regions using statistics in pd-ctl Support formatting JSON output by calling jq in pd-ctl Add metrics about etcd Raft state machine Bug fixes Fix the issue that the namespace is not reloaded after switching Leader Fix the issue that namespace scheduling exceeds the schedule limit Fix the issue that hotspot scheduling exceeds the schedule limit Fix the issue that wrong logs are output when the PD client closes Fix the wrong statistics of Region heartbeat latency TiKV Features Support batch split to avoid too large Regions caused by the Write operation on hot Regions Support splitting Regions based on the number of rows to improve the index scan efficiency Performance Use LocalReader to separate the Read operation from the raftstore thread to lower the Read latency Refactor the MVCC framework, optimize the memory usage and improve the scan Read performance Support splitting Regions based on statistics estimation to reduce the I/O usage Optimize the issue that the Read performance is affected by …"}, {"url": "https://pingcap.com/docs-cn/releases/21rc2/", "title": "TiDB 2.1 RC2 Release Notes", "content": " TiDB 2.1 RC2 Release Notes 2018 年 9 月 14 日,TiDB 发布 2.1 RC2 版。相比 2.1 RC1 版本,该版本对系统稳定性、优化器、统计信息以及执行引擎做了很多改进。TiDB SQL 优化器 新版 Planner 设计方案 #7543 提升常量传播优化规则 #7276 增强 Range 的计算逻辑使其能够同时处理多个 IN 或者等值条件 #7577 修复当 Range 为空时,TableScan 的估算结果不正确的问题 #7583 为 UPDATE 语句支持 PointGet 算子 #7586 修复 FirstRow 聚合函数某些情况下在执行过程中 panic 的问题 #7624 SQL 执行引擎 解决 HashJoin 算子在遇到错误的情况下潜在的 DataRace 问题 #7554 HashJoin 算子同时读取内表数据和构建 Hash 表 #7544 优化 Hash 聚合算子性能 #7541 优化 Join 算子性能 #7493、#7433 修复 UPDATE JOIN 在 Join 顺序改变后结果不正确的问题 #7571 提升 Chunk 迭代器的性能 #7585 统计信息 解决重复自动 Analyze 统计信息的问题 #7550 解决统计信息无变化时更新统计信息遇到错误的问题 #7530 Analyze 执行时使用低优先级以及 RC 隔离级别 #7496 支持只在一天中的某个时间段开启统计信息自动更新的功能 #7570 修复统计信息写日志时发生的 panic #7588 支持通过 ANALYZE TABLE WITH BUCKETS 语句配置直方图中桶的个数 #7619 修复更新空的直方图时 panic 的问题 #7640 使用统计信息更新 information_schema.tables.data_length #7657 Server 增加 Trace 相关的依赖库 #7532 开启 Golang 的 mutex profile 功能 #7512 Admin 语句需要 Super_priv 权限 #7486 禁止用户 Drop 关键的系统表 #7471 从 juju/errors 切换到 pkg/errors #7151 完成 SQL Tracing 功能原型 #7016 删除 goroutine pool #7564 支持使用 USER1 信号来查看 goroutine 信息 #7587 将 TiDB 启动时的内部 SQL 设置为高优先级 #7616 在监控中用不同的标签区分内部 SQL 和用户 SQL #7631 缓存最近一周内最慢的 30 条慢查询日志在 TiDB Server 上 #7646 TiDB 集群设置时区的方案 #7656 丰富 GC life time is shorter than transaction duration 错误信息 #7658 在 TiDB 集群启动时设置集群时区信息 #7638 兼容性 Year 类型字段增加 unsigned flag #7542 修复在 Prepare/Execute 模式下,Year 类型结果长度设置问题 #7525 修复 Prepare/Execute 模式下时间 0 值的处理问题 #7506 解决整数类型除法实现中的错误处理问题 #7492 解决 ComStmtSendLongData 处理过程中的兼容性问题 #7485 解决字符串转为整数类型过程中的错误处理问题 #7483 优化 information_schema.columns_in_table 表中的值精度 #7463 修复使用 MariaDB 客户端对字符串类型数据的写入和更新的兼容性问题 #7573 修复返回值别名的兼容性问题 #7600 修复 information_schema.COLUMNS 表中浮点数的 NUMERIC_SCALE 值不正确的问题 #7602 解决单行注释内容为空 Parser 报错的问题 #7612 表达式 在 insert 函数中检查 max_allowed_packet 的值 #7528 支持内建函数 json_contains #7443 支持内建函数 json_contains_path #7596 支持内建函数 encode/decode #7622 修复一些时间相关的函数在某些情况下和 MySQL 行为不兼容的问题 #7636 解决从字符串中解析时间类型数据的兼容性问题 #7654 解决计算 DateTime 类型数据的默认值时没有考虑时区的问题 #7655 DML InsertOnDuplicateUpdate 语句设置正确的 last_insert_id #7534 减少需要更新 auto_increment_id 计数器的情况 #7515 优化 Duplicate Key 错误的报错信息 #7495 修复 insert...select...on duplicate key update 问题 #7406 支持 LOAD DATA IGNORE LINES 语句 #7576 DDL 在监控中增加 DDL Job 的类型和当前 Schema 版本的信息 #7472 完成 Admin Restore Table 功能方案设计 #7383 解决 Bit 类型的默认值超过 128 的问题 #7249 解决 Bit 类型默认值不能为 NULL 的问题 #7604 减少 DDL 队列中检查 CREATE TABLE/DATABASE 任务的时间间隔 #7608 使用 ddl/owner/resign HTTP 接口释放 DDL Owner 并开启新一轮 Owner 选举 #7649 TiKV Go Client 支持 Seek 操作只获取 Key #7419 Table Partition(实验性) 解决无法使用 Bigint 类型列作为 Partition Key 的问题 #7520 支持 Partitioned Table 添加索引过程中遇到问题回滚操作 #7437 PD 新特性 支持 GetAllStores的接口 #1228 Simulator 添加评估调度的统计信息 #1218 功能改进 优化 Down Store 的处理流程,尽快地补副本 #1222 优化 Coordinator 的启动,减少重启 PD 带来的不必要调度 #1225 优化内存使用,减少 heartbeat 带来的内存开销 #1195 优化错误处理,完善日志信息 #1227 pd-ctl 支持查询指定 store 的 Region 信息 #1231 pd-ctl 支持查询按 version 比对的 topN 的 Region 信息 #1233 pd-ctl 支持更精确的 TSO 解码 #1242 Bug 修复 修复 pd-ctl 使用 hot store 命令错误退出的问题 #1244 TiKV 性能优化 支持基于统计估算进行 Region split,减少 I/O 开销 #3511 减少部分组件的内存拷贝 #3530 功能改进 增加大量内建函数下推支持 增加 leader-transfer-max-log-lag 配置解决特定场景 leader 调度失败的问题 #3507 增加 max-open-engines 配置限制 tikv-importer 同时打开的 engine 个数 #3496 限制垃圾数据的清理速度,减少对 snapshot apply 的影响 #3547 对关键 Raft 消息广播 commit 信息,避免不必要的延迟 #3592 Bug 修复 修复新分裂 Region 的 PreVote 消息被丢弃导致的 leader 选举问题 #3557 修复 Region merge 以后 follower 的相关统计信息 #3573 修复 local reader 使用过期 Region 信息的问题 #3565 "}, {"url": "https://pingcap.com/docs/releases/21rc2/", "title": "TiDB 2.1 RC2 Release Notes", "content": " TiDB 2.1 RC2 Release Notes On September 14, 2018, TiDB 2.1 RC2 is released. Compared with TiDB 2.1 RC1, this release has great improvement in stability, SQL optimizer, statistics information, and execution engine.TiDB SQL Optimizer Put forward a proposal of the next generation Planner #7543 Improve the optimization rules of constant propagation #7276 Enhance the computing logic of Range to enable it to handle multiple IN or EQUAL conditions simultaneously #7577 Fix the issue that the estimation result of TableScan is incorrect when Range is empty #7583 Support the PointGet operator for the UPDATE statement #7586 Fix the panic issue during the process of executing the FirstRow aggregate function in some conditions #7624 SQL Execution Engine Fix the potential DataRace issue when the HashJoin operator encounters an error #7554 Make the HashJoin operator read the inner table and build the hash table simultaneously #7544 Optimize the performance of Hash aggregate operators #7541 Optimize the performance of Join operators #7493, #7433 Fix the issue that the result of UPDATE JOIN is incorrect when the Join order is changed #7571 Improve the performance of Chunk’s iterator #7585 Statistics Fix the issue that the auto Analyze work repeatedly analyzes the statistics #7550 Fix the statistics update error that occurs when there is no statistics change #7530 Use the RC isolation level and low priority when building Analyze requests #7496 Support enabling statistics auto-analyze on certain period of a day #7570 Fix the panic issue when logging the statistics information #7588 Support configuring the number of buckets in the histogram using the ANALYZE TABLE WITH BUCKETS statement #7619 Fix the panic issue when updating an empty histogram #7640 Update information_schema.tables.data_length using the statistics information #7657 Server Add Trace related dependencies #7532 Enable the mutex profile feature of Golang #7512 The Admin statement requires the Super_priv privilege #7486 Forbid users to Drop crucial system tables #7471 Switch from juju/errors to pkg/errors #7151 Complete the functional prototype of SQL Tracing #7016 Remove the goroutine pool #7564 Support viewing the goroutine information using the USER1 signal #7587 Set the internal SQL to high priority while TiDB is started #7616 Use different labels to filter internal SQL and user SQL in monitoring metrics #7631 Store the top 30 slow queries in the last week to the TiDB server #7646 Put forward a proposal of setting the global system time zone for the TiDB cluster #7656 Enrich the error message of “GC life time is shorter than transaction duration” #7658 Set the global system time zone when starting the TiDB cluster #7638 Compatibility Add the unsigned flag for the Year type #7542 Fix the issue of configuring the result length of the Year type in the Prepare/Execute mode #7525 Fix the issue of inserting zero timestamp in the Prepare/Execute mode #7506 Fix the error handling issue of the integer division #7492 Fix the compatibility issue when processing ComStmtSendLongData #7485 Fix the error handling issue during the process of converting string to integer #7483 Optimize the accuracy of values in the information_schema.columns_in_table table #7463 Fix the compatibility issue when writing or updating the string type of data using the MariaDB client #7573 Fix the compatibility issue of aliases of the returned value #7600 Fix the issue that the NUMERIC_SCALE value of the float type is incorrect in the information_schema.COLUMNS table #7602 Fix the issue that Parser reports an error when the single line comment is empty #7612 Expressions Check the value of max_allowed_packet in the insert function #7528 Support the built-in function json_contains #7443 Support the built-in function json_contains_path #7596 Support the built-in function encode/decode #7622 Fix the issue that some time related functions are not compatible with the MySQL behaviors in some cases #7636 Fix the compatibility issue of parsing the time type of data in string #7654 Fix the issue that the time zone is not considered when computing the default value of the DateTime data #7655 DML Set correct last_insert_id in the InsertOnDuplicateUpdate statement #7534 Reduce the cases of updating the auto_increment_id counter #7515 Optimize the error message of Duplicate Key #7495 Fix the insert...select...on duplicate key update issue #7406 Support the LOAD DATA IGNORE LINES statement #7576 DDL Add the DDL job type and the current schema version information in the monitor #7472 Complete the design of the Admin Restore Table feature #7383 Fix the issue that the default value of the Bit type exceeds 128 #7249 Fix the issue that the default value of the Bit type cannot be NULL #7604 Reduce the interval of checking CREATE TABLE/DATABASE in the DDL queue #7608 Use the ddl/owner/resign HTTP interface ro release the DDL owner and start electing a new owner #7649 TiKV Go Client Support the issue that the Seek operation only obtains Key #7419 Table Partition (Experimental) Fix the issue that the Bigint type cannot be used as the partition key #7520 Support the rollback operation when an issue occurs during adding an index in the partitioned table #7437 PD Features Support the GetAllStores interface #1228 Add the statistics of scheduling estimation in Simulator #1218 Improvements Optimize the handling process of down stores to make up replicas as soon as possible #1222 Optimize the start of Coordinator to reduce the unnecessary scheduling caused by restarting PD #1225 Optimize the memory usage to reduce the overhead caused by heartbeats #1195 Optimize error handling and improve the log information #1227 Support querying the Region information of a specific store in pd-ctl #1231 Support querying the topN Region information based on version comparasion in pd-ctl #1233 Support more accurate TSO decoding in pd-ctl #1242 Bug fix Fix the issue that pd-ctl uses the hot store command to exit wrongly #1244 TiKV Performance Support splitting Regions based on statistics estimation to reduce the I/O cost #3511 Reduce clone in the transaction scheduler #3530 Improvements Add the pushdown support for a large number of built-in functions Add the leader-transfer-max-log-lag configuration to fix the failure issue of leader scheduling in specific scenarios #3507 Add the max-open-engines configuration to limit the number of engines opened by tikv-importer simultaneously #3496 Limit the cleanup speed of garbage data to reduce the impact on snapshot apply #3547 Broadcast the commit message for crucial Raft messages to avoid unnecessary delay #3592 Bug fixes Fix the leader election issue caused by discarding the PreVote message of the newly split Region #3557 Fix follower related statistics after merging Regions #3573 Fix the issue that the local reader uses obsolete Region information #3565 "}, {"url": "https://pingcap.com/docs-cn/releases/21rc3/", "title": "TiDB 2.1 RC3 Release Notes", "content": " TiDB 2.1 RC3 Release Notes 2018 年 9 月 29 日,TiDB 发布 2.1 RC3 版。相比 2.1 RC2 版本,该版本对系统稳定性、兼容性、优化器以及执行引擎做了很多改进。TiDB SQL 优化器 修复语句内包含内嵌的 LEFT OUTER JOIN 时,结果不正确的问题 #7689 增强 JOIN 语句上的 predicate pushdown 优化规则 #7645 修复 UnionScan 算子的 predicate pushdown 优化规则 #7695 修复 Union 算子的 unique key 属性设置不正确的问题 #7680 增强常量折叠的优化规则 #7696 把常量传播后的 filter 是 null 的 data source 优化成 table dual #7756 SQL 执行引擎 优化事务内读请求的性能 #7717 优化部分执行器 Chunk 内存分配的开销 #7540 修复点查全部为 NULL 的列导致数组越界的问题 #7790 Server 修复配置文件里内存配额选项不生效的问题 #7729 添加 tidb_force_priority 系统变量用来整体设置语句执行的优先级 #7694 支持使用 admin show slow 语句来获取 SLOW QUERY LOG #7785 兼容性 修复 information_schema.schemata 里 charset/collation 结果不正确的问题 #7751 修复 hostname 系统变量的值为空的问题 #7750 表达式 内建函数 AES_ENCRYPT/AES_DECRYPT 支持 init_vecter 参数 #7425 修复部分表达式 Format 结果不正确的问题 #7770 支持内建函数 JSON_LENGTH #7739 修复 unsigned integer 类型 cast 为 decimal 类型结果不正确的问题 #7792 DML 修复 INSERT … ON DUPLICATE KEY UPDATE 语句在 unique key 更新时结果不正确的问题 #7675 DDL 修复在新建的 timestamp 类型的列上新建索引时,索引值没有做时区转换的问题 #7724 支持 enum 类型 append 新的值 #7767 快速新建 etcd session,使网络隔离后,集群更快恢复可用 #7774 PD 新特性 添加获取按大小逆序排序的 Region 列表 API (/size) #1254 功能改进 Region API 会返回更详细的信息 #1252 Bug 修复 修复 PD 切换 leader 以后 adjacent-region-scheduler 可能会导致 crash 的问题 #1250 TiKV 性能优化 优化函数下推的并发支持 #3515 新特性 添加对 Log 函数的支持 #3603 添加对 sha1 函数的支持 #3612 添加 truncate_int 函数的支持 #3532 添加 year 函数的支持 #3622 添加 truncate_real 函数的支持 #3633 Bug 修复 修正时间函数相关的报错行为 #3487 #3615 修复字符串解析成时间与 TiDB 不一致的问题 #3589 "}, {"url": "https://pingcap.com/docs/releases/21rc3/", "title": "TiDB 2.1 RC3 Release Notes", "content": " TiDB 2.1 RC3 Release Notes On September 29, 2018, TiDB 2.1 RC3 is released. Compared with TiDB 2.1 RC2, this release has great improvement in stability, compatibility, SQL optimizer, and execution engine.TiDB SQL Optimizer Fix the incorrect result issue when a statement contains embedded LEFT OUTER JOIN #7689 Enhance the optimization rule of predicate pushdown on the JOIN statement #7645 Fix the optimization rule of predicate pushdown for the UnionScan operator #7695 Fix the issue that the unique key property of the Union operator is not correctly set #7680 Enhance the optimization rule of constant folding #7696 Optimize the data source in which the filter is null after propagation to table dual #7756 SQL Execution Engine Optimize the performance of read requests in a transaction #7717 Optimize the cost of allocating Chunk memory in some executors #7540 Fix the “index out of range” panic caused by the columns where point queries get all NULL values #7790 Server Fix the issue that the memory quota in the configuration file does not take effect #7729 Add the tidb_force_priority system variable to set the execution priority for each statement #7694 Support using the admin show slow statement to obtain the slow query log #7785 Compatibility Fix the issue that the result of charset/collation is incorrect in information_schema.schemata #7751 Fix the issue that the value of the hostname system variable is empty #7750 Expressions Support the init_vecter argument in the AES_ENCRYPT/AES_DECRYPT built-in function #7425 Fix the issue that the result of Format is incorrect in some expressions #7770 Support the JSON_LENGTH built-in function #7739 Fix the incorrect result issue when casting the unsigned integer type to the decimal type #7792 DML Fix the issue that the result of the INSERT … ON DUPLICATE KEY UPDATE statement is incorrect while updating the unique key #7675 DDL Fix the issue that the index value is not converted between time zones when you create a new index on a new column of the timestamp type #7724 Support appending new values for the enum type #7767 Support creating an etcd session quickly, which improves the cluster availability after network isolation #7774 PD New feature Add the API to get the Region list by size in reverse order #1254 Improvement Return more detailed information in the Region API #1252 Bug fix Fix the issue that adjacent-region-scheduler might lead to a crash after PD switches the leader #1250 TiKV Performance Optimize the concurrency for coprocessor requests #3515 New features Add the support for Log functions #3603 Add the support for the sha1 function #3612 Add the support for the truncate_int function #3532 Add the support for the year function #3622 Add the support for the truncate_real function #3633 Bug fixes Fix the reporting error behavior related to time functions #3487, #3615 Fix the issue that the time parsed from string is inconsistent with that in TiDB #3589 "}, {"url": "https://pingcap.com/docs-cn/releases/21rc4/", "title": "TiDB 2.1 RC4 Release Notes", "content": " TiDB 2.1 RC4 Release Notes 2018 年 10 月 23 日,TiDB 发布 2.1 RC4 版。相比 2.1 RC3 版本,该版本对系统稳定性、优化器、统计信息以及执行引擎做了很多改进。TiDB SQL 优化器 修复某些情况下 UnionAll 的列裁剪不正确的问题 #7941 修复某些情况下 UnionAll 算子结果不正确的问题 #8007 SQL 执行引擎 修复 AVG 函数的精度问题 #7874 支持通过 EXPLAIN ANALYZE 语句查看 Query 执行过程中各个算子的运行时间,返回结果行数等运行时统计信息 #7925 修复多次引用同一列时 PointGet 算子 panic 的问题 #7943 修复当 Limit 子句中的值太大时 panic 的问题 #8002 修复某些情况下 AddDate/SubDate 执行过程中 panic 的问题 #8009 统计信息 修复将组合索引的直方图下边界前缀判断为越界的问题 #7856 修复统计信息收集引发的内存泄漏问题 #7873 修复直方图为空时 panic 的问题 #7928 修复加载统计信息时直方图边界越界的问题 #7944 限制统计信息采样过程中数值的最大长度 #7982 Server 重构 Latch,避免事务冲突误判,提升并发事务的执行性能 #7711 修复某些情况下收集 Slow Query 导致的 panic 问题 #7874 修复 LOAD DATA 语句中,ESCAPED BY 为空字符串时 panic 的问题 #8005 完善 “coprocessor error” 日志信息 #8006 兼容性 当 Query 为空时,将 SHOW PROCESSLIST 结果中的 Command 字段设置为 “Sleep” #7839 表达式 修复 SYSDATE 函数被常量折叠的问题 #7895 修复 SUBSTRING_INDEX 在某些情况下 panic 的问题 #7897 DDL 修复抛出 “invalid ddl job type” 的错误时导致栈溢出的问题 #7958 修复某些情况下 ADMIN CHECK TABLE 结果不正确的问题 #7975 PD 修复下线后的 TiKV 没有从 Grafana 面板中移除的问题 #1261 修复 grpc-go 设置 status 时的 data race 问题#1265 修复 etcd 启动失败导致的服务挂起问题 #1267 修复 leader 切换过程中可能产生的 data race #1273 修复下线 TiKV 时可能输出多余 warning 日志的问题 #1280 TiKV 优化 apply snapshot 导致的 RocksDB Write stall 的问题 #3606 增加 raftstore tick 相关 metrics #3657 升级 RocksDB,修复写入卡死及 IngestExternalFile 时可能写坏源文件的问题 #3661 升级 grpcio,修复 “too many pings” 误报的问题 #3650 "}, {"url": "https://pingcap.com/docs/releases/21rc4/", "title": "TiDB 2.1 RC4 Release Notes", "content": " TiDB 2.1 RC4 Release Notes On October 23, 2018, TiDB 2.1 RC4 is released. Compared with TiDB 2.1 RC3, this release has great improvement in stability, SQL optimizer, statistics information, and execution engine.TiDB SQL Optimizer Fix the issue that column pruning of UnionAll is incorrect in some cases #7941 Fix the issue that the result of the UnionAll operator is incorrect in some cases #8007 SQL Execution Engine Fix the precision issue of the AVG function #7874 Support using the EXPLAIN ANALYZE statement to check the runtime statistics including the execution time and the number of returned rows of each operator during the query execution process #7925 Fix the panic issue of the PointGet operator when a column of a table appears multiple times in the result set #7943 Fix the panic issue caused by too large values in the Limit subclause #8002 Fix the panic issue during the execution process of the AddDate/SubDate statement in some cases #8009 Statistics Fix the issue of judging the prefix of the histogram low-bound of the combined index as out of range #7856 Fix the memory leak issue caused by statistics collecting #7873 Fix the panic issue when the histogram is empty #7928 Fix the issue that the histogram bound is out of range when the statistics is being uploaded #7944 Limit the maximum length of values in the statistics sampling process #7982 Server Refactor Latch to avoid misjudgment of transaction conflicts and improve the execution performance of concurrent transactions #7711 Fix the panic issue caused by collecting slow queries in some cases #7874 Fix the panic issue when ESCAPED BY is an empty string in the LOAD DATA statement #8005 Complete the “coprocessor error” log information #8006 Compatibility Set the Command field of the SHOW PROCESSLIST result to Sleep when the query is empty #7839 Expressions Fix the constant folding issue of the SYSDATE function #7895 Fix the issue that SUBSTRING_INDEX panics in some cases #7897 DDL Fix the stack overflow issue caused by throwing the invalid ddl job type error #7958 Fix the issue that the result of ADMIN CHECK TABLE is incorrect in some cases #7975 PD Fix the issue that the tombstone TiKV is not removed from Grafana #1261 Fix the data race issue when grpc-go configures the status #1265 Fix the issue that the PD server gets stuck caused by etcd startup failure #1267 Fix the issue that data race might occur during leader switching #1273 Fix the issue that extra warning logs might be output when TiKV becomes tombstone #1280 TiKV Optimize the RocksDB Write stall issue caused by applying snapshots #3606 Add raftstore tick metrics #3657 Upgrade RocksDB and fix the Write block issue and that the source file might be damaged by the Write operation when performing IngestExternalFile #3661 Upgrade grpcio and fix the issue that “too many pings” is wrongly reported #3650 "}, {"url": "https://pingcap.com/docs-cn/releases/21rc5/", "title": "TiDB 2.1 RC5 Release Notes", "content": " TiDB 2.1 RC5 Release Notes 2018 年 11 月 12 日,TiDB 发布 2.1 RC5 版。相比 2.1 RC4 版本,该版本对系统稳定性、优化器、统计信息以及执行引擎做了很多改进。TiDB SQL 优化器 修复 IndexReader 在某些情况下读取的 handle 不正确的问题 #8132 修复 IndexScan Prepared 语句在使用 Plan Cache 的时候的问题 #8055 修复 Union 语句结果不稳定的问题 #8165 执行器 提升 TiDB 插入和更新宽表的性能 #8024 内建函数 Truncate 支持 unsigned int 参数 #8068 修复转换 JSON 数据到 decimal 类型出错的问题 #8109 修复 float 类型在 Update 时出错的问题 #8170 统计信息 修复点查在某些情况下,统计信息出现错误的问题 #8035 修复统计信息某些情况下在 primary key 的选择率的问题 #8149 修复被删除的表的统计信息长时间没有清理的问题 #8182 Server 提升日志的可读性,完善日志信息 #8063 #8053 #8224 修复获取 infoschema.profiling 表数据出错的问题 #8096 替换 unix socket,使用 pumps client 来写 binlog #8098 增加环境变量 tidb_slow_log_threshold 动态设置 slow log 的阈值 #8094 增加环境变量 tidb_query_log_max_len 动态设置日志中被截断的原始 SQL 语句的长度 #8200 增加环境变量 tidb_opt_write_row_id 来控制是否允许写入 _tidb_rowid #8218 ticlient Scan 命令增加边界,解决数据扫出边界的问题 #8081,#8247 DDL 修复在事务中某些情况下执行 DDL 语句出错的问题 #8056 修复 partition 分区表执行 truncate table 没有生效的问题 #8103 修复某些情况下 DDL 操作在被 cancel 之后没有正确回滚的问题 #8057 增加命令 admin show next_row_id,返回下一个可用的行 ID #8268 PD 修复 pd-ctl 读取 Region key 的相关问题 #1298 #1299 #1308 修复 regions/check API 输出错误的问题 #1311 修复 PD join 失败后无法重新 join 的问题 #1279 修复某些情况下 watch leader 会丢失事件的问题 #1317 TiKV 优化 WriteConflict 报错信息 #3750 增加 panic 标记文件 #3746 降级 grpcio,避免新版本 gRPC 导致的 segment fault 问题 #3650 增加 kv_scan 接口扫描上界的限制 #3749 Tools TiDB 支持 TiDB-Binlog cluster,不兼容旧版本 TiDB-Binlog #8093,使用文档 "}, {"url": "https://pingcap.com/docs/releases/21rc5/", "title": "TiDB 2.1 RC5 Release Notes", "content": " TiDB 2.1 RC5 Release Notes On November 12, 2018, TiDB 2.1 RC5 is released. Compared with TiDB 2.1 RC4, this release has great improvement in stability, SQL optimizer, statistics information, and execution engine.TiDB SQL Optimizer Fix the issue that IndexReader reads the wrong handle in some cases #8132 Fix the issue occurred while the IndexScan Prepared statement uses Plan Cache #8055 Fix the issue that the result of the Union statement is unstable #8165 SQL Execution Engine Improve the performance of TiDB on inserting or updating wide tables #8024 Support the unsigned int flag in the Truncate built-in function #8068 Fix the error occurred while converting JSON data to the decimal type #8109 Fix the error occurred when you Update the float type #8170 Statistics Fix the incorrect statistics issue during point queries in some cases #8035 Fix the selectivity estimation of statistics for primary key in some cases #8149 Fix the issue that the statistics of deleted tables are not cleared up for a long period of time #8182 Server Improve the readability of logs and make logs better #8063 #8053 #8224 Fix the error occurred when obtaining the table data of infoschema.profiling #8096 Replace the unix socket with the pumps client to write binlogs #8098 Add the threshold value for the tidb_slow_log_threshold environment variable, which dynamically sets the slow log #8094 Add the original length of a SQL statement truncated while the tidb_query_log_max_len environment variable dynamically sets logs #8200 Add the tidb_opt_write_row_id environment variable to control whether to allow writing _tidb_rowid #8218 Add an upper bound to the Scan command of ticlient, to avoid overbound scan #8081, #8247 DDL Fix the issue that executing DDL statements in transactions encounters an error in some cases #8056 Fix the issue that executing truncate table in partition tables does not take effect #8103 Fix the issue that the DDL operation does not roll back correctly after being cancelled in some cases #8057 Add the admin show next_row_id command to return the next available row ID #8268 PD Fix the issues related to pd-ctl reading the Region key #1298 #1299 #1308 Fix the issue that the regions/check API returns the wrong result #1311 Fix the issue that PD cannot restart join after a PD join failure #1279 Fix the issue that watch leader might lose events in some cases #1317 TiKV Improve the error message of WriteConflict #3750 Add the panic mark file #3746 Downgrade grpcio to avoid the segment fault issue caused by the new version of gRPC #3650 Add an upper limit to the kv_scan interface #3749 Tools Support the TiDB-Binlog cluster, which is not compatible with the older version of binlog #8093, documentation "}, {"url": "https://pingcap.com/docs/op-guide/tidb-v2.1-upgrade-guide/", "title": "TiDB 2.1 Upgrade Guide", "content": " TiDB 2.1 Upgrade Guide This document describes how to upgrade from TiDB 2.0 (TiDB 2.0.1 or later) or TiDB 2.1 RC version to TiDB 2.1 GA version. Note: TiDB 2.1 is not compatible with the Kafka version of TiDB-Binlog. If your current TiDB cluster has already been using the Kafka version of TiDB-Binlog, you need to upgrade it to the cluster version of TiDB-Binlog. For details about using Ansible to perform a rolling update to each component, see Perform a rolling update using Ansible.Upgrade caveat TiDB 2.1 does not support downgrading to v2.0.x or earlier due to the adoption of the new storage engine Parallel DDL is enabled in TiDB 2.1, so the clusters with TiDB version earlier than 2.0.1 cannot upgrade to 2.1 using rolling update. You can choose either of the following two options: Stop the cluster and upgrade to 2.1 directly Roll update to 2.0.1 or later 2.0.x versions, and then roll update to the 2.1 version If you upgrade from TiDB 2.0.6 or earlier to TiDB 2.1, check if there is any ongoing DDL operation, especially the time consuming Add Index operation, because the DDL operations slow down the upgrading process. If there is ongoing DDL operation, wait for the DDL operation finishes and then roll update. Step 1: Install Ansible and dependencies on the Control Machine TiDB-Ansible release-2.1 depends on Ansible 2.4.2 ~ 2.7.0 (ansible>=2.4.2,<2.7.0) and the Python module jinja2>=2.9.6 and jmespath>=0.9.0.To make it easy to manage dependencies, use pip to install Ansible and its dependencies. For details, see Install Ansible and its dependencies on the Control Machine. For offline environment, see Install Ansible and its dependencies offline on the Control Machine.After the installation is finished, you can view the version information using the following command:$ ansible --version ansible 2.6.8 $ pip show jinja2 Name: Jinja2 Version: 2.10 $ pip show jmespath Name: jmespath Version: 0.9.3 Note: You must install Ansible and its dependencies following the above procedures. Make sure that the Jinja2 version is correct, otherwise an error occurs when you start Grafana. Make sure that the jmespath version is correct, otherwise an error occurs when you perform a rolling update for TiKV. Step 2: Download TiDB-Ansible to the Control Machine Log in to the Control Machine using the tidb user account and enter the /home/tidb directory. Back up the tidb-ansible folders of TiDB 2.0 or TiDB 2.1 RC versions using the following command:$ mv tidb-ansible tidb-ansible-bak Download the latest tidb-ansible release-2.1 branch using the following command. The default folder name is tidb-ansible.$ git clone -b release-2.1 https://github.com/pingcap/tidb-ansible.git Step 3: Edit the inventory.ini file and the configuration file Log in to the Control Machine using the tidb user account and enter the /home/tidb/tidb-ansible directory.Edit the inventory.ini file Edit the inventory.ini file. For IP information, see the /home/tidb/tidb-ansible-bak/inventory.ini backup file.Pay special attention to the following variables configuration. For variable meaning, see Description of other variables. Make sure that ansible_user is the normal user. For unified privilege management, remote installation using the root user is no longer supported. The default configuration uses the tidb user as the SSH remote user and the program running user.## Connection # ssh via normal user ansible_user = tidb You can refer to How to configure SSH mutual trust and sudo rules on the Control Machine to automatically configure the mutual trust among hosts. Keep the process_supervision variable consistent with that in the previous version. It is recommended to use systemd by default.# process supervision, [systemd, supervise] process_supervision = systemd If you need to modify this variable, see How to modify the supervision method of a process from supervise to systemd. Before you upgrade, first use the /home/tidb/tidb-ansible-bak/ backup branch to modify the supervision method of a process. Edit the configuration file of TiDB cluster components If you have previously customized the configuration file of TiDB cluster components, refer to the backup file to modify the corresponding configuration file in /home/tidb/tidb-ansible/conf.In TiKV configuration, end-point-concurrency is changed to three parameters: high-concurrency, normal-concurrency and low-concurrency.readpool: coprocessor: # Notice: if CPU_NUM > 8, default thread pool size for coprocessors # will be set to CPU_NUM * 0.8. # high-concurrency: 8 # normal-concurrency: 8 # low-concurrency: 8 For the cluster topology of multiple TiKV instances on a single machine, you need to modify the three parameters above. Recommended configuration: number of instances * parameter value = number of CPU cores * 0.8.Step 4: Download TiDB 2.1 binary to the Control Machine Make sure that tidb_version = v2.1.0 in the tidb-ansible/inventory.ini file, and then run the following command to download TiDB 2.1 binary to the Control Machine:$ ansible-playbook local_prepare.yml Step 5: Perform a rolling update to TiDB cluster components $ ansible-playbook rolling_update.yml Step 6: Perform a rolling update to TiDB monitoring component $ ansible-playbook rolling_update_monitor.yml"}, {"url": "https://pingcap.com/docs-cn/op-guide/tidb-v2.1-upgrade-guide/", "title": "TiDB 2.1 升级操作指南", "content": " TiDB 2.1 升级操作指南 本文档适用于从 TiDB 2.0 版本(v2.0.1 及之后版本)或 TiDB 2.1 RC 版本升级到 TiDB 2.1 GA 版本。TiDB 2.1 版本不兼容 Kafka 版本的 TiDB-Binlog,如果当前集群已经使用 Kafka 版本的 TiDB-Binlog,须参考 Binlog 升级方法升级到 Cluster 版本。升级兼容性说明 新版本存储引擎更新,不支持在升级后回退至 2.0.x 或更旧版本 从 2.0.6 之前的版本升级到 2.1 之前,需要确认集群中是否存在正在运行中的 DDL 操作,特别是耗时的 Add Index 操作,等 DDL 操作完成后再执行升级操作 2.1 版本启用了并行 DDL,早于 2.0.1 版本的集群,无法滚动升级到 2.1,可以选择下面两种方案: 停机升级,直接从早于 2.0.1 的 TiDB 版本升级到 2.1 先滚动升级到 2.0.1 或者之后的 2.0.x 版本,再滚动升级到 2.1 版本 在中控机器上安装 Ansible 及其依赖 TiDB-Ansible release-2.1 版本依赖 2.4.2 及以上但不高于 2.7.0 的 Ansible 版本(ansible>=2.4.2,<2.7.0),另依赖 Python 模块:jinja2>=2.9.6 和 jmespath>=0.9.0。为方便管理依赖,新版本使用 pip 安装 Ansible 及其依赖,可参照在中控机器上安装 Ansible 及其依赖 进行安装。离线环境参照在中控机器上离线安装 Ansible 及其依赖。安装完成后,可通过以下命令查看版本:$ ansible --version ansible 2.6.8 $ pip show jinja2 Name: Jinja2 Version: 2.10 $ pip show jmespath Name: jmespath Version: 0.9.3 注意:请务必按以上文档安装 Ansible 及其依赖。确认 Jinja2 版本是否正确,否则启动 Grafana 时会报错。确认 jmespath 版本是否正确,否则滚动升级 TiKV 时会报错。 在中控机器上下载 TiDB-Ansible 以 tidb 用户登录中控机并进入 /home/tidb 目录,备份 TiDB 2.0 版本或 TiDB 2.1 rc 版本的 tidb-ansible 文件夹:$ mv tidb-ansible tidb-ansible-bak 下载最新 tidb-ansible release-2.1 分支,默认的文件夹名称为 tidb-ansible。$ git clone -b release-2.1 https://github.com/pingcap/tidb-ansible.git 编辑 inventory.ini 文件和配置文件 以 tidb 用户登录中控机并进入 /home/tidb/tidb-ansible 目录。编辑 inventory.ini 文件 编辑 inventory.ini 文件,IP 信息参照备份文件 /home/tidb/tidb-ansible-bak/inventory.ini。以下变量配置,需要重点确认,变量含义可参考 inventory.ini 变量调整。 请确认 ansible_user 配置的是普通用户。为统一权限管理,不再支持使用 root 用户远程安装。默认配置中使用 tidb 用户作为 SSH 远程用户及程序运行用户。## Connection # ssh via normal user ansible_user = tidb 可参考如何配置 ssh 互信及 sudo 规则 自动配置主机间互信。 process_supervision 变量请与之前版本保持一致,默认推荐使用 systemd。# process supervision, [systemd, supervise] process_supervision = systemd 如需变更,可参考 如何调整进程监管方式从 supervise 到 systemd,先使用备份 /home/tidb/tidb-ansible-bak/ 分支变更进程监管方式再升级。 编辑 TiDB 集群组件配置文件 如之前自定义过 TiDB 集群组件配置文件,请参照备份文件修改 /home/tidb/tidb-ansible/conf 下对应配置文件。TiKV 配置中 end-point-concurrency 变更为 high-concurrency、normal-concurrency 和 low-concurrency 三个参数:readpool: coprocessor: # Notice: if CPU_NUM > 8, default thread pool size for coprocessors # will be set to CPU_NUM * 0.8. # high-concurrency: 8 # normal-concurrency: 8 # low-concurrency: 8 单机多 TiKV 实例情况下,需要修改这三个参数,推荐设置:实例数 * 参数值 = CPU 核数 * 0.8。下载 TiDB 2.1 binary 到中控机 确认 tidb-ansible/inventory.ini 文件中 tidb_version = v2.1.0,然后执行以下命令下载 TiDB 2.1 binary 到中控机。$ ansible-playbook local_prepare.yml 滚动升级 TiDB 集群组件 $ ansible-playbook rolling_update.yml 滚动升级 TiDB 监控组件 $ ansible-playbook rolling_update_monitor.yml"}, {"url": "https://pingcap.com/docs-cn/releases/2.1.1/", "title": "TiDB 2.1.1 Release Notes", "content": " TiDB 2.1.1 Release Notes 2018 年 12 月 12 日,TiDB 发布 2.1.1 版。相比 2.1.0 版本,该版本对系统稳定性、优化器、统计信息以及执行引擎做了很多改进。TiDB 优化器/执行器 修复时间为负值时的四舍五入错误 #8574 修复 uncompress 函数未检查数据长度的问题 #8606 在执行 execute 命令后重置 prepare 语句绑定的变量 #8652 支持对分区表自动收集统计信息 #8649 修复在下推 abs 函数时设置错误的整数类型 #8628 修复 JSON 列的数据竞争问题 #8660 Server 修复在 PD 故障时获取错误 TSO 的问题 #8567 修复不规范的语句导致启动失败的问题 #8576 修复在事务重试时使用了错误的参数 #8638 DDL 将表的默认字符集和排序规则改为 utf8mb4 和 utf8mb4_bin #8590 增加变量 ddl_reorg_batch_size 来控制添加索引的速度 #8614 DDL 中的 character set 和 collation 选项内容不再大小写敏感 #8611 修复对于生成列添加索引的问题 #8655 PD 修复一些配置项无法在配置文件中设置为 0 的问题 #1334 启动时检查未定义的配置 #1362 避免 transfer leader 至新创建的 Peer,优化可能产生的延迟增加问题 #1339 修复 RaftCluster 在退出时可能的死锁问题 #1370 TiKV 避免 transfer leader 至新创建的 Peer,优化可能产生的延迟增加问题 #3878 Tools Lightning 优化对导入表的 analyze 机制,提升了导入速度 支持 checkpoint 信息储存在本地文件 TiDB-Binlog 修复 pb files 输出 bug,表只有主键列则无法产生 pb event "}, {"url": "https://pingcap.com/docs/releases/2.1.1/", "title": "TiDB 2.1.1 Release Notes", "content": " TiDB 2.1.1 Release Notes On December 12, 2018, TiDB 2.1.1 is released. Compared with TiDB 2.1.0, this release has great improvement in stability, SQL optimizer, statistics information, and execution engine.TiDB SQL Optimizer/Executor Fix the round error of the negative date #8574 Fix the issue that the uncompress function does not check the data length #8606 Reset bind arguments of the prepare statement after the execute command is executed #8652 Support automatically collecting the statistics information of a partition table #8649 Fix the wrongly configured integer type when pushing down the abs function #8628 Fix the data race on the JSON column #8660 Server Fix the issue that the transaction obtained TSO is incorrect when PD breaks down #8567 Fix the bootstrap failure caused by the statement that does not conform to ANSI standards #8576 Fix the issue that incorrect parameters are used in transaction retries #8638 DDL Change the default character set and collation of tables into utf8mb4 #8590 Add the ddl_reorg_batch_size variable to control the speed of adding indexes #8614 Make the character set and collation options content in DDL case-insensitive #8611 Fix the issue of adding indexes for generated columns #8655 PD Fix the issue that some configuration items cannot be set to 0 in the configuration file #1334 Check the undefined configuration when starting PD #1362 Avoid transferring the leader to a newly created peer, to optimize the possible delay #1339 Fix the issue that RaftCluster cannot stop caused by deadlock #1370 TiKV Avoid transferring the leader to a newly created peer, to optimize the possible delay #3878 Tools Lightning Optimize the analyze mechanism on imported tables to increase the import speed Support storing the checkpoint information to a local file TiDB-Binlog Fix the output bug of pb files that a table only with the primary key column cannot generate the pb event "}, {"url": "https://pingcap.com/docs-cn/releases/2.1.2/", "title": "TiDB 2.1.2 Release Notes", "content": " TiDB 2.1.2 Release Notes 2018 年 12 月 22 日,TiDB 发布 2.1.2 版,TiDB-Ansible 相应发布 2.1.2 版本。该版本在 2.1.1 版的基础上,对系统兼容性、稳定性做出了改进。TiDB 兼容 Kafka 版本的 TiDB-Binlog #8747 完善滚动升级下 TiDB 的退出机制 #8707 修复在某些情况下为 generated column 增加索引 panic 的问题 #8676 修复在某些情况下语句有 TIDB_SMJ Hint 的时候优化器无法找到正确执行计划的问题 #8729 修复在某些情况下 AntiSemiJoin 返回错误结果的问题 #8730 增强 utf8 字符集的有效字符检查 #8754 修复事务中先写后读的情况下时间类型字段可能返回错误结果的问题 #8746 PD 修复 Region Merge 相关的 Region 信息更新问题 #1377 TiKV 支持以日 (d) 为时间单位的配置格式,并解决配置兼容性问题 #3931 修复 Approximate Size Split 可能会 panic 的问题 #3942 修复两个 Region merge 相关问题 #3822,#3873 Tools TiDB-Lightning 支持最小 TiDB 集群版本为 2.1.0 修复解析包含 JSON 类型数据的文件内容出错 #144 修复使用 checkpoint 重启后 Too many open engines 错误 TiDB-Binlog 消除了 Drainer 往 Kafka 写数据的一些瓶颈点 TiDB 支持写 Kafka 版本的 TiDB-Binlog "}, {"url": "https://pingcap.com/docs/releases/2.1.2/", "title": "TiDB 2.1.2 Release Notes", "content": " TiDB 2.1.2 Release Notes On December 22, 2018, TiDB 2.1.2 is released. The corresponding TiDB-Ansible 2.1.2 is also released. Compared with TiDB 2.1.1, this release has great improvement in system compatibility and stability.TiDB Make TiDB compatible with TiDB-Binlog of the Kafka version #8747 Improve the exit mechanism of TiDB in a rolling update #8707 Fix the panic issue caused by adding the index for the generated column in some cases #8676 Fix the issue that the optimizer cannot find the optimal query plan when TIDB_SMJ Hint exists in the SQL statement in some cases #8729 Fix the issue that AntiSemiJoin returns an incorrect result in some cases #8730 Improve the valid character check of the utf8 character set #8754 Fix the issue that the field of the time type might return an incorrect result when the write operation is performed before the read operation in a transaction #8746 PD Fix the Region information update issue about Region merge #1377 TiKV Support the configuration format in the unit of DAY (d) and fix the configuration compatibility issue #3931 Fix the possible panic issue caused by Approximate Size Split #3942 Fix two issues about Region merge #3822, #3873 Tools TiDB-Lightning Make TiDB 2.1.0 the minimum cluster version supported by Lightning Fix the content error of the file involving parsed JSON data in Lightning #144 Fix the issue that Too many open engines occurs after the checkpoint is used to restart Lightning TiDB-Binlog Eliminate some bottlenecks of Drainer writing data to Kafka Support the Kafka version of TiDB-Binlog "}, {"url": "https://pingcap.com/docs/adopters/", "title": "TiDB Adopters", "content": " TiDB Adopters This is a list of TiDB adopters in various industries. Company Industry Success Story Mobike Ridesharing English; Chinese Jinri Toutiao Mobile News Platform Chinese Yiguo.com E-commerce English; Chinese Yuanfudao.com EdTech English; Chinese Ele.me Food Delivery English; Chinese-1; Chinese-2 Xiaomi Consumer Electronics Chinese LY.com Travel Chinese Qunar.com Travel Chinese Hulu Entertainment VIPKID EdTech Lenovo Enterprise Technology Bank of Beijing Banking Chinese Industrial and Commercial Bank of China Banking iQiyi Media and Entertainment English; Chinese Yimian Data Big Data Chinese CAASDATA Big Data Chinese Phoenix New Media Media Chinese Mobikok AdTech Chinese LinkDoc Technology HealthTech Chinese G7 Networks Logistics Chinese Hive-Box Logistics Chinese 360 Finance FinTech Chinese GAEA Gaming English; Chinese YOOZOO Games Gaming Chinese Seasun Games Gaming Chinese NetEase Games Gaming FUNYOURS JAPAN Gaming Chinese Zhaopin.com Recruiting Panda.tv Live Streaming Hoodinn Gaming Ping++ Mobile Payment Chinese Hainan eKing Technology Enterprise Technology Chinese LianLian Tech Mobile Payment Tongdun Technology FinTech Wacai FinTech Tree Finance FinTech 2Dfire.com FoodTech Chinese Happigo.com E-commerce Mashang Consumer Finance FinTech Tencent OMG Media Terren Media LeCloud Media Miaopai Media Snowball Finance FinTech Yimutian E-commerce Gengmei Plastic Surgery Acewill FoodTech Keruyun SaaS Chinese Youju Tech E-Commerce Maizuo E-Commerce Mogujie E-Commerce Zhuan Zhuan Online Marketplace English; Chinese Shuangchuang Huipu FinTech Meizu Media SEA group Gaming Sogou MediaTech Chunyu Yisheng HealthTech Meituan-Dianping Food Delivery English; Chinese Qutoutiao Social Network QuantGroup FinTech FINUP FinTech Meili Finance FinTech Guolian Securities Financial Services Founder Securities Financial Services China Telecom Shanghai Telecom State Administration of Taxation Finance Wuhan Antian Information Technology Enterprise Technology Ausnutria Dairy FoodTech Qingdao Telaidian Electric Car Charger Chinese "}, {"url": "https://pingcap.com/docs/v1.0/adopters/", "title": "TiDB Adopters", "content": " TiDB Adopters This is a list of TiDB adopters in various industries. Mobike (Ridesharing) Yiguo.com (E-commerce) Phoenix TV (Media) Ping++ (Payment) Qunar.com (Travel) LinkDoc Technology (HealthTech) Yuanfudao (EdTech) ZuoZhu Financial (FinTech) 360 Financial (FinTech) GAEA (Gaming) YOOZOO GAMES (Gaming) Hainan eKing Technology (Enterprise Technology) 2Dfire (FoodTech) G7 (Internet of Things) Yimian Data (Big Data) Wanda Internet Technology Group (Big Data) "}, {"url": "https://pingcap.com/docs/v2.0/adopters/", "title": "TiDB Adopters", "content": " TiDB Adopters This is a list of TiDB adopters in various industries. Company Industry Success Story Mobike Ridesharing English; Chinese Jinri Toutiao Mobile News Platform Chinese Yiguo.com E-commerce English; Chinese Yuanfudao.com EdTech English; Chinese Ele.me Food Delivery English; Chinese LY.com Travel Chinese Qunar.com Travel Chinese Hulu Entertainment VIPKID EdTech Lenovo Enterprise Technology Bank of Beijing Banking Industrial and Commercial Bank of China Banking iQiyi Media and Entertainment Yimian Data Big Data Chinese Phoenix New Media Media Chinese Mobikok AdTech Chinese LinkDoc Technology HealthTech Chinese G7 Networks Logistics Chinese 360 Finance FinTech Chinese GAEA Gaming English; Chinese YOOZOO Games Gaming Chinese Seasun Games Gaming Chinese NetEase Games Gaming FUNYOURS JAPAN Gaming Chinese Zhaopin.com Recruiting Panda.tv Live Streaming Hoodinn Gaming Ping++ Mobile Payment Chinese Hainan eKing Technology Enterprise Technology Chinese LianLian Tech Mobile Payment Tongdun Technology FinTech Wacai FinTech Tree Finance FinTech 2Dfire.com FoodTech Chinese Happigo.com E-commerce Mashang Consumer Finance FinTech Tencent OMG Media Terren Media LeCloud Media Miaopai Media Snowball Finance FinTech Yimutian E-commerce Gengmei Plastic Surgery Acewill FoodTech Keruyun SaaS Chinese Youju Tech E-Commerce Maizuo E-Commerce Mogujie E-Commerce Zhuan Zhuan Online Marketplace Chinese Shuangchuang Huipu FinTech Meizu Media SEA group Gaming Sogou MediaTech Chunyu Yisheng HealthTech Meituan Food Delivery Qutoutiao Social Network QuantGroup FinTech FINUP FinTech Meili Finance FinTech Guolian Securities Financial Services Founder Securities Financial Services China Telecom Shanghai Telecom State Administration of Taxation Finance Wuhan Antian Information Technology Enterprise Technology Ausnutria Dairy FoodTech Qingdao Telaidian Electric Car Charger "}, {"url": "https://pingcap.com/docs/architecture/", "title": "TiDB Architecture", "content": " TiDB Architecture The TiDB platform is comprised of three key components: the TiDB server, the PD server, and the TiKV server. In addition, TiDB also provides the TiSpark component for complex OLAP requirements.TiDB server The TiDB server is in charge of the following operations: Receiving the SQL requests Processing the SQL related logics Locating the TiKV address for storing and computing data through Placement Driver (PD) Exchanging data with TiKV Returning the result The TiDB server is stateless. It does not store data and it is for computing only. TiDB is horizontally scalable and provides the unified interface to the outside through the load balancing components such as Linux Virtual Server (LVS), HAProxy, or F5.Placement Driver server The Placement Driver (PD) server is the managing component of the entire cluster and is in charge of the following three operations: Storing the metadata of the cluster such as the region location of a specific key. Scheduling and load balancing regions in the TiKV cluster, including but not limited to data migration and Raft group leader transfer. Allocating the transaction ID that is globally unique and monotonic increasing. As a cluster, PD needs to be deployed to an odd number of nodes. Usually it is recommended to deploy to 3 online nodes at least.TiKV server The TiKV server is responsible for storing data. From an external view, TiKV is a distributed transactional Key-Value storage engine. Region is the basic unit to store data. Each Region stores the data for a particular Key Range which is a left-closed and right-open interval from StartKey to EndKey. There are multiple Regions in each TiKV node. TiKV uses the Raft protocol for replication to ensure the data consistency and disaster recovery. The replicas of the same Region on different nodes compose a Raft Group. The load balancing of the data among different TiKV nodes are scheduled by PD. Region is also the basic unit for scheduling the load balance.TiSpark TiSpark deals with the complex OLAP requirements. TiSpark makes Spark SQL directly run on the storage layer of the TiDB cluster, combines the advantages of the distributed TiKV cluster, and integrates into the big data ecosystem. With TiSpark, TiDB can support both OLTP and OLAP scenarios in one cluster, so the users never need to worry about data synchronization."}, {"url": "https://pingcap.com/docs-cn/v1.0/op-guide/binary-deployment/", "title": "TiDB Binary 部署方案详解", "content": " TiDB Binary 部署指导 概述 一个完整的 TiDB 集群包括 PD,TiKV 以及 TiDB。启动顺序依次是 PD,TiKV 以及 TiDB。在关闭数据库服务时,请按照启动的相反顺序进行逐一关闭服务。阅读本章前,请先确保阅读 TiDB 整体架构及部署建议。本文档描述了三种场景的二进制部署方式: 快速了解和试用 TiDB,推荐使用单节点方式快速部署。 功能性测试 TiDB,推荐使用功能性测试部署。 生产环境使用 TiDB,推荐使用多节点集群模式部署。 TiDB 组件及默认端口 1. TiDB 数据库组件(必装) 组件 默认端口 协议 说明 ssh 22 TCP sshd 服务 TiDB 4000 TCP 应用及 DBA 工具访问通信端口 TiDB 10080 TCP TiDB 状态信息上报通信端口 TiKV 20160 TCP TiKV 通信端口 PD 2379 TCP 提供 TiDB 和 PD 通信端口 PD 2380 TCP PD 集群节点间通信端口 2. TiDB 数据库组件(选装) 组件 默认端口 协议 说明 Prometheus 9090 TCP Prometheus 服务通信端口 Pushgateway 9091 TCP TiDB, TiKV, PD 监控聚合和上报端口 Node_exporter 9100 TCP TiDB 集群每个节点的系统信息上报通信端口 Grafana 3000 TCP Web 监控服务对外服务和客户端(浏览器)访问端口 alertmanager 9093 TCP 告警服务端口 TiDB 安装前系统配置与检查 操作系统检查 配置 描述 支持平台 请查看和了解系统部署建议 文件系统 TiDB 部署环境推荐使用 ext4 文件系统 Swap 空间 TiDB 部署推荐关闭 Swap 空间 Disk Block Size 设置系统磁盘 Block 大小为 4096 网络与防火墙 配置 描述 防火墙 / 端口 请查看 TiDB 所需端口在各个节点之间是否能正常访问 操作系统参数 配置 说明 Nice Limits 系统用户 tidb 的 nice 值设置为缺省值 0 min_free_kbytes 在 sysctl.conf 中关于 vm.min_free_kbytes 的设置需要足够高 User Open Files Limit 对数据库管理员 tidb 的 open 文件数设置为 1000000 System Open File Limits 对系统的 open 文件数设置为 1000000 User Process Limits 在 limits.conf 配置的 tidb 用户的 nproc 为 4096 Address Space Limits 在 limits.conf 配置的 tidb 用户空间为 unlimited File Size Limits 在 limits.conf 配置的 tidb 用户 fsize 为 unlimited Disk Readahead 设置数据磁盘 readahead 至少为 4096 NTP 服务 为各个节点配置 NTP 时间同步服务 SELinux 关闭各个节点的 SELinux 服务 CPU Frequency Scaling TiDB 推荐打开 CPU 超频 Transparent Hugepages 针对 Red Hat 7+ 和 CentOS 7+ 系统, Transparent Hugepages 必须被设置为 always I/O Scheduler 设置数据磁盘 I/0 Schedule 设置为 deadline 模式 vm.swappiness 设置 vm.swappiness = 0 注意:请联系系统管理员进行操作系统参数调整。 数据库运行用户设置 配置 说明 LANG 环境设定 设置 LANG = en_US.UTF8 TZ 时区设定 确保所有节点的时区 TZ 设置为一样的值 创建系统数据库运行账户 在 Linux 环境下,在每台安装节点上创建 tidb 作为数据库系统运行用户并设置集群节点之间的 ssh 互信访问。以下是一个示例,具体创建用户与开通 ssh 互信访问请联系系统管理员进行。# useradd tidb # usermod -a -G tidb tidb # su - tidb Last login: Tue Aug 22 12:06:23 CST 2017 on pts/2 -bash-4.2$ ssh-keygen -t rsa Generating public/private rsa key pair. Enter file in which to save the key (/home/tidb/.ssh/id_rsa): Created directory '/home/tidb/.ssh'. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/tidb/.ssh/id_rsa. Your public key has been saved in /home/tidb/.ssh/id_rsa.pub. The key fingerprint is: 5a:00:e6:df:9e:40:25:2c:2d:e2:6e:ee:74:c6:c3:c1 tidb@t001 The key's randomart image is: +--[ RSA 2048]----+ | oo. . | | .oo.oo | | . ..oo | | .. o o | | . E o S | | oo . = . | | o. * . o | | ..o . | | .. | +-----------------+ -bash-4.2$ cd .ssh -bash-4.2$ cat id_rsa.pub >> authorized_keys -bash-4.2$ chmod 644 authorized_keys -bash-4.2$ ssh-copy-id -i ~/.ssh/id_rsa.pub 192.168.1.100 下载官方 Binary TiDB 官方提供了支持 Linux 版本的二进制安装包,官方推荐使用 Redhat 7+、CentOS 7+ 以上版本的操作系统,不推荐在 Redhat 6、CentOS 6 上部署 TiDB 集群。操作系统:Linux ( Redhat 7+,CentOS 7+ ) 执行步骤:# 下载压缩包 wget http://download.pingcap.org/tidb-latest-linux-amd64.tar.gz wget http://download.pingcap.org/tidb-latest-linux-amd64.sha256 # 检查文件完整性,返回 ok 则正确 sha256sum -c tidb-latest-linux-amd64.sha256 # 解开压缩包 tar -xzf tidb-latest-linux-amd64.tar.gz cd tidb-latest-linux-amd64 单节点方式快速部署 在获取 TiDB 二进制文件包后,我们可以在单机上面,运行和测试 TiDB 集群,请按如下步骤依次启动 PD,TiKV,TiDB。 注意:以下启动各个应用程序组件实例的时候,请选择后台启动,避免前台失效后程序自动退出。 步骤一. 启动 PD:./bin/pd-server --data-dir=pd --log-file=pd.log 步骤二. 启动 TiKV:./bin/tikv-server --pd="127.0.0.1:2379" --data-dir=tikv --log-file=tikv.log 步骤三. 启动 TiDB:./bin/tidb-server --store=tikv --path="127.0.0.1:2379" --log-file=tidb.log 步骤四. 使用 MySQL 客户端连接 TiDB:mysql -h 127.0.0.1 -P 4000 -u root -D test 功能性测试部署 如果只是对 TiDB 进行测试,并且机器数量有限,我们可以只启动一台 PD 测试整个集群。这里我们使用四个节点,部署一个 PD,三个 TiKV,以及一个 TiDB,各个节点以及所运行服务信息如下: Name Host IP Services node1 192.168.199.113 PD1, TiDB node2 192.168.199.114 TiKV1 node3 192.168.199.115 TiKV2 node4 192.168.199.116 TiKV3 请按如下步骤依次启动 PD 集群,TiKV 集群以及 TiDB: 注意:以下启动各个应用程序组件实例的时候,请选择后台启动,避免前台失效后程序自动退出。 步骤一. 在 node1 启动 PD:./bin/pd-server --name=pd1 --data-dir=pd1 --client-urls="http://192.168.199.113:2379" --peer-urls="http://192.168.199.113:2380" --initial-cluster="pd1=http://192.168.199.113:2380" --log-file=pd.log 步骤二. 在 node2,node3,node4 启动 TiKV:./bin/tikv-server --pd="192.168.199.113:2379" --addr="192.168.199.114:20160" --data-dir=tikv1 --log-file=tikv.log ./bin/tikv-server --pd="192.168.199.113:2379" --addr="192.168.199.115:20160" --data-dir=tikv2 --log-file=tikv.log ./bin/tikv-server --pd="192.168.199.113:2379" --addr="192.168.199.116:20160" --data-dir=tikv3 --log-file=tikv.log 步骤三. 在 node1 启动 TiDB:./bin/tidb-server --store=tikv --path="192.168.199.113:2379" --log-file=tidb.log 步骤四. 使用 MySQL 客户端连接 TiDB:mysql -h 192.168.199.113 -P 4000 -u root -D test 多节点集群模式部署 在生产环境中,我们推荐多节点部署 TiDB 集群,首先请参考部署建议。这里我们使用六个节点,部署三个 PD,三个 TiKV,以及一个 TiDB,各个节点以及所运行服务信息如下: Name Host IP Services node1 192.168.199.113 PD1, TiDB node2 192.168.199.114 PD2 node3 192.168.199.115 PD3 node4 192.168.199.116 TiKV1 node5 192.168.199.117 TiKV2 node6 192.168.199.118 TiKV3 请按如下步骤依次启动 PD 集群,TiKV 集群以及 TiDB:步骤一 . 在 node1,node2,node3 依次启动 PD:./bin/pd-server --name=pd1 --data-dir=pd1 --client-urls="http://192.168.199.113:2379" --peer-urls="http://192.168.199.113:2380" --initial-cluster="pd1=http://192.168.199.113:2380,pd2=http://192.168.199.114:2380,pd3=http://192.168.199.115:2380" -L "info" --log-file=pd.log ./bin/pd-server --name=pd2 --data-dir=pd2 --client-urls="http://192.168.199.114:2379" --peer-urls="http://192.168.199.114:2380" --initial-cluster="pd1=http://192.168.199.113:2380,pd2=http://192.168.199.114:2380,pd3=http://192.168.199.115:2380" --join="http://192.168.199.113:2379" -L "info" --log-file=pd.log ./bin/pd-server --name=pd3 --data-dir=pd3 --client-urls="http://192.168.199.115:2379" --peer-urls="http://192.168.199.115:2380" --initial-cluster="pd1=http://192.168.199.113:2380,pd2=http://192.168.199.114:2380,pd3=http://192.168.199.115:2380" --join="http://192.168.199.113:2379" -L "info" --log-file=pd.log 步骤二. 在 node4,node5,node6 启动 TiKV:./bin/tikv-server --pd="192.168.199.113:2379,192.168.199.114:2379,192.168.199.115:2379" --addr="192.168.199.116:20160" --data-dir=tikv1 --log-file=tikv.log ./bin/tikv-server --pd="192.168.199.113:2379,192.168.199.114:2379,192.168.199.115:2379" --addr="192.168.199.117:20160" --data-dir=tikv2 --log-file=tikv.log ./bin/tikv-server --pd="192.168.199.113:2379,192.168.199.114:2379,192.168.199.115:2379" --addr="192.168.199.118:20160" --data-dir=tikv3 --log-file=tikv.log 步骤三. 在 node1 启动 TiDB:./bin/tidb-server --store=tikv --path="192.168.199.113:2379,192.168.199.114:2379,192.168.199.115:2379" --log-file=tidb.log 步骤四. 使用 MySQL 客户端连接 TiDB:mysql -h 192.168.199.113 -P 4000 -u root -D test 注意:在生产环境中启动 TiKV 时,建议使用 --config 参数指定配置文件路径,如果不设置这个参数,TiKV 不会读取配置文件。同样,在生产环境中部署 PD 时,也建议使用 --config 参数指定配置文件路径。 TiKV 调优参见:TiKV 性能参数调优。 注意:如果使用 nohup 在生产环境中启动集群,需要将启动命令放到一个脚本文件里面执行,否则会出现因为 Shell 退出导致 nohup 启动的进程也收到异常信号退出的问题,具体参考进程异常退出。 TiDB 监控和告警环境安装 安装部署监控和告警环境的系统信息如下: Name Host IP Services node1 192.168.199.113 node_export, pushgateway, Prometheus, Grafana node2 192.168.199.114 node_export node3 192.168.199.115 node_export node4 192.168.199.116 node_export 获取二进制包 # 下载压缩包 wget https://github.com/prometheus/prometheus/releases/download/v1.5.2/prometheus-1.5.2.linux-amd64.tar.gz wget https://github.com/prometheus/node_exporter/releases/download/v0.14.0-rc.2/node_exporter-0.14.0-rc.2.linux-amd64.tar.gz wget https://grafanarel.s3.amazonaws.com/builds/grafana-4.1.2-1486989747.linux-x64.tar.gz wget https://github.com/prometheus/pushgateway/releases/download/v0.3.1/pushgateway-0.3.1.linux-amd64.tar.gz # 解开压缩包 tar -xzf …"}, {"url": "https://pingcap.com/docs-cn/v2.0/op-guide/binary-deployment/", "title": "TiDB Binary 部署方案详解", "content": " TiDB Binary 部署指导 概述 一个完整的 TiDB 集群包括 PD,TiKV 以及 TiDB。启动顺序依次是 PD,TiKV 以及 TiDB。在关闭数据库服务时,请按照启动的相反顺序进行逐一关闭服务。阅读本章前,请先确保阅读 TiDB 整体架构及部署建议。本文档描述了三种场景的二进制部署方式: 快速了解和试用 TiDB,推荐使用单节点方式快速部署。 功能性测试 TiDB,推荐使用功能性测试部署。 生产环境使用 TiDB,推荐使用多节点集群模式部署。 TiDB 组件及默认端口 1. TiDB 数据库组件(必装) 组件 默认端口 协议 说明 ssh 22 TCP sshd 服务 TiDB 4000 TCP 应用及 DBA 工具访问通信端口 TiDB 10080 TCP TiDB 状态信息上报通信端口 TiKV 20160 TCP TiKV 通信端口 PD 2379 TCP 提供 TiDB 和 PD 通信端口 PD 2380 TCP PD 集群节点间通信端口 2. TiDB 数据库组件(选装) 组件 默认端口 协议 说明 Prometheus 9090 TCP Prometheus 服务通信端口 Pushgateway 9091 TCP TiDB, TiKV, PD 监控聚合和上报端口 Node_exporter 9100 TCP TiDB 集群每个节点的系统信息上报通信端口 Grafana 3000 TCP Web 监控服务对外服务和客户端(浏览器)访问端口 alertmanager 9093 TCP 告警服务端口 TiDB 安装前系统配置与检查 操作系统检查 配置 描述 支持平台 请查看和了解系统部署建议 文件系统 TiDB 部署环境推荐使用 ext4 文件系统 Swap 空间 TiDB 部署推荐关闭 Swap 空间 Disk Block Size 设置系统磁盘 Block 大小为 4096 网络与防火墙 配置 描述 防火墙 / 端口 请查看 TiDB 所需端口在各个节点之间是否能正常访问 操作系统参数 配置 说明 Nice Limits 系统用户 tidb 的 nice 值设置为缺省值 0 min_free_kbytes 在 sysctl.conf 中关于 vm.min_free_kbytes 的设置需要足够高 User Open Files Limit 对数据库管理员 tidb 的 open 文件数设置为 1000000 System Open File Limits 对系统的 open 文件数设置为 1000000 User Process Limits 在 limits.conf 配置的 tidb 用户的 nproc 为 4096 Address Space Limits 在 limits.conf 配置的 tidb 用户空间为 unlimited File Size Limits 在 limits.conf 配置的 tidb 用户 fsize 为 unlimited Disk Readahead 设置数据磁盘 readahead 至少为 4096 NTP 服务 为各个节点配置 NTP 时间同步服务 SELinux 关闭各个节点的 SELinux 服务 CPU Frequency Scaling TiDB 推荐打开 CPU 超频 Transparent Hugepages 针对 Red Hat 7+ 和 CentOS 7+ 系统, Transparent Hugepages 必须被设置为 always I/O Scheduler 设置数据磁盘 I/0 Schedule 设置为 deadline 模式 vm.swappiness 设置 vm.swappiness = 0 注意:请联系系统管理员进行操作系统参数调整。 数据库运行用户设置 配置 说明 LANG 环境设定 设置 LANG = en_US.UTF8 TZ 时区设定 确保所有节点的时区 TZ 设置为一样的值 创建系统数据库运行账户 在 Linux 环境下,在每台安装节点上创建 tidb 作为数据库系统运行用户并设置集群节点之间的 ssh 互信访问。以下是一个示例,具体创建用户与开通 ssh 互信访问请联系系统管理员进行。# useradd tidb # usermod -a -G tidb tidb # su - tidb Last login: Tue Aug 22 12:06:23 CST 2017 on pts/2 -bash-4.2$ ssh-keygen -t rsa Generating public/private rsa key pair. Enter file in which to save the key (/home/tidb/.ssh/id_rsa): Created directory '/home/tidb/.ssh'. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/tidb/.ssh/id_rsa. Your public key has been saved in /home/tidb/.ssh/id_rsa.pub. The key fingerprint is: 5a:00:e6:df:9e:40:25:2c:2d:e2:6e:ee:74:c6:c3:c1 tidb@t001 The key's randomart image is: +--[ RSA 2048]----+ | oo. . | | .oo.oo | | . ..oo | | .. o o | | . E o S | | oo . = . | | o. * . o | | ..o . | | .. | +-----------------+ -bash-4.2$ cd .ssh -bash-4.2$ cat id_rsa.pub >> authorized_keys -bash-4.2$ chmod 644 authorized_keys -bash-4.2$ ssh-copy-id -i ~/.ssh/id_rsa.pub 192.168.1.100 下载官方 Binary TiDB 官方提供了支持 Linux 版本的二进制安装包,官方推荐使用 Redhat 7+、CentOS 7+ 以上版本的操作系统,不推荐在 Redhat 6、CentOS 6 上部署 TiDB 集群。操作系统:Linux ( Redhat 7+,CentOS 7+ ) 执行步骤:# 下载压缩包 wget http://download.pingcap.org/tidb-latest-linux-amd64.tar.gz wget http://download.pingcap.org/tidb-latest-linux-amd64.sha256 # 检查文件完整性,返回 ok 则正确 sha256sum -c tidb-latest-linux-amd64.sha256 # 解开压缩包 tar -xzf tidb-latest-linux-amd64.tar.gz cd tidb-latest-linux-amd64 单节点方式快速部署 在获取 TiDB 二进制文件包后,我们可以在单机上面,运行和测试 TiDB 集群,请按如下步骤依次启动 PD,TiKV,TiDB。 注意:以下启动各个应用程序组件实例的时候,请选择后台启动,避免前台失效后程序自动退出。 步骤一. 启动 PD:./bin/pd-server --data-dir=pd --log-file=pd.log 步骤二. 启动 TiKV:./bin/tikv-server --pd="127.0.0.1:2379" --data-dir=tikv --log-file=tikv.log 步骤三. 启动 TiDB:./bin/tidb-server --store=tikv --path="127.0.0.1:2379" --log-file=tidb.log 步骤四. 使用 MySQL 客户端连接 TiDB:mysql -h 127.0.0.1 -P 4000 -u root -D test 功能性测试部署 如果只是对 TiDB 进行测试,并且机器数量有限,我们可以只启动一台 PD 测试整个集群。这里我们使用四个节点,部署一个 PD,三个 TiKV,以及一个 TiDB,各个节点以及所运行服务信息如下: Name Host IP Services node1 192.168.199.113 PD1, TiDB node2 192.168.199.114 TiKV1 node3 192.168.199.115 TiKV2 node4 192.168.199.116 TiKV3 请按如下步骤依次启动 PD 集群,TiKV 集群以及 TiDB: 注意:以下启动各个应用程序组件实例的时候,请选择后台启动,避免前台失效后程序自动退出。 步骤一. 在 node1 启动 PD:./bin/pd-server --name=pd1 --data-dir=pd1 --client-urls="http://192.168.199.113:2379" --peer-urls="http://192.168.199.113:2380" --initial-cluster="pd1=http://192.168.199.113:2380" --log-file=pd.log 步骤二. 在 node2,node3,node4 启动 TiKV:./bin/tikv-server --pd="192.168.199.113:2379" --addr="192.168.199.114:20160" --data-dir=tikv1 --log-file=tikv.log ./bin/tikv-server --pd="192.168.199.113:2379" --addr="192.168.199.115:20160" --data-dir=tikv2 --log-file=tikv.log ./bin/tikv-server --pd="192.168.199.113:2379" --addr="192.168.199.116:20160" --data-dir=tikv3 --log-file=tikv.log 步骤三. 在 node1 启动 TiDB:./bin/tidb-server --store=tikv --path="192.168.199.113:2379" --log-file=tidb.log 步骤四. 使用 MySQL 客户端连接 TiDB:mysql -h 192.168.199.113 -P 4000 -u root -D test 多节点集群模式部署 在生产环境中,我们推荐多节点部署 TiDB 集群,首先请参考部署建议。这里我们使用六个节点,部署三个 PD,三个 TiKV,以及一个 TiDB,各个节点以及所运行服务信息如下: Name Host IP Services node1 192.168.199.113 PD1, TiDB node2 192.168.199.114 PD2 node3 192.168.199.115 PD3 node4 192.168.199.116 TiKV1 node5 192.168.199.117 TiKV2 node6 192.168.199.118 TiKV3 请按如下步骤依次启动 PD 集群,TiKV 集群以及 TiDB:步骤一 . 在 node1,node2,node3 依次启动 PD:./bin/pd-server --name=pd1 --data-dir=pd1 --client-urls="http://192.168.199.113:2379" --peer-urls="http://192.168.199.113:2380" --initial-cluster="pd1=http://192.168.199.113:2380,pd2=http://192.168.199.114:2380,pd3=http://192.168.199.115:2380" -L "info" --log-file=pd.log ./bin/pd-server --name=pd2 --data-dir=pd2 --client-urls="http://192.168.199.114:2379" --peer-urls="http://192.168.199.114:2380" --initial-cluster="pd1=http://192.168.199.113:2380,pd2=http://192.168.199.114:2380,pd3=http://192.168.199.115:2380" --join="http://192.168.199.113:2379" -L "info" --log-file=pd.log ./bin/pd-server --name=pd3 --data-dir=pd3 --client-urls="http://192.168.199.115:2379" --peer-urls="http://192.168.199.115:2380" --initial-cluster="pd1=http://192.168.199.113:2380,pd2=http://192.168.199.114:2380,pd3=http://192.168.199.115:2380" --join="http://192.168.199.113:2379" -L "info" --log-file=pd.log 步骤二. 在 node4,node5,node6 启动 TiKV:./bin/tikv-server --pd="192.168.199.113:2379,192.168.199.114:2379,192.168.199.115:2379" --addr="192.168.199.116:20160" --data-dir=tikv1 --log-file=tikv.log ./bin/tikv-server --pd="192.168.199.113:2379,192.168.199.114:2379,192.168.199.115:2379" --addr="192.168.199.117:20160" --data-dir=tikv2 --log-file=tikv.log ./bin/tikv-server --pd="192.168.199.113:2379,192.168.199.114:2379,192.168.199.115:2379" --addr="192.168.199.118:20160" --data-dir=tikv3 --log-file=tikv.log 步骤三. 在 node1 启动 TiDB:./bin/tidb-server --store=tikv --path="192.168.199.113:2379,192.168.199.114:2379,192.168.199.115:2379" --log-file=tidb.log 步骤四. 使用 MySQL 客户端连接 TiDB:mysql -h 192.168.199.113 -P 4000 -u root -D test 注意:在生产环境中启动 TiKV 时,建议使用 --config 参数指定配置文件路径,如果不设置这个参数,TiKV 不会读取配置文件。同样,在生产环境中部署 PD 时,也建议使用 --config 参数指定配置文件路径。 TiKV 调优参见:TiKV 性能参数调优。 注意:如果使用 nohup 在生产环境中启动集群,需要将启动命令放到一个脚本文件里面执行,否则会出现因为 Shell 退出导致 nohup 启动的进程也收到异常信号退出的问题,具体参考进程异常退出。 TiDB 监控和告警环境安装 安装部署监控和告警环境的系统信息如下: Name Host IP Services node1 192.168.199.113 node_export, pushgateway, Prometheus, Grafana node2 192.168.199.114 node_export node3 192.168.199.115 node_export node4 192.168.199.116 node_export 获取二进制包 # 下载压缩包 wget https://github.com/prometheus/prometheus/releases/download/v1.5.2/prometheus-1.5.2.linux-amd64.tar.gz wget https://github.com/prometheus/node_exporter/releases/download/v0.14.0-rc.2/node_exporter-0.14.0-rc.2.linux-amd64.tar.gz wget https://grafanarel.s3.amazonaws.com/builds/grafana-4.1.2-1486989747.linux-x64.tar.gz wget https://github.com/prometheus/pushgateway/releases/download/v0.3.1/pushgateway-0.3.1.linux-amd64.tar.gz # 解开压缩包 tar -xzf …"}, {"url": "https://pingcap.com/tidb-cloud/sign-up/", "title": "TiDB Cloud Sign Up", "content": ""}, {"url": "https://pingcap.com/docs/trouble-shooting/", "title": "TiDB Cluster Troubleshooting Guide", "content": " TiDB Cluster Troubleshooting Guide You can use this guide to help you diagnose and solve basic problems while using TiDB. If your problem is not resolved, please collect the following information and create an issue: The exact error message and the operations while the error occurs The state of all the components The error / fatal / panic information in the log of the component that reports the error The configuration and deployment topology The TiDB component related issue in dmesg For other information, see Frequently Asked Questions (FAQ).Cannot connect to the database Make sure all the services are started, including tidb-server, pd-server, and tikv-server. Use the ps command to check if all the processes are running. If a certain process is not running, see the following corresponding sections to diagnose and solve the issue. If all the processes are running, check the tidb-server log to see if the following messages are displayed: InformationSchema is out of date: This message is displayed if the tikv-server cannot be connected. Check the state and log of pd-server and tikv-server. panic: This message is displayed if there is an issue with the program. Please provide the detailed panic log and create an issue. If the data is cleared and the services are re-deployed, make sure that: All the data in tikv-server and pd-server are cleared. The specific data is stored in tikv-server and the metadata is stored in pd-server. If only one of the two servers is cleared, the data will be inconsistent. After the data in pd-server and tikv-server are cleared and the pd-server and tikv-server are restarted, the tidb-server must be restarted too. The cluster ID is randomly allocated when the pd-server is initialized. So when the cluster is re-deployed, the cluster ID changes and you need to restart the tidb-server to get the new cluster ID. Cannot start tidb-server See the following for the situations when the tidb-server cannot be started: Error in the startup parameters. See the TiDB configuration and options. The port is occupied. Use the lsof -i:port command to show all the networking related to a given port and make sure the port to start the tidb-server is not occupied. Cannot connect to pd-server. Check if the network between TiDB and PD is running smoothly, including whether the network can be pinged or if there is any issue with the Firewall configuration. If there is no issue with the network, check the state and log of the pd-server process. Cannot start tikv-server See the following for the situations when the tikv-server cannot be started: Error in the startup parameters: See the TiKV configuration and options. The port is occupied: Use the lsof -i:port command to show all the networking related to a given port and make sure the port to start the tikv-server is not occupied. Cannot connect to pd-server. Check if the network between TiDB and PD is running smoothly, including whether the network can be pinged or if there is any issue with the Firewall configuration. If there is no issue with the network, check the state and log of the pd-server process. The file is occupied. Do not open two TiKV files on one database file directory. Cannot start pd-server See the following for the situations when the pd-server cannot be started: Error in the startup parameters. See the PD configuration and options. The port is occupied. Use the lsof -i:port command to show all the networking related to a given port and make sure the port to start the pd-server is not occupied. The TiDB/TiKV/PD process aborts unexpectedly Is the process started on the foreground? The process might exit because the client aborts. Is nohup+& run in the command line? This might cause the process to abort because it receives the hup signal. It is recommended to write and run the startup command in a script. TiDB panic Please provide panic log and create an issue.The connection is rejected Make sure the network parameters of the operating system are correct, including but not limited to: The port in the connection string is consistent with the tidb-server starting port. The firewall is configured correctly. Open too many files Before starting the process, make sure the result of ulimit -n is large enough. It is recommended to set the value to unlimited or larger than 1000000.Database access times out and the system load is too high First, check the SLOW-QUERY log and see if it is because of some inappropriate SQL statement. If you failed to solve the problem, provide the following information: The deployment topology How many tidb-server/pd-server/tikv-server instances are deployed? How are these instances distributed in the machines? The hardware configuration of the machines where these instances are deployed: The number of CPU cores The size of the memory The type of the disk (SSD or Hard Drive Disk) Are they physical machines or virtual machines? Are there other services besides the TiDB cluster? Are the pd-servers and tikv-servers deployed separately? What is the current operation? Check the CPU thread name using the top -H command. Are there any exceptions in the network or IO monitoring data recently? "}, {"url": "https://pingcap.com/docs/v1.0/trouble-shooting/", "title": "TiDB Cluster Troubleshooting Guide", "content": " TiDB Cluster Troubleshooting Guide You can use this guide to help you diagnose and solve basic problems while using TiDB. If your problem is not resolved, please collect the following information and create an issue: The exact error message and the operations while the error occurs The state of all the components The error / fatal / panic information in the log of the component that reports the error The configuration and deployment topology The TiDB component related issue in dmesg For other information, see Frequently Asked Questions (FAQ).Cannot connect to the database Make sure all the services are started, including tidb-server, pd-server, and tikv-server. Use the ps command to check if all the processes are running. If a certain process is not running, see the following corresponding sections to diagnose and solve the issue. If all the processes are running, check the tidb-server log to see if the following messages are displayed: InfomationSchema is out of date: This message is displayed if the tikv-server cannot be connected. Check the state and log of pd-server and tikv-server. panic: This message is displayed if there is an issue with the program. Please provide the detailed panic log and create an issue. If the data is cleared and the services are re-deployed, make sure that: All the data in tikv-server and pd-server are cleared. The specific data is stored in tikv-server and the metadata is stored in pd-server. If only one of the two servers is cleared, the data will be inconsistent. After the data in pd-server and tikv-server are cleared and the pd-server and tikv-server are restarted, the tidb-server must be restarted too. The cluster ID is randomly allocated when the pd-server is initialized. So when the cluster is re-deployed, the cluster ID changes and you need to restart the tidb-server to get the new cluster ID. Cannot start tidb-server See the following for the situations when the tidb-server cannot be started: Error in the startup parameters. See the TiDB configuration and options. The port is occupied. Use the lsof -i:port command to show all the networking related to a given port and make sure the port to start the tidb-server is not occupied. Cannot connect to pd-server. Check if the network between TiDB and PD is running smoothly, including whether the network can be pinged or if there is any issue with the Firewall configuration. If there is no issue with the network, check the state and log of the pd-server process. Cannot start tikv-server See the following for the situations when the tikv-server cannot be started: Error in the startup parameters: See the TiKV configuration and options. The port is occupied: Use the lsof -i:port command to show all the networking related to a given port and make sure the port to start the tikv-server is not occupied. Cannot connect to pd-server. Check if the network between TiDB and PD is running smoothly, including whether the network can be pinged or if there is any issue with the Firewall configuration. If there is no issue with the network, check the state and log of the pd-server process. The file is occupied. Do not open two TiKV files on one database file directory. Cannot start pd-server See the following for the situations when the pd-server cannot be started: Error in the startup parameters. See the PD configuration and options. The port is occupied. Use the lsof -i:port command to show all the networking related to a given port and make sure the port to start the pd-server is not occupied. The TiDB/TiKV/PD process aborts unexpectedly Is the process started on the foreground? The process might exit because the client aborts. Is nohup+& run in the command line? This might cause the process to abort because it receives the hup signal. It is recommended to write and run the startup command in a script. TiDB panic Please provide panic log and create an issue.The connection is rejected Make sure the network parameters of the operating system are correct, including but not limited to: The port in the connection string is consistent with the tidb-server starting port. The firewall is configured correctly. Open too many files Before starting the process, make sure the result of ulimit -n is large enough. It is recommended to set the value to unlimited or larger than 1000000.Database access times out and the system load is too high Provide the following information: The deployment topology How many tidb-server/pd-server/tikv-server instances are deployed? How are these instances distributed in the machines? The hardware configuration of the machines where these instances are deployed: The number of CPU cores The size of the memory The type of the disk (SSD or Hard Drive Disk) Are they physical machines or virtual machines? Are there other services besides the TiDB cluster? Are the pd-servers and tikv-servers deployed separately? What is the current operation? Check the CPU thread name using the top -H command. Are there any exceptions in the network or IO monitoring data recently? "}, {"url": "https://pingcap.com/docs/v2.0/trouble-shooting/", "title": "TiDB Cluster Troubleshooting Guide", "content": " TiDB Cluster Troubleshooting Guide You can use this guide to help you diagnose and solve basic problems while using TiDB. If your problem is not resolved, please collect the following information and create an issue: The exact error message and the operations while the error occurs The state of all the components The error / fatal / panic information in the log of the component that reports the error The configuration and deployment topology The TiDB component related issue in dmesg For other information, see Frequently Asked Questions (FAQ).Cannot connect to the database Make sure all the services are started, including tidb-server, pd-server, and tikv-server. Use the ps command to check if all the processes are running. If a certain process is not running, see the following corresponding sections to diagnose and solve the issue. If all the processes are running, check the tidb-server log to see if the following messages are displayed: InfomationSchema is out of date: This message is displayed if the tikv-server cannot be connected. Check the state and log of pd-server and tikv-server. panic: This message is displayed if there is an issue with the program. Please provide the detailed panic log and create an issue. If the data is cleared and the services are re-deployed, make sure that: All the data in tikv-server and pd-server are cleared. The specific data is stored in tikv-server and the metadata is stored in pd-server. If only one of the two servers is cleared, the data will be inconsistent. After the data in pd-server and tikv-server are cleared and the pd-server and tikv-server are restarted, the tidb-server must be restarted too. The cluster ID is randomly allocated when the pd-server is initialized. So when the cluster is re-deployed, the cluster ID changes and you need to restart the tidb-server to get the new cluster ID. Cannot start tidb-server See the following for the situations when the tidb-server cannot be started: Error in the startup parameters. See the TiDB configuration and options. The port is occupied. Use the lsof -i:port command to show all the networking related to a given port and make sure the port to start the tidb-server is not occupied. Cannot connect to pd-server. Check if the network between TiDB and PD is running smoothly, including whether the network can be pinged or if there is any issue with the Firewall configuration. If there is no issue with the network, check the state and log of the pd-server process. Cannot start tikv-server See the following for the situations when the tikv-server cannot be started: Error in the startup parameters: See the TiKV configuration and options. The port is occupied: Use the lsof -i:port command to show all the networking related to a given port and make sure the port to start the tikv-server is not occupied. Cannot connect to pd-server. Check if the network between TiDB and PD is running smoothly, including whether the network can be pinged or if there is any issue with the Firewall configuration. If there is no issue with the network, check the state and log of the pd-server process. The file is occupied. Do not open two TiKV files on one database file directory. Cannot start pd-server See the following for the situations when the pd-server cannot be started: Error in the startup parameters. See the PD configuration and options. The port is occupied. Use the lsof -i:port command to show all the networking related to a given port and make sure the port to start the pd-server is not occupied. The TiDB/TiKV/PD process aborts unexpectedly Is the process started on the foreground? The process might exit because the client aborts. Is nohup+& run in the command line? This might cause the process to abort because it receives the hup signal. It is recommended to write and run the startup command in a script. TiDB panic Please provide panic log and create an issue.The connection is rejected Make sure the network parameters of the operating system are correct, including but not limited to: The port in the connection string is consistent with the tidb-server starting port. The firewall is configured correctly. Open too many files Before starting the process, make sure the result of ulimit -n is large enough. It is recommended to set the value to unlimited or larger than 1000000.Database access times out and the system load is too high First, check the SLOW-QUERY log and see if it is because of some inappropriate SQL statement. If you failed to solve the problem, provide the following information: The deployment topology How many tidb-server/pd-server/tikv-server instances are deployed? How are these instances distributed in the machines? The hardware configuration of the machines where these instances are deployed: The number of CPU cores The size of the memory The type of the disk (SSD or Hard Drive Disk) Are they physical machines or virtual machines? Are there other services besides the TiDB cluster? Are the pd-servers and tikv-servers deployed separately? What is the current operation? Check the CPU thread name using the top -H command. Are there any exceptions in the network or IO monitoring data recently? "}, {"url": "https://pingcap.com/docs/op-guide/tidb-config-file/", "title": "TiDB Configuration File Description", "content": " TiDB Configuration File Description The TiDB configuration file supports more options than command line options. You can find the default configuration file in config/config.toml.example and rename it to config.toml.This document describes the options that are not involved in command line options. For command line options, see here.split-table To create a separate Region for each table Default: true It is recommended to set it to false if you need to create a large number of tables oom-action To specify the operation when out-of-memory occurs in TiDB Default: “log” The valid options are “log” and “cancel”; “log” only prints the log, without actual processing; “cancel” cancels the operation and outputs the log enable-streaming To enable the data fetch mode of streaming in Coprocessor Default: false lower-case-table-names To configure the value of the lower_case_table_names system variable Default: 2 For details, you can see the MySQL description of this variable Currently, TiDB only supports setting the value of this option to 2. This means it is case-sensitive when you save a table name, but case-insensitive when you compare table names. The comparison is based on the lower case. compatible-kill-query To set the “kill” statement to be MySQL compatible Default: false In TiDB, the behavior of “kill xxx” is not compatible with MySQL. A query is killed only when you are executing “kill tidb xxx”. If compatible-kill-query is set to true, the “kill xxx” is compatible with MySQL, so no additional “tidb” is needed. Log Configuration about log.format To specify the log output format The valid options are “json”, “text” and “console” Default: “text” disable-timestamp Whether to disable outputting timestamp in the log Default: false If you set the value to true, the log does not output timestamp slow-query-file The file name of the slow query log Default: “” After you set it, the slow query log is output to this file separately slow-threshold To output the threshold value of consumed time in the slow log Default: 300ms If the value in a query is larger than the default value, it is a slow query and is output to the slow log expensive-threshold To output the threshold value of the number of rows for the expensive operation Default: 10000 When the number of query rows (including the intermediate results based on statistics) is larger than this value, it is an expensive operation and outputs log with the [EXPENSIVE_QUERY] prefix. query-log-max-len The maximum length of SQL output Default: 2048 When the length of the statement is longer than query-log-max-len, the statement is truncated to output log.file filename The file name of the general log file Default: “” If you set it, the log is output to this file max-size The size limit of the log file Default: 300MB The maximum size is 4GB max-days The maximum number of days that the log is retained Default: 0 The log is retained by default; if you set the value, the expired log is cleaned up after max-days max-backups The maximum number of retained logs Default: 0 All the log files are retained by default; if you set it to 7, 7 log files are retained at maximum log-rotate Whether to create a new log file every day Default: true If you set it to true, a new log file is created every day; if you set it to false, the log is output to a single log file Security Configuration about security.ssl-ca The file path of the trusted CA certificate in the PEM format Default: “” If you set this option and --ssl-cert, --ssl-key at the same time, TiDB authenticates the client certificate based on the list of trusted CAs specified by this option when the client presents the certificate. If the authentication fails, the connection is terminated. If you set this option but the client does not present the certificate, the secure connection continues without client certificate authentication. ssl-cert The file path of the SSL certificate in the PEM format Default: “” If you set this option and --ssl-key at the same time, TiDB allows (but not forces) the client to securely connect to TiDB using TLS If the specified certificate or private key is invalid, TiDB starts as usual but cannot receive secure connection ssl-key The file path of the SSL certificate key in the PEM format, that is the private key of the certificate specified by --ssl-cert Default: “” Currently, TiDB does not support loading the private keys protected by passwords Performance Configuration about performance.max-procs The number of CPUs used by TiDB Default: 0 The default “0” indicates using all CPUs in the machine; you can also set it to max-procs, and then TiDB uses max-procs CPUs stmt-count-limit The maximum number of statements allowed in a single TiDB transaction Default: 5000 If a transaction does not roll back or commit after the number of statements exceeds stmt-count-limit, TiDB returns the statement count 5001 exceeds the transaction limitation, autocommit = false error tcp-keep-alive To enable keepalive in the TCP layer Default: false retry-limit The number of retries that TiDB makes when it encounters a key conflict or other errors while committing a transaction Default: 10 If the number of retries exceeds retry-limit but the transaction still fails, TiDB returns an error cross-join Default: true TiDB supports executing the join statement without any condition (the where field) of both sides tables by default; if you set the value to false, the server refuses to execute when such a join statement appears stats-lease The time interval between analyzing TiDB statistics and reloading statistics Default: 3s At intervals of stats-lease time, TiDB checks the statistics for updates and updates them to the memory if updates exist At intervals of 5 * stats-lease time, TiDB persists the total number of rows generated by DML and the number of modified rows At intervals of stats-lease, TiDB checks for tables and indexes that need to be automatically analyzed At intervals of stats-lease, TiDB checks for column statistics that need to be loaded to the memory run-auto-analyze Whether TiDB executes automatic analysis Default: true feedback-probability The probability that TiDB collects the feedback statistics of each query Default: 0 TiDB collects the feedback of each query at the probability of feedback-probability, to update statistics prepared-plan-cache The Plan Cache configuration of the prepare statement.enabled To enable Plan Cache of the prepare statement Default: false capacity The number of cached statements Default: 100 tikv-client grpc-connection-count The maximum number of connections established with each TiKV Default: 16 commit-timeout The maximum timeout time when executing a transaction commit Default: 41s It is required to set this value larger than twice of the Raft election timeout time txn-local-latches Configuration about the transaction latch. It is recommended to enable it when many local transaction conflicts occur.enable To enable Default: false capacity The number of slots corresponding to Hash, which automatically adjusts upward to an exponential multiple of 2. Each slot occupies 32 Bytes of memory. If set too small, it might result in slower running speed and poor performance in the scenario where data writing covers a relatively large range (such as importing data). Default: 1024000 "}, {"url": "https://pingcap.com/docs/v2.0/op-guide/tidb-config-file/", "title": "TiDB Configuration File Description", "content": " TiDB Configuration File Description The TiDB configuration file supports more options than command line options. You can find the default configuration file in config/config.toml.example and rename it to config.toml.This document describes the options that are not involved in command line options. For command line options, see here.split-table To create a separate Region for each table Default: true It is recommended to set it to false if you need to create a large number of tables oom-action To specify the operation when out-of-memory occurs in TiDB Default: “log” The valid options are “log” and “cancel”; “log” only prints the log, without actual processing; “cancel” cancels the operation and outputs the log enable-streaming To enable the data fetch mode of streaming in Coprocessor Default: false lower-case-table-names To configure the value of the lower_case_table_names system variable Default: 2 For details, you can see the MySQL description of this variable Currently, TiDB only supports setting the value of this option to 2. This means it is case-sensitive when you save a table name, but case-insensitive when you compare table names. The comparison is based on the lower case. Log Configuration about log.format To specify the log output format The valid options are “json”, “text” and “console” Default: “text” disable-timestamp Whether to disable outputting timestamp in the log Default: false If you set the value to true, the log does not output timestamp slow-query-file The file name of the slow query log Default: “” After you set it, the slow query log is output to this file separately slow-threshold To output the threshold value of consumed time in the slow log Default: 300ms If the value in a query is larger than the default value, it is a slow query and is output to the slow log expensive-threshold To output the threshold value of the number of rows for the expensive operation Default: 10000 When the number of query rows (including the intermediate results based on statistics) is larger than this value, it is an expensive operation and outputs log with the [EXPENSIVE_QUERY] prefix. query-log-max-len The maximum length of SQL output Default: 2048 When the length of the statement is longer than query-log-max-len, the statement is truncated to output log.file filename The file name of the general log file Default: “” If you set it, the log is output to this file max-size The size limit of the log file Default: 300MB The maximum size is 4GB max-days The maximum number of days that the log is retained Default: 0 The log is retained by default; if you set the value, the expired log is cleaned up after max-days max-backups The maximum number of retained logs Default: 0 All the log files are retained by default; if you set it to 7, 7 log files are retained at maximum log-rotate Whether to create a new log file every day Default: true If you set it to true, a new log file is created every day; if you set it to false, the log is output to a single log file Security Configuration about security.ssl-ca The file path of the trusted CA certificate in the PEM format Default: “” If you set this option and --ssl-cert, --ssl-key at the same time, TiDB authenticates the client certificate based on the list of trusted CAs specified by this option when the client presents the certificate. If the authentication fails, the connection is terminated. If you set this option but the client does not present the certificate, the secure connection continues without client certificate authentication. ssl-cert The file path of the SSL certificate in the PEM format Default: “” If you set this option and --ssl-key at the same time, TiDB allows (but not forces) the client to securely connect to TiDB using TLS If the specified certificate or private key is invalid, TiDB starts as usual but cannot receive secure connection ssl-key The file path of the SSL certificate key in the PEM format, that is the private key of the certificate specified by --ssl-cert Default: “” Currently, TiDB does not support loading the private keys protected by passwords Performance Configuration about performance.max-procs The number of CPUs used by TiDB Default: 0 The default “0” indicates using all CPUs in the machine; you can also set it to max-procs, and then TiDB uses max-procs CPUs stmt-count-limit The maximum number of statements allowed in a single TiDB transaction Default: 5000 If a transaction does not roll back or commit after the number of statements exceeds stmt-count-limit, TiDB returns the statement count 5001 exceeds the transaction limitation, autocommit = false error tcp-keep-alive To enable keepalive in the TCP layer Default: false retry-limit The number of retries that TiDB makes when it encounters a key conflict or other errors while committing a transaction Default: 10 If the number of retries exceeds retry-limit but the transaction still fails, TiDB returns an error cross-join Default: true TiDB supports executing the join statement without any condition (the where field) of both sides tables by default; if you set the value to false, the server refuses to execute when such a join statement appears stats-lease The time interval between analyzing TiDB statistics and reloading statistics Default: 3s At intervals of stats-lease time, TiDB checks the statistics for updates and updates them to the memory if updates exist At intervals of 5 * stats-lease time, TiDB persists the total number of rows generated by DML and the number of modified rows At intervals of stats-lease, TiDB checks for tables and indexes that need to be automatically analyzed At intervals of stats-lease, TiDB checks for column statistics that need to be loaded to the memory run-auto-analyze Whether TiDB executes automatic analysis Default: true feedback-probability The probability that TiDB collects the feedback statistics of each query Default: 0 TiDB collects the feedback of each query at the probability of feedback-probability, to update statistics prepared-plan-cache The Plan Cache configuration of the prepare statement.enabled To enable Plan Cache of the prepare statement Default: false capacity The number of cached statements Default: 100 tikv-client grpc-connection-count The maximum number of connections established with each TiKV Default: 16 commit-timeout The maximum timeout time when executing a transaction commit Default: 41s It is required to set this value larger than twice of the Raft election timeout time txn-local-latches Configuration about the transaction latch. It is recommended to enable it when many local transaction conflicts occur.enable To enable Default: false capacity The number of slots corresponding to Hash, which automatically adjusts upward to an exponential multiple of 2. Each slot occupies 32 Bytes of memory. If set too small, it might result in slower running speed and poor performance in the scenario where data writing covers a relatively large range (such as importing data). Default: 1024000 "}, {"url": "https://pingcap.com/docs/v1.0/tispark/tispark-user-guide/", "title": "TiDB Connector for Spark User Guide", "content": " TiDB Connector for Spark User Guide The TiDB Connector for Spark is a thin layer built for running Apache Spark on top of TiDB/TiKV to answer the complex OLAP queries. It takes advantages of both the Spark platform and the distributed TiKV cluster and seamlessly glues to TiDB, the distributed OLTP database, to provide a Hybrid Transactional/Analytical Processing (HTAP) solution to serve as a one-stop solution for both online transactions and analysis.The TiDB Connector for Spark depends on the TiKV cluster and the PD cluster. You also need to set up a Spark cluster. This document provides a brief introduction to how to setup and use the TiDB Connector for Spark. It requires some basic knowledge of Apache Spark. For more information, see Spark website.Overview The TiDB Connector for Spark is an OLAP solution that runs Spark SQL directly on TiKV, the distributed storage engine. TiDB Connector for Spark integrates with Spark Catalyst Engine deeply. It provides precise control of the computing, which allows Spark read data from TiKV efficiently. It also supports index seek, which improves the performance of the point query execution significantly. It utilizes several strategies to push down the computing to reduce the size of dataset handling by Spark SQL, which accelerates the query execution. It also uses the TiDB built-in statistical information for the query plan optimization. From the data integration point of view, TiDB Connector for Spark and TiDB serve as a solution runs both transaction and analysis directly on the same platform without building and maintaining any ETLs. It simplifies the system architecture and reduces the cost of maintenance. also, you can deploy and utilize tools from the Spark ecosystem for further data processing and manipulation on TiDB. For example, using the TiDB Connector for Spark for data analysis and ETL; retrieving data from TiKV as a machine learning data source; generating reports from the scheduling system and so on. Environment setup The current version of the TiDB Connector for Spark supports Spark 2.1. For Spark 2.0 and Spark 2.2, it has not been fully tested yet. It does not support any versions earlier than 2.0. The TiDB Connector for Spark requires JDK 1.8+ and Scala 2.11 (Spark2.0 + default Scala version). The TiDB Connector for Spark runs in any Spark mode such as YARN, Mesos, and Standalone. Recommended configuration Deployment of TiKV and the TiDB Connector for Spark clusters Configuration of the TiKV cluster For independent deployment of TiKV and the TiDB Connector for Spark, it is recommended to refer to the following recommendations Hardware configuration For general purposes, please refer to the TiDB and TiKV hardware configuration recommendations. If the usage is more focused on the analysis scenarios, you can increase the memory of the TiKV nodes to at least 64G. TiKV parameters (default)[server] end-point-concurrency = 8 # For OLAP scenarios, consider increasing this parameter [raftstore] sync-log = false [rocksdb] max-background-compactions = 6 max-background-flushes = 2 [rocksdb.defaultcf] block-cache-size = "10GB" [rocksdb.writecf] block-cache-size = "4GB" [rocksdb.raftcf] block-cache-size = "1GB" [rocksdb.lockcf] block-cache-size = "1GB" [storage] scheduler-worker-pool-size = 4 Configuration of the independent deployment of the Spark cluster and the TiDB Connector for Spark cluster See the Spark official website for the detail hardware recommendations.The following is a short overview of the TiDB Connector for Spark configuration.It is recommended to allocate 32G memory for Spark. Please reserve at least 25% of the memory for the operating system and buffer cache.It is recommended to provision at least 8 to 16 cores on per machine for Spark. Initially, you can assign all the CPU cores to Spark.See the official configuration on the Spark website. The following is an example based on the spark-env.sh configuration:SPARK_EXECUTOR_MEMORY = 32g SPARK_WORKER_MEMORY = 32g SPARK_WORKER_CORES = 8 Hybrid deployment configuration for the TiDB Connector for Spark and TiKV cluster For the hybrid deployment of the TiDB Connector for Spark and TiKV, add the TiDB Connector for Spark required resources to the TiKV reserved resources, and allocate 25% of the memory for the system.Deploy the TiDB Connector for Spark Download the TiDB Connector for Spark’s jar package here.Deploy the TiDB Connector for Spark on the existing Spark cluster Running TiDB Connector for Spark on an existing Spark cluster does not require a reboot of the cluster. You can use Spark’s --jars parameter to introduce the TiDB Connector for Spark as a dependency:spark-shell --jars $PATH/tispark-0.1.0.jar If you want to deploy TiDB Connector for Spark as a default component, simply place the TiDB Connector for Spark jar package into the jars path for each node of the Spark cluster and restart the Spark cluster:${SPARK_INSTALL_PATH}/jars In this way, you can use either Spark-Submit or Spark-Shell to use the TiDB Connector for Spark directly.Deploy TiDB Connector for Spark without the Spark cluster If you do not have a Spark cluster, we recommend using the standalone mode. To use the Spark Standalone model, you can simply place a compiled version of Spark on each node of the cluster. If you encounter problems, see its official website. And you are welcome to file an issue on our GitHub.Download and install You can download Apache SparkFor the Standalone mode without Hadoop support, use Spark 2.1.x and any version of Pre-build with Apache Hadoop 2.x with Hadoop dependencies. If you need to use the Hadoop cluster, please choose the corresponding Hadoop version. You can also choose to build from the source code to match the previous version of the official Hadoop 2.6. Please note that the TiDB Connector for Spark currently only supports Spark 2.1.x version.Suppose you already have a Spark binaries, and the current PATH is SPARKPATH, please copy the TiDB Connector for Spark jar package to the ${SPARKPATH}/jars directory.Start a Master node Execute the following command on the selected Spark Master node:cd $SPARKPATH ./sbin/start-master.sh After the above step is completed, a log file will be printed on the screen. Check the log file to confirm whether the Spark-Master is started successfully. You can open the http://spark-master-hostname:8080 to view the cluster information (if you does not change the Spark-Master default port number). When you start Spark-Slave, you can also use this panel to confirm whether the Slave is joined to the cluster.Start a Slave node Similarly, you can start a Spark-Slave node with the following command:./sbin/start-slave.sh spark://spark-master-hostname:7077 After the command returns, you can see if the Slave node is joined to the Spark cluster correctly from the panel as well. Repeat the above command at all Slave nodes. After all Slaves are connected to the master, you have a Standalone mode Spark cluster.Spark SQL shell and JDBC server If you want to use JDBC server and interactive SQL shell, please copy start-tithriftserver.sh stop-tithriftserver.sh to your Spark’s sbin folder and tispark-sql to the bin folder.To start interactive shell:./bin/tispark-sql To use Thrift Server, you can start it similar way as default Spark Thrift Server:./sbin/start-tithriftserver.sh And stop it like below:./sbin/stop-tithriftserver.sh Demo Assuming that you have successfully started the TiDB Connector for Spark cluster as described above, here’s a quick introduction to how to use Spark SQL for OLAP analysis. Here we use a table named lineitem in the tpch database as an example.Assuming that your PD node is located at 192.168.1.100, port 2379, add the following command to $SPARK_HOME/conf/spark-defaults.conf:spark.tispark.pd.addresses 192.168.1.100:2379 And then enter the following command in the Spark-Shell:import org.apache.spark.sql.TiContext val ti = new …"}, {"url": "https://pingcap.com/docs/tools/tidb-controller/", "title": "TiDB Controller User Guide", "content": " TiDB Controller User Guide TiDB Controller is a command line tool of TiDB, usually used to obtain the status information of TiDB for debugging.Compile from source code Compilation environment requirement: Go Version 1.7 or later Compilation procedures: Go to the root directory of the TiDB Controller project, use the make command to compile, and generate tidb-ctl. Compilation documentation: you can find the help files in the doc directory; if the help files are lost or you want to update them, use the make doc command to generate the help files. Usage introduction The usage of tidb-ctl consists of command (including subcommand), option, and flag. command: characters without - or -- option: characters with - or -- flag: characters exactly following the command or option, passing value to the command or option Usage example: tidb-ctl schema in mysql -n db schema: the command in: the subcommand of schema mysql: the flag of in -n: the option db: the flag of -n Get help Use tidb-ctl -h/--help to get the help information. tidb-ctl consists of multiple layers of commands. You can use -h/--help to get the help information of tidb-ctl and all other subcommands.Connect tidb-ctl -H/--host {TiDB service address} -P/--port {TiDB service port} If you do not add an address or a port, the default value is used. The default address is 127.0.0.1 (service address must be the IP address); the default port is 10080. Connection options are top-level options and apply to all of the following commands.Currently, TiDB Controller can obtain four categories of information using the following four commands: tidb-ctl mvcc: MVCC information tidb-ctl region: Region information tidb-ctl schema: Schema information tidb-ctl table: Table information Examples The following example shows how to obtain the schema information:Use tidb-ctl schema -h to get the help information of the subcommands. schema has two subcommands: in and tid. in is used to obtain the table schema of all tables in the database through the database name. tid is used to obtain the table schema through the unique table_id in the whole database. The in command You can also use tidb-ctl schema in -h/--help to get the help information of the in subcommand.Basic usage tidb-ctl schema in {database name} For example, tidb-ctl schema in mysql returns the following result:[ { "id": 13, "name": { "O": "columns_priv", "L": "columns_priv" }, ... "update_timestamp": 399494726837600268, "ShardRowIDBits": 0, "Partition": null } ] The result is long and displayed in JSON. The above result is a truncated one. If you want to specify the table name, use tidb-ctl schema in {database} -n {table name} to filter.For example, tidb-ctl schema in mysql -n db returns the table schema of the db table in the mysql database:{ "id": 9, "name": { "O": "db", "L": "db" }, ... "Partition": null } The above result is a truncated one, too. If you want to specify the server address, use the -H -P option.For example, tidb-ctl -H 127.0.0.1 -P 10080 schema in mysql -n db. "}, {"url": "https://pingcap.com/docs/v2.0/tools/tidb-controller/", "title": "TiDB Controller User Guide", "content": " TiDB Controller User Guide TiDB Controller is a command line tool of TiDB, usually used to obtain the status information of TiDB for debugging.Compile from source code Compilation environment requirement: Go Version 1.7 or later Compilation procedures: Go to the root directory of the TiDB Controller project, use the make command to compile, and generate tidb-ctl. Compilation documentation: you can find the help files in the doc directory; if the help files are lost or you want to update them, use the make doc command to generate the help files. Usage introduction The usage of tidb-ctl consists of command (including subcommand), option, and flag. command: characters without - or -- option: characters with - or -- flag: characters exactly following the command or option, passing value to the command or option Usage example: tidb-ctl schema in mysql -n db schema: the command in: the subcommand of schema mysql: the flag of in -n: the option db: the flag of -n Get help Use tidb-ctl -h/--help to get the help information. tidb-ctl consists of multiple layers of commands. You can use -h/--help to get the help information of tidb-ctl and all other subcommands.Connect tidb-ctl -H/--host {TiDB service address} -P/--port {TiDB service port} If you do not add an address or a port, the default value is used. The default address is 127.0.0.1 (service address must be the IP address); the default port is 10080. Connection options are top-level options and apply to all of the following commands.Currently, TiDB Controller can obtain four categories of information using the following four commands: tidb-ctl mvcc: MVCC information tidb-ctl region: Region information tidb-ctl schema: Schema information tidb-ctl table: Table information Examples The following example shows how to obtain the schema information:Use tidb-ctl schema -h to get the help information of the subcommands. schema has two subcommands: in and tid. in is used to obtain the table schema of all tables in the database through the database name. tid is used to obtain the table schema through the unique table_id in the whole database. The in command You can also use tidb-ctl schema in -h/--help to get the help information of the in subcommand.Basic usage tidb-ctl schema in {database name} For example, tidb-ctl schema in mysql returns the following result:[ { "id": 13, "name": { "O": "columns_priv", "L": "columns_priv" }, ... "update_timestamp": 399494726837600268, "ShardRowIDBits": 0, "Partition": null } ] The result is long and displayed in JSON. The above result is a truncated one. If you want to specify the table name, use tidb-ctl schema in {database} -n {table name} to filter.For example, tidb-ctl schema in mysql -n db returns the table schema of the db table in the mysql database:{ "id": 9, "name": { "O": "db", "L": "db" }, ... "Partition": null } The above result is a truncated one, too. If you want to specify the server address, use the -H -P option.For example, tidb-ctl -H 127.0.0.1 -P 10080 schema in mysql -n db. "}, {"url": "https://pingcap.com/docs-cn/tools/tidb-controller/", "title": "TiDB Controller 使用说明", "content": " TiDB Controller 使用说明 TiDB Controller 是 TiDB 的命令行工具,用于获取 TiDB 状态信息,多用于调试。源码编译 编译环境要求:Go Version 1.7 以上编译步骤:在 TiDB Controller 项目根目录,使用 make 命令进行编译,生成 tidb-ctl。编译文档:帮助文档在 doc 文件夹下,如丢失或需要更新,可通过 make doc 命令生成帮助文档。使用介绍 tidb-ctl 的使用由命令(包括子命令)、选项和参数组成。命令即不带 - 或者 -- 的字符,选项即带有 - 或者 -- 的字符,参数即命令或选项字符后紧跟的传递给命令和选项的字符。如:tidb-ctl schema in mysql -n db schema: 命令 in: schema 的子命令 mysql: in 的参数 -n: 选项 db: -n 的参数 获取帮助 tidb-ctl -h/--help 用于获取帮助信息。tidb-ctl 由多层命令组成,tidb-ctl 及其所有子命令都可以通过 -h/--help 来获取使用帮助。连接 tidb-ctl -H/--host { TiDB 服务地址} -P/--port { TiDB 服务端口}如不添加地址和端口将使用默认值,默认的地址是 127.0.0.1 (服务地址只能使用 IP 地址),默认的端口是 10080。连接选项是顶级选项,适用于以下所有命令。目前,TiDB Controller 可以获取四类信息,分别通过以下四个命令获得: tidb-ctl mvcc - MVCC 信息 tidb-ctl region - Region 信息 tidb-ctl schema - Schema 信息 tidb-ctl table - Table 信息 使用举例 以获取 Schema 信息为例:通过 tidb-ctl schema -h 可以获取这个子命令的使用帮助。schema 有两个子命令,in 和 tid。in 用来通过数据库名获取数据库中所有表的表结构,tid 用来通过全数据库唯一的 table_id 获取表的表结构。in 命令 同样可以通过 tidb-ctl schema in -h/--help 来获取子命令 in 的使用帮助。基本用法 tidb-ctl schema in {数据库名}如:tidb-ctl schema in mysql 将得到以下结果:[ { "id": 13, "name": { "O": "columns_priv", "L": "columns_priv" }, ... "update_timestamp": 399494726837600268, "ShardRowIDBits": 0, "Partition": null } ] 结果将以 json 形式展示,内容较长,这里做了截断。如希望指定表名,可以使用 tidb-ctl schema in {数据库名} -n {表名} 进行过滤。如:tidb-ctl schema in mysql -n db 将得到 mysql 库中 db 表的表结构,结果如下:{ "id": 9, "name": { "O": "db", "L": "db" }, ... "Partition": null } 这里同样做了截断。如希望指定服务地址,可以使用 -H -P 选项,如:tidb-ctl -H 127.0.0.1 -P 10080 schema in mysql -n db。"}, {"url": "https://pingcap.com/docs/sql/dml/", "title": "TiDB Data Manipulation Language", "content": " TiDB Data Manipulation Language Data manipulation language (DML) is a family of syntax elements used for selecting, inserting, deleting and updating data in a database.SELECT SELECT is used to retrieve rows selected from one or more tables.Syntax SELECT [ALL | DISTINCT | DISTINCTROW ] [HIGH_PRIORITY] [STRAIGHT_JOIN] [SQL_CACHE | SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS] select_expr [, select_expr ...] [FROM table_references [WHERE where_condition] [GROUP BY {col_name | expr | position} [ASC | DESC], ...] [HAVING where_condition] [ORDER BY {col_name | expr | position} [ASC | DESC], ...] [LIMIT {[offset,] row_count | row_count OFFSET offset}] [FOR UPDATE | LOCK IN SHARE MODE]] Description of the syntax elements Syntax Element Description ALL, DISTINCT, DISTINCTROW The ALL, DISTINCT/DISTINCTROW modifiers specify whether duplicate rows should be returned. ALL (the default) specifies that all matching rows should be returned. HIGH_PRIORITY HIGH_PRIORITY gives the current statement higher priority than other statements. SQL_CACHE, SQL_NO_CACHE, SQL_CALC_FOUND_ROWS To guarantee compatibility with MySQL, TiDB parses these three modifiers, but will ignore them. STRAIGHT_JOIN STRAIGHT_JOIN forces the optimizer to execute a Join query in the order of the tables used in the FROM clause. You can use this syntax to speed up queries execution when the Join order chosen by the optimizer is not good. select_expr Each select_expr indicates a column to retrieve. including the column names and expressions. * represents all the columns. |FROM table_references The FROM table_references clause indicates the table (such as (select * from t;)), or tables (such as select * from t1 join t2;)) or even 0 tables (such as select 1+1 from dual; (which is equivalent to `select 1+1;‘)) from which to retrieve rows. WHERE where_condition The WHERE clause, if given, indicates the condition or conditions that rows must satisfy to be selected. The result contains only the data that meets the condition(s). GROUP BY The GROUP BY statement is used to group the result-set. HAVING where_condition The HAVING clause and the WHERE clause are both used to filter the results. The HAVING clause filters the results of GROUP BY, while the WHERE clause filter the results before aggregation ORDER BY The ORDER BY clause is used to sort the data in ascending or descending order, based on columns, expressions or items in the select_expr list. LIMIT The LIMIT clause can be used to constrain the number of rows. LIMIT takes one or two numeric arguments. With one argument, the argument specifies the maximum number of rows to return, the first row to return is the first row of the table by default; with two arguments, the first argument specifies the offset of the first row to return, and the second specifies the maximum number of rows to return. FOR UPDATE All the data in the result sets are read-locked, in order to detect the concurrent updates. TiDB uses the Optimistic Transaction Model. The transaction conflicts are detected in the commit phase instead of statement execution phase. while executing the SELECT FOR UPDATE statement, if there are other transactions trying to update relevant data, the SELECT FOR UPDATE transaction will fail. LOCK IN SHARE MODE To guarantee compatibility, TiDB parses these three modifiers, but will ignore them. INSERT INSERT inserts new rows into an existing table. TiDB is compatible with all the INSERT syntaxes of MySQL.Syntax Insert Statement: INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE] [INTO] tbl_name insert_values [ON DUPLICATE KEY UPDATE assignment_list] insert_values: [(col_name [, col_name] ...)] {VALUES | VALUE} (expr_list) [, (expr_list)] ... | SET assignment_list | [(col_name [, col_name] ...)] SELECT ... expr_list: expr [, expr] ... assignment: col_name = expr assignment_list: assignment [, assignment] ... Description of the syntax elements Syntax Elements Description LOW_PRIORITY LOW_PRIORITY gives the statement lower priority. TiDB lowers the priority of the current statement. DELAYED To guarantee compatibility, TiDB parses this modifier, but will ignore it. HIGH_PRIORITY HIGH_PRIORITY gives the current statement higher priority than other statements. TiDB raises the priority of the current statement. IGNORE If IGNORE modifier is specified and there is a duplicate key error, the data cannot be inserted without an error. tbl_name tbl_name is the table into which the rows should be inserted. insert_values The insert_values is the value to be inserted. For more information, see insert_values. ON DUPLICATE KEY UPDATE assignment_list If ON DUPLICATE KEY UPDATE is specified, and there is a conflict in a UNIQUE index or PRIMARY KEY, the data cannot be inserted, instead, the existing row will be updated using assignment_list. insert_values You can use the following ways to specify the data set: Value ListPlace the values to be inserted in a Value List.CREATE TABLE tbl_name ( a int, b int, c int ); INSERT INTO tbl_name VALUES(1,2,3),(4,5,6),(7,8,9); In the example above, (1,2,3),(4,5,6),(7,8,9) are the Value Lists enclosed within parentheses and separated by commas. Each Values List means a row of data. In this example, 3 rows are inserted. You can also specify the ColumnName List to insert rows only to some columns.INSERT INTO tbl_name (a,c) VALUES(1,2),(4,5),(7,8); In the example above, only the a and c columns are listed, the the b of each row will be set to Null. Assignment ListInsert the values by using Assignment Statements, for example:INSERT INTO tbl_name SET a=1, b=2, c=3; In this way, you can insert only one row of data each time, and the value of each column is specified using the assignment list. Select StatementThe data set to be inserted is obtained using a SELECT statement. The column to be inserted into is obtained from the Schema in the SELECT statement.CREATE TABLE tbl_name1 ( a int, b int, c int ); INSERT INTO tbl_name SELECT * from tbl_name1; In the example above, the data is selected from tal_name1, and then inserted into tbl_name. DELETE DELETE is a DML statement that removes rows from a table. TiDB is compatible with all the DELETE syntaxes of MySQL except for PARTITION. There are two kinds of DELETE, Single-Table DELETE and Multiple-Table DELETE.Single-Table DELETE syntax The Single_Table DELETE syntax deletes rows from a single table.DELETE syntax DELETE [LOW_PRIORITY] [QUICK] [IGNORE] FROM tbl_name [WHERE where_condition] [ORDER BY ...] [LIMIT row_count] Multiple-Table DELETE syntax The Multiple_Table DELETE syntax deletes rows of multiple tables, and has the following two kinds of formats:DELETE [LOW_PRIORITY] [QUICK] [IGNORE] tbl_name[.*] [, tbl_name[.*]] ... FROM table_references [WHERE where_condition] DELETE [LOW_PRIORITY] [QUICK] [IGNORE] FROM tbl_name[.*] [, tbl_name[.*]] ... USING table_references [WHERE where_condition] Both of the two syntax formats can be used to delete multiple tables, or delete the selected results from multiple tables. There are still differences between the two formats. The first one will delete data of every table in the table list before FROM. The second one will delete the data of the tables in the table list which is after FROM and before USING.Description of the syntax elements Syntax Elements Description LOW_PRIORITY LOW_PRIORITY gives the statement lower priority. TiDB lowers the priority of the current statement. QUICK To guarantee compatibility with MySQL, TiDB parses these three modifiers, but will ignore them. IGNORE To guarantee compatibility with MySQL, TiDB parses these three modifiers, but will ignore them. tbl_name the table names to be deleted WHERE where_condition the Where expression, which deletes rows that meets the expression ORDER BY To sort the data set which are to be deleted LIMIT row_count the top number of rows to be deleted as specified inrow_count Update UPDATE is used to update data of the …"}, {"url": "https://pingcap.com/docs/v1.0/sql/dml/", "title": "TiDB Data Manipulation Language", "content": " TiDB Data Manipulation Language Data manipulation language (DML) is a family of syntax elements used for selecting, inserting, deleting and updating data in a database.SELECT SELECT is used to retrieve rows selected from one or more tables.Syntax SELECT [ALL | DISTINCT | DISTINCTROW ] [HIGH_PRIORITY] [SQL_CACHE | SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS] select_expr [, select_expr ...] [FROM table_references [WHERE where_condition] [GROUP BY {col_name | expr | position} [ASC | DESC], ...] [HAVING where_condition] [ORDER BY {col_name | expr | position} [ASC | DESC], ...] [LIMIT {[offset,] row_count | row_count OFFSET offset}] [FOR UPDATE | LOCK IN SHARE MODE]] Description of the syntax elements Syntax Element Description ALL, DISTINCT, DISTINCTROW The ALL, DISTINCT/DISTINCTROW modifiers specify whether duplicate rows should be returned. ALL (the default) specifies that all matching rows should be returned. HIGH_PRIORITY HIGH_PRIORITY gives the current statement higher priority than other statements. SQL_CACHE, SQL_NO_CACHE, SQL_CALC_FOUND_ROWS To guarantee compatibility with MySQL, TiDB parses these three modifiers, but will ignore them. select_expr Each select_expr indicates a column to retrieve. including the column names and expressions. * represents all the columns. |FROM table_references The FROM table_references clause indicates the table (such as (select * from t;)) , or tables(such as select * from t1 join t2;)') or even 0 tables (such asselect 1+1 from dual;(which is equivalent toselect 1+1;‘)) from which to retrieve rows. WHERE where_condition The WHERE clause, if given, indicates the condition or conditions that rows must satisfy to be selected. The result contains only the data that meets the condition(s). GROUP BY The GROUP BY statement is used to group the result-set. HAVING where_condition The HAVING clause and the WHERE clause are both used to filter the results. The HAVING clause filters the results of GROUP BY, while the WHERE clause filter the results before aggregation。 ORDER BY The ORDER BY clause is used to sort the data in ascending or descending order, based on columns, expressions or items in the select_expr list. LIMIT The LIMIT clause can be used to constrain the number of rows. LIMIT takes one or two numeric arguments. With one argument, the argument specifies the maximum number of rows to return, the first row to return is the first row of the table by default; with two arguments, the first argument specifies the offset of the first row to return, and the second specifies the maximum number of rows to return. FOR UPDATE All the data in the result sets are read-locked, in order to detect the concurrent updates. TiDB uses the Optimistic Transaction Model. The transaction conflicts are detected in the commit phase instead of statement execution phase. while executing the SELECT FOR UPDATE statement, if there are other transactions trying to update relavant data, the SELECT FOR UPDATE transaction will fail. LOCK IN SHARE MODE To guarantee compatibility, TiDB parses these three modifiers, but will ignore them. INSERT INSERT inserts new rows into an existing table. TiDB is compatible with all the INSERT syntaxes of MySQL.Syntax Insert Statement: INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE] [INTO] tbl_name insert_values [ON DUPLICATE KEY UPDATE assignment_list] insert_values: [(col_name [, col_name] ...)] {VALUES | VALUE} (expr_list) [, (expr_list)] ... | SET assignment_list | [(col_name [, col_name] ...)] SELECT ... expr_list: expr [, expr] ... assignment: col_name = expr assignment_list: assignment [, assignment] ... Description of the syntax elements Syntax Elements Description LOW_PRIORITY LOW_PRIORITY gives the statement lower priority. TiDB lowers the priority of the current statement. DELAYED To guarantee compatibility, TiDB parses this modifier, but will ignore it. HIGH_PRIORITY HIGH_PRIORITY gives the current statement higher priority than other statements. TiDB raises the priority of the current statement. IGNORE If IGNORE modifier is specified and there is a duplicate key error, the data cannot be inserted without an error. tbl_name tbl_name is the table into which the rows should be inserted. insert_values The insert_values is the value to be inserted. For more information, see insert_values. ON DUPLICATE KEY UPDATE assignment_list If ON DUPLICATE KEY UPDATE is specified, and there is a conflict in a UNIQUE index or PRIMARY KEY, the data cannot be inserted, instead, the existing row will be updated using assignment_list. insert_values You can use the following ways to specify the data set: Value ListPlace the values to be inserted in a Value List.CREATE TABLE tbl_name ( a int, b int, c int ); INSERT INTO tbl_name VALUES(1,2,3),(4,5,6),(7,8,9); In the example above, (1,2,3),(4,5,6),(7,8,9) are the Value Lists enclosed within parentheses and separated by commas. Each Values List means a row of data. In this example, 3 rows are inserted. You can also specify the ColumnName List to insert rows only to some columns.INSERT INTO tbl_name (a,c) VALUES(1,2),(4,5),(7,8); In the example above, only the a and c columns are listed, the the b of each row will be set to Null. Assignment ListInsert the values by using Assignment Statements, for example:INSERT INTO tbl_name SET a=1, b=2, c=3; In this way, you can insert only one row of data each time, and the value of each column is specified using the assignment list. Select StatementThe data set to be inserted is obtained using a SELECT statement. The column to be inserted into is obtained from the Schema in the SELECT statement.CREATE TABLE tbl_name1 ( a int, b int, c int ); INSERT INTO tbl_name SELECT * from tbl_name1; In the example above, the data is selected from tal_name1, and then inserted into tbl_name. DELETE DELETE is a DML statement that removes rows from a table. TiDB is compatible with all the DELETE syntaxes of MySQL except for PARTITION. There are two kinds of DELETE, Single-Table DELETE and Multiple-Table DELETE.Single-Table DELETE syntax The Single_Table DELETE syntax deletes rows from a single table.DELETE syntax DELETE [LOW_PRIORITY] [QUICK] [IGNORE] FROM tbl_name [WHERE where_condition] [ORDER BY ...] [LIMIT row_count] Multiple-Table DELETE syntax The Multiple_Table DELETE syntax deletes rows of multiple tables, and has the following two kinds of formats:DELETE [LOW_PRIORITY] [QUICK] [IGNORE] tbl_name[.*] [, tbl_name[.*]] ... FROM table_references [WHERE where_condition] DELETE [LOW_PRIORITY] [QUICK] [IGNORE] FROM tbl_name[.*] [, tbl_name[.*]] ... USING table_references [WHERE where_condition] Both of the two syntax formats can be used to delete multiple tables, or delete the selected results from multiple tables. There are still differences between the two formats. The first one will delete data of every table in the table list before FROM. The second one will delete the data of the tables in the table list which is after FROM and before USING.Description of the syntax elements Syntax Elements Description LOW_PRIORITY LOW_PRIORITY gives the statement lower priority. TiDB lowers the priority of the current statement. QUICK To guarantee compatibility with MySQL, TiDB parses these three modifiers, but will ignore them. IGNORE To guarantee compatibility with MySQL, TiDB parses these three modifiers, but will ignore them. tbl_name the table names to be deleted WHERE where_condition the Where expression, which deletes rows that meets the expression ORDER BY To sort the data set which are to be deleted LIMIT row_count the top number of rows to be deleted as specified inrow_count Update UPDATE is used to update data of the tables.Syntax There are two kinds of UPDATE syntax, Single-table UPDATE and Multi-Table UPDATE.Single-table UPDATE UPDATE [LOW_PRIORITY] [IGNORE] table_reference SET assignment_list [WHERE where_condition] [ORDER BY ...] [LIMIT row_count] assignment: col_name …"}, {"url": "https://pingcap.com/docs/v2.0/sql/dml/", "title": "TiDB Data Manipulation Language", "content": " TiDB Data Manipulation Language Data manipulation language (DML) is a family of syntax elements used for selecting, inserting, deleting and updating data in a database.SELECT SELECT is used to retrieve rows selected from one or more tables.Syntax SELECT [ALL | DISTINCT | DISTINCTROW ] [HIGH_PRIORITY] [STRAIGHT_JOIN] [SQL_CACHE | SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS] select_expr [, select_expr ...] [FROM table_references [WHERE where_condition] [GROUP BY {col_name | expr | position} [ASC | DESC], ...] [HAVING where_condition] [ORDER BY {col_name | expr | position} [ASC | DESC], ...] [LIMIT {[offset,] row_count | row_count OFFSET offset}] [FOR UPDATE | LOCK IN SHARE MODE]] Description of the syntax elements Syntax Element Description ALL, DISTINCT, DISTINCTROW The ALL, DISTINCT/DISTINCTROW modifiers specify whether duplicate rows should be returned. ALL (the default) specifies that all matching rows should be returned. HIGH_PRIORITY HIGH_PRIORITY gives the current statement higher priority than other statements. SQL_CACHE, SQL_NO_CACHE, SQL_CALC_FOUND_ROWS To guarantee compatibility with MySQL, TiDB parses these three modifiers, but will ignore them. STRAIGHT_JOIN STRAIGHT_JOIN forces the optimizer to execute a Join query in the order of the tables used in the FROM clause. You can use this syntax to speed up queries execution when the Join order chosen by the optimizer is not good. select_expr Each select_expr indicates a column to retrieve. including the column names and expressions. * represents all the columns. |FROM table_references The FROM table_references clause indicates the table (such as (select * from t;)) , or tables(such as select * from t1 join t2;)') or even 0 tables (such asselect 1+1 from dual;(which is equivalent toselect 1+1;‘)) from which to retrieve rows. WHERE where_condition The WHERE clause, if given, indicates the condition or conditions that rows must satisfy to be selected. The result contains only the data that meets the condition(s). GROUP BY The GROUP BY statement is used to group the result-set. HAVING where_condition The HAVING clause and the WHERE clause are both used to filter the results. The HAVING clause filters the results of GROUP BY, while the WHERE clause filter the results before aggregation。 ORDER BY The ORDER BY clause is used to sort the data in ascending or descending order, based on columns, expressions or items in the select_expr list. LIMIT The LIMIT clause can be used to constrain the number of rows. LIMIT takes one or two numeric arguments. With one argument, the argument specifies the maximum number of rows to return, the first row to return is the first row of the table by default; with two arguments, the first argument specifies the offset of the first row to return, and the second specifies the maximum number of rows to return. FOR UPDATE All the data in the result sets are read-locked, in order to detect the concurrent updates. TiDB uses the Optimistic Transaction Model. The transaction conflicts are detected in the commit phase instead of statement execution phase. while executing the SELECT FOR UPDATE statement, if there are other transactions trying to update relavant data, the SELECT FOR UPDATE transaction will fail. LOCK IN SHARE MODE To guarantee compatibility, TiDB parses these three modifiers, but will ignore them. INSERT INSERT inserts new rows into an existing table. TiDB is compatible with all the INSERT syntaxes of MySQL.Syntax Insert Statement: INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE] [INTO] tbl_name insert_values [ON DUPLICATE KEY UPDATE assignment_list] insert_values: [(col_name [, col_name] ...)] {VALUES | VALUE} (expr_list) [, (expr_list)] ... | SET assignment_list | [(col_name [, col_name] ...)] SELECT ... expr_list: expr [, expr] ... assignment: col_name = expr assignment_list: assignment [, assignment] ... Description of the syntax elements Syntax Elements Description LOW_PRIORITY LOW_PRIORITY gives the statement lower priority. TiDB lowers the priority of the current statement. DELAYED To guarantee compatibility, TiDB parses this modifier, but will ignore it. HIGH_PRIORITY HIGH_PRIORITY gives the current statement higher priority than other statements. TiDB raises the priority of the current statement. IGNORE If IGNORE modifier is specified and there is a duplicate key error, the data cannot be inserted without an error. tbl_name tbl_name is the table into which the rows should be inserted. insert_values The insert_values is the value to be inserted. For more information, see insert_values. ON DUPLICATE KEY UPDATE assignment_list If ON DUPLICATE KEY UPDATE is specified, and there is a conflict in a UNIQUE index or PRIMARY KEY, the data cannot be inserted, instead, the existing row will be updated using assignment_list. insert_values You can use the following ways to specify the data set: Value ListPlace the values to be inserted in a Value List.CREATE TABLE tbl_name ( a int, b int, c int ); INSERT INTO tbl_name VALUES(1,2,3),(4,5,6),(7,8,9); In the example above, (1,2,3),(4,5,6),(7,8,9) are the Value Lists enclosed within parentheses and separated by commas. Each Values List means a row of data. In this example, 3 rows are inserted. You can also specify the ColumnName List to insert rows only to some columns.INSERT INTO tbl_name (a,c) VALUES(1,2),(4,5),(7,8); In the example above, only the a and c columns are listed, the the b of each row will be set to Null. Assignment ListInsert the values by using Assignment Statements, for example:INSERT INTO tbl_name SET a=1, b=2, c=3; In this way, you can insert only one row of data each time, and the value of each column is specified using the assignment list. Select StatementThe data set to be inserted is obtained using a SELECT statement. The column to be inserted into is obtained from the Schema in the SELECT statement.CREATE TABLE tbl_name1 ( a int, b int, c int ); INSERT INTO tbl_name SELECT * from tbl_name1; In the example above, the data is selected from tal_name1, and then inserted into tbl_name. DELETE DELETE is a DML statement that removes rows from a table. TiDB is compatible with all the DELETE syntaxes of MySQL except for PARTITION. There are two kinds of DELETE, Single-Table DELETE and Multiple-Table DELETE.Single-Table DELETE syntax The Single_Table DELETE syntax deletes rows from a single table.DELETE syntax DELETE [LOW_PRIORITY] [QUICK] [IGNORE] FROM tbl_name [WHERE where_condition] [ORDER BY ...] [LIMIT row_count] Multiple-Table DELETE syntax The Multiple_Table DELETE syntax deletes rows of multiple tables, and has the following two kinds of formats:DELETE [LOW_PRIORITY] [QUICK] [IGNORE] tbl_name[.*] [, tbl_name[.*]] ... FROM table_references [WHERE where_condition] DELETE [LOW_PRIORITY] [QUICK] [IGNORE] FROM tbl_name[.*] [, tbl_name[.*]] ... USING table_references [WHERE where_condition] Both of the two syntax formats can be used to delete multiple tables, or delete the selected results from multiple tables. There are still differences between the two formats. The first one will delete data of every table in the table list before FROM. The second one will delete the data of the tables in the table list which is after FROM and before USING.Description of the syntax elements Syntax Elements Description LOW_PRIORITY LOW_PRIORITY gives the statement lower priority. TiDB lowers the priority of the current statement. QUICK To guarantee compatibility with MySQL, TiDB parses these three modifiers, but will ignore them. IGNORE To guarantee compatibility with MySQL, TiDB parses these three modifiers, but will ignore them. tbl_name the table names to be deleted WHERE where_condition the Where expression, which deletes rows that meets the expression ORDER BY To sort the data set which are to be deleted LIMIT row_count the top number of rows to be deleted as specified inrow_count Update UPDATE is used to update data of the …"}, {"url": "https://pingcap.com/docs/sql/datatype/", "title": "TiDB Data Type", "content": " TiDB Data Type TiDB supports all the data types in MySQL except the Spatial type, including numeric type, string type, date & time type, and JSON type.The definition of the data type is: T(M[, D]). In this format: T indicates the specific data type. M indicates the maximum display width for integer types. For floating-point and fixed-point types, M is the total number of digits that can be stored (the precision). For string types, M is the maximum length. The maximum permissible value of M depends on the data type. D applies to floating-point and fixed-point types and indicates the number of digits following the decimal point (the scale). fsp applies to the TIME, DATETIME, and TIMESTAMP types and represents the fractional seconds precision. The fsp value, if given, must be in the range 0 to 6. A value of 0 signifies that there is no fractional part. If omitted, the default precision is 0. Numeric types Overview TiDB supports all the MySQL numeric types, including: Integer Types (Exact Value) Floating-Point Types (Approximate Value) Fixed-Point Types (Exact Value) Integer types (exact value) TiDB supports all the MySQL integer types, including INTEGER/INT, TINYINT, SMALLINT, MEDIUMINT, and BIGINT. For more information, see Numeric Type Overview in MySQL.Type definition Syntax:BIT[(M)] > The BIT data type. A type of BIT(M) enables storage of M-bit values. M can range from 1 to 64. TINYINT[(M)] [UNSIGNED] [ZEROFILL] > The TINYINT data type. The value range for signed: [-128, 127] and the range for unsigned is [0, 255]. BOOL, BOOLEAN > BOOLEAN and is equivalent to TINYINT(1). If the value is "0", it is considered as False; otherwise, it is considered True. In TiDB, True is "1" and False is "0". SMALLINT[(M)] [UNSIGNED] [ZEROFILL] > SMALLINT. The signed range is: [-32768, 32767], and the unsigned range is [0, 65535]. MEDIUMINT[(M)] [UNSIGNED] [ZEROFILL] > MEDIUMINT. The signed range is: [-8388608, 8388607], and the unsigned range is [0, 16777215]. INT[(M)] [UNSIGNED] [ZEROFILL] > INT. The signed range is: [-2147483648, 2147483647], and the unsigned range is [0, 4294967295]. INTEGER[(M)] [UNSIGNED] [ZEROFILL] > Same as INT. BIGINT[(M)] [UNSIGNED] [ZEROFILL] > BIGINT. The signed range is: [-9223372036854775808, 9223372036854775807], and the unsigned range is [0, 18446744073709551615]. The meaning of the fields: Syntax Element Description M the display width of the type. Optional. UNSIGNED UNSIGNED. If omitted, it is SIGNED. ZEROFILL If you specify ZEROFILL for a numeric column, TiDB automatically adds the UNSIGNED attribute to the column. Storage and range See the following for the requirements of the storage and minimum value/maximim value of each data type: Type Storage Required (bytes) Minimum Value (Signed/Unsigned) Maximum Value (Signed/Unsigned) TINYINT 1 -128 / 0 127 / 255 SMALLINT 2 -32768 / 0 32767 / 65535 MEDIUMINT 3 -8388608 / 0 8388607 / 16777215 INT 4 -2147483648 / 0 2147483647 / 4294967295 BIGINT 8 -9223372036854775808 / 0 9223372036854775807 / 18446744073709551615 Floating-point types (approximate value) TiDB supports all the MySQL floating-point types, including FLOAT, and DOUBLE. For more information, Floating-Point Types (Approximate Value) - FLOAT, DOUBLE in MySQL.Type definition Syntax:FLOAT[(M,D)] [UNSIGNED] [ZEROFILL] > A small (single-precision) floating-point number. Permissible values are -3.402823466E+38 to -1.175494351E-38, 0, and 1.175494351E-38 to 3.402823466E+38. These are the theoretical limits, based on the IEEE standard. The actual range might be slightly smaller depending on your hardware or operating system. DOUBLE[(M,D)] [UNSIGNED] [ZEROFILL] > A normal-size (double-precision) floating-point number. Permissible values are -1.7976931348623157E+308 to -2.2250738585072014E-308, 0, and 2.2250738585072014E-308 to 1.7976931348623157E+308. These are the theoretical limits, based on the IEEE standard. The actual range might be slightly smaller depending on your hardware or operating system. DOUBLE PRECISION [(M,D)] [UNSIGNED] [ZEROFILL], REAL[(M,D)] [UNSIGNED] [ZEROFILL] > Synonym for DOUBLE. FLOAT(p) [UNSIGNED] [ZEROFILL] > A floating-point number. p represents the precision in bits, but TiDB uses this value only to determine whether to use FLOAT or DOUBLE for the resulting data type. If p is from 0 to 24, the data type becomes FLOAT with no M or D values. If p is from 25 to 53, the data type becomes DOUBLE with no M or D values. The range of the resulting column is the same as for the single-precision FLOAT or double-precision DOUBLE data types described earlier in this section. The meaning of the fields: Syntax Element Description M the total number of digits D the number of digits following the decimal point UNSIGNED UNSIGNED. If omitted, it is SIGNED. ZEROFILL If you specify ZEROFILL for a numeric column, TiDB automatically adds the UNSIGNED attribute to the column. Storage See the following for the requirements of the storage: Data Type Storage Required (bytes) FLOAT 4 FLOAT(p) If 0 <= p <= 24, it is 4; if 25 <= p <= 53, it is 8 DOUBLE 8 Fixed-point types (exact value) TiDB supports all the MySQL floating-point types, including DECIMAL, and NUMERIC. For more information, Fixed-Point Types (Exact Value) - DECIMAL, NUMERIC in MySQL.Type definition SyntaxDECIMAL[(M[,D])] [UNSIGNED] [ZEROFILL] > A packed “exact” fixed-point number. M is the total number of digits (the precision), and D is the number of digits after the decimal point (the scale). The decimal point and (for negative numbers) the - sign are not counted in M. If D is 0, values have no decimal point or fractional part. The maximum number of digits (M) for DECIMAL is 65. The maximum number of supported decimals (D) is 30. If D is omitted, the default is 0. If M is omitted, the default is 10. NUMERIC[(M[,D])] [UNSIGNED] [ZEROFILL] > Synonym for DECIMAL. The meaning of the fields: Syntax Element Description M the total number of digits D the number of digits after the decimal point UNSIGNED UNSIGNED. If omitted, it is SIGNED. ZEROFILL If you specify ZEROFILL for a numeric column, TiDB automatically adds the UNSIGNED attribute to the column. Date and time types Overview TiDB supports all the MySQL floating-point types, including DATE, DATETIME, TIMESTAMP, TIME, and YEAR. For more information, Date and Time Types in MySQL.Type definition Syntax:DATE > A date. The supported range is '1000-01-01' to '9999-12-31'. TiDB displays DATE values in 'YYYY-MM-DD' format. DATETIME[(fsp)] > A date and time combination. The supported range is '1000-01-01 00:00:00.000000' to '9999-12-31 23:59:59.999999'. TiDB displays DATETIME values in 'YYYY-MM-DD HH:MM:SS[.fraction]' format, but permits assignment of values to DATETIME columns using either strings or numbers. An optional fsp value in the range from 0 to 6 may be given to specify fractional seconds precision. If omitted, the default precision is 0. TIMESTAMP[(fsp)] > A timestamp. The range is '1970-01-01 00:00:01.000000' to '2038-01-19 03:14:07.999999'. An optional fsp value in the range from 0 to 6 may be given to specify fractional seconds precision. If omitted, the default precision is 0. An optional fsp value in the range from 0 to 6 may be given to specify fractional seconds precision. If omitted, the default precision is 0. TIME[(fsp)] > A time. The range is '-838:59:59.000000' to '838:59:59.000000'. TiDB displays TIME values in 'HH:MM:SS[.fraction]' format. An optional fsp value in the range from 0 to 6 may be given to specify fractional seconds precision. If omitted, the default precision is 0. YEAR[(4)] > A year in four-digit format. Values display as 1901 to 2155, and 0000. String types Overview TiDB supports all the MySQL string types, including CHAR, VARCHAR, …"}, {"url": "https://pingcap.com/docs/v1.0/sql/datatype/", "title": "TiDB Data Type", "content": " TiDB Data Type Overview TiDB supports all the data types in MySQL except the Spatial type, including numeric type, string type, date & time type, and JSON type.The definition of the data type is: T(M[, D]). In this format: T indicates the specific data type. M indicates the maximum display width for integer types. For floating-point and fixed-point types, M is the total number of digits that can be stored (the precision). For string types, M is the maximum length. The maximum permissible value of M depends on the data type. D applies to floating-point and fixed-point types and indicates the number of digits following the decimal point (the scale). fsp applies to the TIME, DATETIME, and TIMESTAMP types and represents the fractional seconds precision. The fsp value, if given, must be in the range 0 to 6. A value of 0 signifies that there is no fractional part. If omitted, the default precision is 0. Numeric types Overview TiDB supports all the MySQL numeric types, including: Integer Types (Exact Value) Floating-Point Types (Approximate Value) Fixed-Point Types (Exact Value) Integer types (exact value) TiDB supports all the MySQL integer types, including INTEGER/INT, TINYINT, SMALLINT, MEDIUMINT, and BIGINT. For more information, see Numeric Type Overview in MySQL.Type definition Syntax:BIT[(M)] > The BIT data type. A type of BIT(M) enables storage of M-bit values. M can range from 1 to 64. TINYINT[(M)] [UNSIGNED] [ZEROFILL] > The TINYINT data type. The value range for signed: [-128, 127] and the range for unsigned is [0, 255]. BOOL, BOOLEAN > BOOLEAN and is equivalent to TINYINT(1). If the value is "0", it is considered as False; otherwise, it is considered True. In TiDB, True is "1" and False is "0". SMALLINT[(M)] [UNSIGNED] [ZEROFILL] > SMALLINT. The signed range is: [-32768, 32767], and the unsigned range is [0, 65535]. MEDIUMINT[(M)] [UNSIGNED] [ZEROFILL] > MEDIUMINT. The signed range is: [-8388608, 8388607], and the unsigned range is [0, 16777215]. INT[(M)] [UNSIGNED] [ZEROFILL] > INT. The signed range is: [-2147483648, 2147483647], and the unsigned range is [0, 4294967295]. INTEGER[(M)] [UNSIGNED] [ZEROFILL] > Same as INT. BIGINT[(M)] [UNSIGNED] [ZEROFILL] > BIGINT. The signed range is: [-9223372036854775808, 9223372036854775807], and the unsigned range is [0, 18446744073709551615]. The meaning of the fields: Syntax Element Description M the length of the type. Optional. UNSIGNED UNSIGNED. If omitted, it is SIGNED. ZEROFILL If you specify ZEROFILL for a numeric column, TiDB automatically adds the UNSIGNED attribute to the column. Storage and range See the following for the requirements of the storage and minimum value/maximim value of each data type: Type Storage Required (bytes) Minimum Value (Signed/Unsigned) Maximum Value (Signed/Unsigned) TINYINT 1 -128 / 0 127 / 255 SMALLINT 2 -32768 / 0 32767 / 65535 MEDIUMINT 3 -8388608 / 0 8388607 / 16777215 INT 4 -2147483648 / 0 2147483647 / 4294967295 BIGINT 8 -9223372036854775808 / 0 9223372036854775807 / 18446744073709551615 Floating-point types (approximate value) TiDB supports all the MySQL floating-point types, including FLOAT, and DOUBLE. For more information, Floating-Point Types (Approximate Value) - FLOAT, DOUBLE in MySQL.Type definition Syntax:FLOAT[(M,D)] [UNSIGNED] [ZEROFILL] > A small (single-precision) floating-point number. Permissible values are -3.402823466E+38 to -1.175494351E-38, 0, and 1.175494351E-38 to 3.402823466E+38. These are the theoretical limits, based on the IEEE standard. The actual range might be slightly smaller depending on your hardware or operating system. DOUBLE[(M,D)] [UNSIGNED] [ZEROFILL] > A normal-size (double-precision) floating-point number. Permissible values are -1.7976931348623157E+308 to -2.2250738585072014E-308, 0, and 2.2250738585072014E-308 to 1.7976931348623157E+308. These are the theoretical limits, based on the IEEE standard. The actual range might be slightly smaller depending on your hardware or operating system. DOUBLE PRECISION [(M,D)] [UNSIGNED] [ZEROFILL], REAL[(M,D)] [UNSIGNED] [ZEROFILL] > Synonym for DOUBLE. FLOAT(p) [UNSIGNED] [ZEROFILL] > A floating-point number. p represents the precision in bits, but TiDB uses this value only to determine whether to use FLOAT or DOUBLE for the resulting data type. If p is from 0 to 24, the data type becomes FLOAT with no M or D values. If p is from 25 to 53, the data type becomes DOUBLE with no M or D values. The range of the resulting column is the same as for the single-precision FLOAT or double-precision DOUBLE data types described earlier in this section. The meaning of the fields: Syntax Element Description M the total number of digits D the number of digits following the decimal point UNSIGNED UNSIGNED. If omitted, it is SIGNED. ZEROFILL If you specify ZEROFILL for a numeric column, TiDB automatically adds the UNSIGNED attribute to the column. Storage See the following for the requirements of the storage: Data Type Storage Required (bytes) FLOAT 4 FLOAT(p) If 0 <= p <= 24, it is 4; if 25 <= p <= 53, it is 8 DOUBLE 8 Fixed-point types (exact value) TiDB supports all the MySQL floating-point types, including DECIMAL, and NUMERIC. For more information, Fixed-Point Types (Exact Value) - DECIMAL, NUMERIC in MySQL.Type definition SyntaxDECIMAL[(M[,D])] [UNSIGNED] [ZEROFILL] > A packed “exact” fixed-point number. M is the total number of digits (the precision), and D is the number of digits after the decimal point (the scale). The decimal point and (for negative numbers) the - sign are not counted in M. If D is 0, values have no decimal point or fractional part. The maximum number of digits (M) for DECIMAL is 65. The maximum number of supported decimals (D) is 30. If D is omitted, the default is 0. If M is omitted, the default is 10. NUMERIC[(M[,D])] [UNSIGNED] [ZEROFILL] > Synonym for DECIMAL. The meaning of the fields: Syntax Element Description M the total number of digits D the number of digits after the decimal point UNSIGNED UNSIGNED. If omitted, it is SIGNED. ZEROFILL If you specify ZEROFILL for a numeric column, TiDB automatically adds the UNSIGNED attribute to the column. Date and time types Overview TiDB supports all the MySQL floating-point types, including DATE, DATETIME, TIMESTAMP, TIME, and YEAR. For more information, Date and Time Types in MySQL.Type definition Syntax:DATE > A date. The supported range is '1000-01-01' to '9999-12-31'. TiDB displays DATE values in 'YYYY-MM-DD' format. DATETIME[(fsp)] > A date and time combination. The supported range is '1000-01-01 00:00:00.000000' to '9999-12-31 23:59:59.999999'. TiDB displays DATETIME values in 'YYYY-MM-DD HH:MM:SS[.fraction]' format, but permits assignment of values to DATETIME columns using either strings or numbers. An optional fsp value in the range from 0 to 6 may be given to specify fractional seconds precision. If omitted, the default precision is 0. TIMESTAMP[(fsp)] > A timestamp. The range is '1970-01-01 00:00:01.000000' to '2038-01-19 03:14:07.999999'. An optional fsp value in the range from 0 to 6 may be given to specify fractional seconds precision. If omitted, the default precision is 0. An optional fsp value in the range from 0 to 6 may be given to specify fractional seconds precision. If omitted, the default precision is 0. TIME[(fsp)] > A time. The range is '-838:59:59.000000' to '838:59:59.000000'. TiDB displays TIME values in 'HH:MM:SS[.fraction]' format. An optional fsp value in the range from 0 to 6 may be given to specify fractional seconds precision. If omitted, the default precision is 0. YEAR[(2|4)] > A year in two-digit or four-digit format. The default is the four-digit format. In four-digit format, values display as 1901 to 2155, and 0000. In two-digit …"}, {"url": "https://pingcap.com/docs/v2.0/sql/datatype/", "title": "TiDB Data Type", "content": " TiDB Data Type TiDB supports all the data types in MySQL except the Spatial type, including numeric type, string type, date & time type, and JSON type.The definition of the data type is: T(M[, D]). In this format: T indicates the specific data type. M indicates the maximum display width for integer types. For floating-point and fixed-point types, M is the total number of digits that can be stored (the precision). For string types, M is the maximum length. The maximum permissible value of M depends on the data type. D applies to floating-point and fixed-point types and indicates the number of digits following the decimal point (the scale). fsp applies to the TIME, DATETIME, and TIMESTAMP types and represents the fractional seconds precision. The fsp value, if given, must be in the range 0 to 6. A value of 0 signifies that there is no fractional part. If omitted, the default precision is 0. Numeric types Overview TiDB supports all the MySQL numeric types, including: Integer Types (Exact Value) Floating-Point Types (Approximate Value) Fixed-Point Types (Exact Value) Integer types (exact value) TiDB supports all the MySQL integer types, including INTEGER/INT, TINYINT, SMALLINT, MEDIUMINT, and BIGINT. For more information, see Numeric Type Overview in MySQL.Type definition Syntax:BIT[(M)] > The BIT data type. A type of BIT(M) enables storage of M-bit values. M can range from 1 to 64. TINYINT[(M)] [UNSIGNED] [ZEROFILL] > The TINYINT data type. The value range for signed: [-128, 127] and the range for unsigned is [0, 255]. BOOL, BOOLEAN > BOOLEAN and is equivalent to TINYINT(1). If the value is "0", it is considered as False; otherwise, it is considered True. In TiDB, True is "1" and False is "0". SMALLINT[(M)] [UNSIGNED] [ZEROFILL] > SMALLINT. The signed range is: [-32768, 32767], and the unsigned range is [0, 65535]. MEDIUMINT[(M)] [UNSIGNED] [ZEROFILL] > MEDIUMINT. The signed range is: [-8388608, 8388607], and the unsigned range is [0, 16777215]. INT[(M)] [UNSIGNED] [ZEROFILL] > INT. The signed range is: [-2147483648, 2147483647], and the unsigned range is [0, 4294967295]. INTEGER[(M)] [UNSIGNED] [ZEROFILL] > Same as INT. BIGINT[(M)] [UNSIGNED] [ZEROFILL] > BIGINT. The signed range is: [-9223372036854775808, 9223372036854775807], and the unsigned range is [0, 18446744073709551615]. The meaning of the fields: Syntax Element Description M the length of the type. Optional. UNSIGNED UNSIGNED. If omitted, it is SIGNED. ZEROFILL If you specify ZEROFILL for a numeric column, TiDB automatically adds the UNSIGNED attribute to the column. Storage and range See the following for the requirements of the storage and minimum value/maximim value of each data type: Type Storage Required (bytes) Minimum Value (Signed/Unsigned) Maximum Value (Signed/Unsigned) TINYINT 1 -128 / 0 127 / 255 SMALLINT 2 -32768 / 0 32767 / 65535 MEDIUMINT 3 -8388608 / 0 8388607 / 16777215 INT 4 -2147483648 / 0 2147483647 / 4294967295 BIGINT 8 -9223372036854775808 / 0 9223372036854775807 / 18446744073709551615 Floating-point types (approximate value) TiDB supports all the MySQL floating-point types, including FLOAT, and DOUBLE. For more information, Floating-Point Types (Approximate Value) - FLOAT, DOUBLE in MySQL.Type definition Syntax:FLOAT[(M,D)] [UNSIGNED] [ZEROFILL] > A small (single-precision) floating-point number. Permissible values are -3.402823466E+38 to -1.175494351E-38, 0, and 1.175494351E-38 to 3.402823466E+38. These are the theoretical limits, based on the IEEE standard. The actual range might be slightly smaller depending on your hardware or operating system. DOUBLE[(M,D)] [UNSIGNED] [ZEROFILL] > A normal-size (double-precision) floating-point number. Permissible values are -1.7976931348623157E+308 to -2.2250738585072014E-308, 0, and 2.2250738585072014E-308 to 1.7976931348623157E+308. These are the theoretical limits, based on the IEEE standard. The actual range might be slightly smaller depending on your hardware or operating system. DOUBLE PRECISION [(M,D)] [UNSIGNED] [ZEROFILL], REAL[(M,D)] [UNSIGNED] [ZEROFILL] > Synonym for DOUBLE. FLOAT(p) [UNSIGNED] [ZEROFILL] > A floating-point number. p represents the precision in bits, but TiDB uses this value only to determine whether to use FLOAT or DOUBLE for the resulting data type. If p is from 0 to 24, the data type becomes FLOAT with no M or D values. If p is from 25 to 53, the data type becomes DOUBLE with no M or D values. The range of the resulting column is the same as for the single-precision FLOAT or double-precision DOUBLE data types described earlier in this section. The meaning of the fields: Syntax Element Description M the total number of digits D the number of digits following the decimal point UNSIGNED UNSIGNED. If omitted, it is SIGNED. ZEROFILL If you specify ZEROFILL for a numeric column, TiDB automatically adds the UNSIGNED attribute to the column. Storage See the following for the requirements of the storage: Data Type Storage Required (bytes) FLOAT 4 FLOAT(p) If 0 <= p <= 24, it is 4; if 25 <= p <= 53, it is 8 DOUBLE 8 Fixed-point types (exact value) TiDB supports all the MySQL floating-point types, including DECIMAL, and NUMERIC. For more information, Fixed-Point Types (Exact Value) - DECIMAL, NUMERIC in MySQL.Type definition SyntaxDECIMAL[(M[,D])] [UNSIGNED] [ZEROFILL] > A packed “exact” fixed-point number. M is the total number of digits (the precision), and D is the number of digits after the decimal point (the scale). The decimal point and (for negative numbers) the - sign are not counted in M. If D is 0, values have no decimal point or fractional part. The maximum number of digits (M) for DECIMAL is 65. The maximum number of supported decimals (D) is 30. If D is omitted, the default is 0. If M is omitted, the default is 10. NUMERIC[(M[,D])] [UNSIGNED] [ZEROFILL] > Synonym for DECIMAL. The meaning of the fields: Syntax Element Description M the total number of digits D the number of digits after the decimal point UNSIGNED UNSIGNED. If omitted, it is SIGNED. ZEROFILL If you specify ZEROFILL for a numeric column, TiDB automatically adds the UNSIGNED attribute to the column. Date and time types Overview TiDB supports all the MySQL floating-point types, including DATE, DATETIME, TIMESTAMP, TIME, and YEAR. For more information, Date and Time Types in MySQL.Type definition Syntax:DATE > A date. The supported range is '1000-01-01' to '9999-12-31'. TiDB displays DATE values in 'YYYY-MM-DD' format. DATETIME[(fsp)] > A date and time combination. The supported range is '1000-01-01 00:00:00.000000' to '9999-12-31 23:59:59.999999'. TiDB displays DATETIME values in 'YYYY-MM-DD HH:MM:SS[.fraction]' format, but permits assignment of values to DATETIME columns using either strings or numbers. An optional fsp value in the range from 0 to 6 may be given to specify fractional seconds precision. If omitted, the default precision is 0. TIMESTAMP[(fsp)] > A timestamp. The range is '1970-01-01 00:00:01.000000' to '2038-01-19 03:14:07.999999'. An optional fsp value in the range from 0 to 6 may be given to specify fractional seconds precision. If omitted, the default precision is 0. An optional fsp value in the range from 0 to 6 may be given to specify fractional seconds precision. If omitted, the default precision is 0. TIME[(fsp)] > A time. The range is '-838:59:59.000000' to '838:59:59.000000'. TiDB displays TIME values in 'HH:MM:SS[.fraction]' format. An optional fsp value in the range from 0 to 6 may be given to specify fractional seconds precision. If omitted, the default precision is 0. YEAR[(2|4)] > A year in two-digit or four-digit format. The default is the four-digit format. In four-digit format, values display as 1901 to 2155, and 0000. In two-digit format, …"}, {"url": "https://pingcap.com/docs/op-guide/kubernetes/", "title": "TiDB Deployment on Kubernetes", "content": " TiDB Deployment on Kubernetes TiDB Operator manages TiDB clusters on Kubernetes and automates tasks related to operating a TiDB cluster. It makes TiDB a truly cloud-native database. Warning: Currently, TiDB Operator is work in progress [WIP] and is NOT ready for production. Use at your own risk. GCP AWS Local Google Kubernetes Engine (GKE) The TiDB Operator tutorial for GKE runs directly in the Google Cloud Shell. AWS Elastic Kubernetes Service (EKS) Deploy a running TiDB Cluster on EKS using a combination of Terraform and TiDB Operator.Continue reading tutorial on GitHub Local installation using Docker in Docker Docker in Docker (DinD) runs Docker containers as virtual machines and runs another layer of Docker containers inside the first layer of Docker containers. kubeadm-dind-cluster uses this technology to run the Kubernetes cluster in Docker containers. TiDB Operator uses a modified DinD script to manage the DinD Kubernetes cluster.Continue reading tutorial on GitHub "}, {"url": "https://pingcap.com/docs/op-guide/docker-compose/", "title": "TiDB Docker Compose Deployment", "content": " TiDB Docker Compose Deployment This document describes how to quickly deploy a TiDB testing cluster with a single command using Docker Compose.With Docker Compose, you can use a YAML file to configure application services in multiple containers. Then, with a single command, you can create and start all the services from your configuration.Prerequisites Make sure you have installed the following items on your machine: Git Docker Compose MySQL Client Deploy TiDB using Docker Compose Download tidb-docker-compose.git clone https://github.com/pingcap/tidb-docker-compose.git Change the directory to tidb-docker-compose and get the latest TiDB Docker Images:cd tidb-docker-compose && docker-compose pull Start the TiDB cluster:docker-compose up -d Use the MySQL client to connect to TiDB to read and write data:mysql -h 127.0.0.1 -P 4000 -u root Monitor the cluster After you have successfully deployed a TiDB cluster, you can now monitor the TiDB cluster using one of the following methods: Use Grafana to view the status of the cluster via http://localhost:3000 with the default account name and password: admin and admin. Use TiDB-Vision, a cluster visualization tool, to see data transfer and load-balancing inside your cluster via http://localhost:8010. Customize the cluster After the deployment is completed, the following components are deployed by default: 3 PD instances, 3 TiKV instances, 1 TiDB instance Monitoring components: Prometheus, Pushgateway, Grafana Data visualization component: tidb-vision To customize the cluster, you can edit the docker-compose.yml file directly. It is recommended to generate docker-compose.yml using the Helm template engine, because manual editing is tedious and error-prone. Install Helm.Helm can be used as a template rendering engine. To use Helm, you only need to download its binary file:curl https://raw.githubusercontent.com/kubernetes/helm/master/scripts/get | bash For macOS, you can also install Helm using the following command in Homebrew:brew install kubernetes-helm Download tidb-docker-compose.git clone https://github.com/pingcap/tidb-docker-compose.git Customize the cluster.cd tidb-docker-compose vim compose/values.yaml # custom the cluster size, docker image, port mapping and so on You can modify the configuration in values.yaml, such as the cluster size, TiDB image version, and so on.tidb-vision is the data visualization interface of the TiDB cluster, used to visually display the PD scheduling on TiKV data. If you do not need this component, comment out the tidbVision section.For PD, TiKV, TiDB and tidb-vision, you can build Docker images from GitHub source code or local files for development and testing. To build PD, TiKV or TiDB images from the locally compiled binary file, you need to comment out the image field and copy the compiled binary file to the corresponding pd/bin/pd-server, tikv/bin/tikv-server, tidb/bin/tidb-server. To build the tidb-vision image from local, you need to comment out the image field and copy the tidb-vision project to tidb-vision/tidb-vision. Generate the docker-compose.yml file.helm template compose > generated-docker-compose.yml Create and start the cluster using the generated docker-compose.yml file.docker-compose -f generated-docker-compose.yml pull # Get the latest Docker images docker-compose -f generated-docker-compose.yml up -d Access the cluster.mysql -h 127.0.0.1 -P 4000 -u root Access the Grafana monitoring interface: Default address: http://localhost:3000 Default account name: admin Default password: admin If tidb-vision is enabled, you can access the cluster data visualization interface: http://localhost:8010. Access the Spark shell and load TiSpark Insert some sample data to the TiDB cluster:$ docker-compose exec tispark-master bash $ cd /opt/spark/data/tispark-sample-data $ mysql -h tidb -P 4000 -u root < dss.ddl After the sample data is loaded into the TiDB cluster, you can access the Spark shell using docker-compose exec tispark-master /opt/spark/bin/spark-shell.$ docker-compose exec tispark-master /opt/spark/bin/spark-shell ... Spark context available as 'sc' (master = local[*], app id = local-1527045927617). Spark session available as 'spark'. Welcome to ____ __ / __/__ ___ _____/ /__ _ / _ / _ `/ __/ '_/ /___/ .__/_,_/_/ /_/_ version 2.1.1 /_/ Using Scala version 2.11.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_172) Type in expressions to have them evaluated. Type :help for more information. scala> import org.apache.spark.sql.TiContext ... scala> val ti = new TiContext(spark) ... scala> ti.tidbMapDatabase("TPCH_001") ... scala> spark.sql("select count(*) from lineitem").show +--------+ |count(1)| +--------+ | 60175| +--------+ You can also access Spark with Python or R using the following commands:docker-compose exec tispark-master /opt/spark/bin/pyspark docker-compose exec tispark-master /opt/spark/bin/sparkR For more details about TiSpark, see here.Here is a 5-minute tutorial for macOS users that shows how to spin up a standard TiDB cluster using Docker Compose on your local computer."}, {"url": "https://pingcap.com/docs/v1.0/op-guide/docker-compose/", "title": "TiDB Docker Compose Deployment", "content": " TiDB Docker Compose Deployment This document describes how to quickly deploy TiDB using Docker Compose.With Docker Compose, you can use a YAML file to configure application services in multiple containers. Then, with a single command, you can create and start all the services from your configuration.You can use Docker Compose to deploy a TiDB test cluster with a single command. It is required to use Docker 17.06.0 or later.Quick start Download tidb-docker-compose.git clone https://github.com/pingcap/tidb-docker-compose.git Create and start the cluster.cd tidb-docker-compose && docker-compose up -d Access the cluster.mysql -h 127.0.0.1 -P 4000 -u root Access the Grafana monitoring interface: Default address: http://localhost:3000 Default account name: admin Default password: admin Access the cluster data visualization interface: http://localhost:8010 Customize the cluster In Quick start, the following components are deployed by default: 3 PD instances, 3 TiKV instances, 1 TiDB instance Monitoring components: Prometheus,Pushgateway,Grafana Data visualization component: tidb-vision To customize the cluster, you can edit the docker-compose.yml file directly. It is recommended to generate docker-compose.yml using the Helm template engine, because manual editing is tedious and error-prone. Install Helm.Helm can be used as a template rendering engine. To use Helm, you only need to download its binary file:curl https://raw.githubusercontent.com/kubernetes/helm/master/scripts/get | bash For macOS, you can also install Helm using the following command in Homebrew:brew install kubernetes-helm Download tidb-docker-compose.git clone https://github.com/pingcap/tidb-docker-compose.git Customize the cluster.cd tidb-docker-compose cp compose/values.yaml values.yaml vim values.yaml Modify the configuration in values.yaml, such as the cluster size, TiDB image version, and so on.tidb-vision is the data visualization interface of the TiDB cluster, used to visually display the PD scheduling on TiKV data. If you do not need this component, leave tidbVision empty.For PD, TiKV, TiDB and tidb-vision, you can build Docker images from GitHub source code or local files for development and testing. To build the image of a component from GitHub source code, you need to leave the image field empty and set buildFrom to remote. To build PD, TiKV or TiDB images from the locally compiled binary file, you need to leave the image field empty, set buildFrom to local and copy the compiled binary file to the corresponding pd/bin/pd-server, tikv/bin/tikv-server, tidb/bin/tidb-server. To build the tidb-vision image from local, you need to leave the image field empty, set buildFrom to local and copy the tidb-vision project to tidb-vision/tidb-vision. Generate the docker-compose.yml file.helm template -f values.yaml compose > generated-docker-compose.yml Create and start the cluster using the generated docker-compose.yml file.docker-compose -f generated-docker-compose.yml up -d Access the cluster.mysql -h 127.0.0.1 -P 4000 -u root Access the Grafana monitoring interface: Default address: http://localhost:3000 Default account name: admin Default password: admin If tidb-vision is enabled, you can access the cluster data visualization interface: http://localhost:8010. "}, {"url": "https://pingcap.com/docs/v2.0/op-guide/docker-compose/", "title": "TiDB Docker Compose Deployment", "content": " TiDB Docker Compose Deployment This document describes how to quickly deploy a TiDB testing cluster with a single command using Docker Compose.With Docker Compose, you can use a YAML file to configure application services in multiple containers. Then, with a single command, you can create and start all the services from your configuration.Prerequisites Make sure you have installed the following items on your machine: Docker (17.06.0 or later) Docker Compose Git Deploy TiDB using Docker Compose Download tidb-docker-compose.git clone https://github.com/pingcap/tidb-docker-compose.git Create and start the cluster.cd tidb-docker-compose && docker-compose pull # Get the latest Docker images docker-compose up -d Access the cluster.mysql -h 127.0.0.1 -P 4000 -u root Access the Grafana monitoring interface: Default address: http://localhost:3000 Default account name: admin Default password: admin Access the cluster data visualization interface: http://localhost:8010 Customize the cluster After the deployment is completed, the following components are deployed by default: 3 PD instances, 3 TiKV instances, 1 TiDB instance Monitoring components: Prometheus, Pushgateway, Grafana Data visualization component: tidb-vision To customize the cluster, you can edit the docker-compose.yml file directly. It is recommended to generate docker-compose.yml using the Helm template engine, because manual editing is tedious and error-prone. Install Helm.Helm can be used as a template rendering engine. To use Helm, you only need to download its binary file:curl https://raw.githubusercontent.com/kubernetes/helm/master/scripts/get | bash For macOS, you can also install Helm using the following command in Homebrew:brew install kubernetes-helm Download tidb-docker-compose.git clone https://github.com/pingcap/tidb-docker-compose.git Customize the cluster.cd tidb-docker-compose cp compose/values.yaml values.yaml vim values.yaml You can modify the configuration in values.yaml, such as the cluster size, TiDB image version, and so on.tidb-vision is the data visualization interface of the TiDB cluster, used to visually display the PD scheduling on TiKV data. If you do not need this component, leave tidbVision empty.For PD, TiKV, TiDB and tidb-vision, you can build Docker images from GitHub source code or local files for development and testing. To build the image of a component from GitHub source code, you need to leave the image field empty and set buildFrom to remote. To build PD, TiKV or TiDB images from the locally compiled binary file, you need to leave the image field empty, set buildFrom to local and copy the compiled binary file to the corresponding pd/bin/pd-server, tikv/bin/tikv-server, tidb/bin/tidb-server. To build the tidb-vision image from local, you need to leave the image field empty, set buildFrom to local and copy the tidb-vision project to tidb-vision/tidb-vision. Generate the docker-compose.yml file.helm template -f values.yaml compose > generated-docker-compose.yml Create and start the cluster using the generated docker-compose.yml file.docker-compose -f generated-docker-compose.yml pull # Get the latest Docker images docker-compose -f generated-docker-compose.yml up -d Access the cluster.mysql -h 127.0.0.1 -P 4000 -u root Access the Grafana monitoring interface: Default address: http://localhost:3000 Default account name: admin Default password: admin If tidb-vision is enabled, you can access the cluster data visualization interface: http://localhost:8010. Access the Spark shell and load TiSpark Insert some sample data to the TiDB cluster:$ docker-compose exec tispark-master bash $ cd /opt/spark/data/tispark-sample-data $ mysql -h tidb -P 4000 -u root < dss.ddl After the sample data is loaded into the TiDB cluster, you can access the Spark shell using docker-compose exec tispark-master /opt/spark/bin/spark-shell.$ docker-compose exec tispark-master /opt/spark/bin/spark-shell ... Spark context available as 'sc' (master = local[*], app id = local-1527045927617). Spark session available as 'spark'. Welcome to ____ __ / __/__ ___ _____/ /__ _ / _ / _ `/ __/ '_/ /___/ .__/_,_/_/ /_/_ version 2.1.1 /_/ Using Scala version 2.11.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_172) Type in expressions to have them evaluated. Type :help for more information. scala> import org.apache.spark.sql.TiContext ... scala> val ti = new TiContext(spark) ... scala> ti.tidbMapDatabase("TPCH_001") ... scala> spark.sql("select count(*) from lineitem").show +--------+ |count(1)| +--------+ | 60175| +--------+ You can also access Spark with Python or R using the following commands:docker-compose exec tispark-master /opt/spark/bin/pyspark docker-compose exec tispark-master /opt/spark/bin/sparkR For more details about TiSpark, see here.Here is a 5-minute tutorial for macOS users that shows how to spin up a standard TiDB cluster using Docker Compose on your local computer."}, {"url": "https://pingcap.com/docs/v1.0/op-guide/docker-deployment/", "title": "TiDB Docker Deployment", "content": " Docker Deployment This page shows you how to manually deploy a multi-node TiDB cluster on multiple machines using Docker.To learn more, see TiDB architecture and Software and Hardware Requirements.Preparation Before you start, make sure that you have: Installed the latest version of Docker Pulled the latest images of TiDB, TiKV and PD from Docker Hub. If not, pull the images using the following commands:docker pull pingcap/tidb:latest docker pull pingcap/tikv:latest docker pull pingcap/pd:latest Multi nodes deployment Assume we have 6 machines with the following details: Host Name IP Services Data Path host1 192.168.1.101 PD1 & TiDB /data host2 192.168.1.102 PD2 /data host3 192.168.1.103 PD3 /data host4 192.168.1.104 TiKV1 /data host5 192.168.1.105 TiKV2 /data host6 192.168.1.106 TiKV3 /data 1. Start PD Start PD1 on the host1docker run -d --name pd1 -p 2379:2379 -p 2380:2380 -v /etc/localtime:/etc/localtime:ro -v /data:/data pingcap/pd:latest --name="pd1" --data-dir="/data/pd1" --client-urls="http://0.0.0.0:2379" --advertise-client-urls="http://192.168.1.101:2379" --peer-urls="http://0.0.0.0:2380" --advertise-peer-urls="http://192.168.1.101:2380" --initial-cluster="pd1=http://192.168.1.101:2380,pd2=http://192.168.1.102:2380,pd3=http://192.168.1.103:2380" Start PD2 on the host2docker run -d --name pd2 -p 2379:2379 -p 2380:2380 -v /etc/localtime:/etc/localtime:ro -v /data:/data pingcap/pd:latest --name="pd2" --data-dir="/data/pd2" --client-urls="http://0.0.0.0:2379" --advertise-client-urls="http://192.168.1.102:2379" --peer-urls="http://0.0.0.0:2380" --advertise-peer-urls="http://192.168.1.102:2380" --initial-cluster="pd1=http://192.168.1.101:2380,pd2=http://192.168.1.102:2380,pd3=http://192.168.1.103:2380" Start PD3 on the host3docker run -d --name pd3 -p 2379:2379 -p 2380:2380 -v /etc/localtime:/etc/localtime:ro -v /data:/data pingcap/pd:latest --name="pd3" --data-dir="/data/pd3" --client-urls="http://0.0.0.0:2379" --advertise-client-urls="http://192.168.1.103:2379" --peer-urls="http://0.0.0.0:2380" --advertise-peer-urls="http://192.168.1.103:2380" --initial-cluster="pd1=http://192.168.1.101:2380,pd2=http://192.168.1.102:2380,pd3=http://192.168.1.103:2380" 2. Start TiKV Start TiKV1 on the host4docker run -d --name tikv1 -p 20160:20160 -v /etc/localtime:/etc/localtime:ro -v /data:/data pingcap/tikv:latest --addr="0.0.0.0:20160" --advertise-addr="192.168.1.104:20160" --data-dir="/data/tikv1" --pd="192.168.1.101:2379,192.168.1.102:2379,192.168.1.103:2379" Start TiKV2 on the host5docker run -d --name tikv2 -p 20160:20160 -v /etc/localtime:/etc/localtime:ro -v /data:/data pingcap/tikv:latest --addr="0.0.0.0:20160" --advertise-addr="192.168.1.105:20160" --data-dir="/data/tikv2" --pd="192.168.1.101:2379,192.168.1.102:2379,192.168.1.103:2379" Start TiKV3 on the host6docker run -d --name tikv3 -p 20160:20160 -v /etc/localtime:/etc/localtime:ro -v /data:/data pingcap/tikv:latest --addr="0.0.0.0:20160" --advertise-addr="192.168.1.106:20160" --data-dir="/data/tikv3" --pd="192.168.1.101:2379,192.168.1.102:2379,192.168.1.103:2379" 3. Start TiDB Start TiDB on the host1docker run -d --name tidb -p 4000:4000 -p 10080:10080 -v /etc/localtime:/etc/localtime:ro pingcap/tidb:latest --store=tikv --path="192.168.1.101:2379,192.168.1.102:2379,192.168.1.103:2379" 4. Use the MySQL client to connect to TiDB Install the MySQL client on host1 and run:$ mysql -h 127.0.0.1 -P 4000 -u root -D test mysql> show databases; +--------------------+ | Database | +--------------------+ | INFORMATION_SCHEMA | | PERFORMANCE_SCHEMA | | mysql | | test | +--------------------+ 4 rows in set (0.00 sec) How to customize the configuration file The TiKV and PD can be started with a specified configuration file, which includes some advanced parameters, for the performance tuning.Assume that the path to configuration file of PD and TiKV on the host is /path/to/config/pd.toml and /path/to/config/tikv.tomlYou can start TiKV and PD as follows:docker run -d --name tikv1 -p 20160:20160 -v /etc/localtime:/etc/localtime:ro -v /data:/data -v /path/to/config/tikv.toml:/tikv.toml:ro pingcap/tikv:latest --addr="0.0.0.0:20160" --advertise-addr="192.168.1.104:20160" --data-dir="/data/tikv1" --pd="192.168.1.101:2379,192.168.1.102:2379,192.168.1.103:2379" --config="/tikv.toml"docker run -d --name pd1 -p 2379:2379 -p 2380:2380 -v /etc/localtime:/etc/localtime:ro -v /data:/data -v /path/to/config/pd.toml:/pd.toml:ro pingcap/pd:latest --name="pd1" --data-dir="/data/pd1" --client-urls="http://0.0.0.0:2379" --advertise-client-urls="http://192.168.1.101:2379" --peer-urls="http://0.0.0.0:2380" --advertise-peer-urls="http://192.168.1.101:2380" --initial-cluster="pd1=http://192.168.1.101:2380,pd2=http://192.168.1.102:2380,pd3=http://192.168.1.103:2380" --config="/pd.toml""}, {"url": "https://pingcap.com/docs-cn/op-guide/docker-deployment/", "title": "TiDB Docker 部署方案", "content": " TiDB Docker 部署方案 本文介绍如何使用 Docker 部署一个多节点的 TiDB 集群。 注:对于生产环境,不要使用 Docker 进行部署,而应使用 Ansible 部署 TiDB 集群。 环境准备 安装 Docker Docker 可以方便地在 Linux / Mac OS / Windows 平台安装,安装方法请参考 Docker 官方文档。拉取 TiDB 的 Docker 镜像 部署 TiDB 集群主要包括 3 个服务组件: TiDB TiKV PD 对应的最新 Docker 镜像可以通过 Docker 官方镜像仓库 获取:docker pull pingcap/tidb:latest docker pull pingcap/tikv:latest docker pull pingcap/pd:latest 部署一个多节点集群 假设我们打算在 6 台主机上部署一个 TiDB 集群: 主机名 IP 部署服务 数据盘挂载 host1 192.168.1.101 PD1 & TiDB /data host2 192.168.1.102 PD2 /data host3 192.168.1.103 PD3 /data host4 192.168.1.104 TiKV1 /data host5 192.168.1.105 TiKV2 /data host6 192.168.1.106 TiKV3 /data 启动 PD 登录 host1 执行:docker run -d --name pd1 -p 2379:2379 -p 2380:2380 -v /etc/localtime:/etc/localtime:ro -v /data:/data pingcap/pd:latest --name="pd1" --data-dir="/data/pd1" --client-urls="http://0.0.0.0:2379" --advertise-client-urls="http://192.168.1.101:2379" --peer-urls="http://0.0.0.0:2380" --advertise-peer-urls="http://192.168.1.101:2380" --initial-cluster="pd1=http://192.168.1.101:2380,pd2=http://192.168.1.102:2380,pd3=http://192.168.1.103:2380" 登录 host2 执行:docker run -d --name pd2 -p 2379:2379 -p 2380:2380 -v /etc/localtime:/etc/localtime:ro -v /data:/data pingcap/pd:latest --name="pd2" --data-dir="/data/pd2" --client-urls="http://0.0.0.0:2379" --advertise-client-urls="http://192.168.1.102:2379" --peer-urls="http://0.0.0.0:2380" --advertise-peer-urls="http://192.168.1.102:2380" --initial-cluster="pd1=http://192.168.1.101:2380,pd2=http://192.168.1.102:2380,pd3=http://192.168.1.103:2380" 登录 host3 执行:docker run -d --name pd3 -p 2379:2379 -p 2380:2380 -v /etc/localtime:/etc/localtime:ro -v /data:/data pingcap/pd:latest --name="pd3" --data-dir="/data/pd3" --client-urls="http://0.0.0.0:2379" --advertise-client-urls="http://192.168.1.103:2379" --peer-urls="http://0.0.0.0:2380" --advertise-peer-urls="http://192.168.1.103:2380" --initial-cluster="pd1=http://192.168.1.101:2380,pd2=http://192.168.1.102:2380,pd3=http://192.168.1.103:2380" 启动 TiKV 登录 host4 执行:docker run -d --name tikv1 -p 20160:20160 --ulimit nofile=1000000:1000000 -v /etc/localtime:/etc/localtime:ro -v /data:/data pingcap/tikv:latest --addr="0.0.0.0:20160" --advertise-addr="192.168.1.104:20160" --data-dir="/data/tikv1" --pd="192.168.1.101:2379,192.168.1.102:2379,192.168.1.103:2379" 登录 host5 执行:docker run -d --name tikv2 -p 20160:20160 --ulimit nofile=1000000:1000000 -v /etc/localtime:/etc/localtime:ro -v /data:/data pingcap/tikv:latest --addr="0.0.0.0:20160" --advertise-addr="192.168.1.105:20160" --data-dir="/data/tikv2" --pd="192.168.1.101:2379,192.168.1.102:2379,192.168.1.103:2379" 登录 host6 执行:docker run -d --name tikv3 -p 20160:20160 --ulimit nofile=1000000:1000000 -v /etc/localtime:/etc/localtime:ro -v /data:/data pingcap/tikv:latest --addr="0.0.0.0:20160" --advertise-addr="192.168.1.106:20160" --data-dir="/data/tikv3" --pd="192.168.1.101:2379,192.168.1.102:2379,192.168.1.103:2379" 启动 TiDB 登录 host1 执行:docker run -d --name tidb -p 4000:4000 -p 10080:10080 -v /etc/localtime:/etc/localtime:ro pingcap/tidb:latest --store=tikv --path="192.168.1.101:2379,192.168.1.102:2379,192.168.1.103:2379" 使用 MySQL 标准客户端连接 TiDB 测试 登录 host1 并确保已安装 MySQL 命令行客户端,执行:$ mysql -h 127.0.0.1 -P 4000 -u root -D test mysql> show databases; +--------------------+ | Database | +--------------------+ | INFORMATION_SCHEMA | | PERFORMANCE_SCHEMA | | mysql | | test | +--------------------+ 4 rows in set (0.00 sec) 如何自定义配置文件 TiKV 和 PD 可以通过指定配置文件的方式来加载更加丰富的启动参数,用于性能调优。假定配置文件在宿主机上的存放路径 /path/to/config/pd.toml 和 /path/to/config/tikv.toml。启动 Docker 时需要调整相应的启动参数,以 tikv1 和 pd1 为例:docker run -d --name tikv1 -p 20160:20160 -v /etc/localtime:/etc/localtime:ro -v /data:/data -v /path/to/config/tikv.toml:/tikv.toml:ro pingcap/tikv:latest --addr="0.0.0.0:20160" --advertise-addr="192.168.1.104:20160" --data-dir="/data/tikv1" --pd="192.168.1.101:2379,192.168.1.102:2379,192.168.1.103:2379" --config="/tikv.toml"docker run -d --name pd1 -p 2379:2379 -p 2380:2380 -v /etc/localtime:/etc/localtime:ro -v /data:/data -v /path/to/config/pd.toml:/pd.toml:ro pingcap/pd:latest --name="pd1" --data-dir="/data/pd1" --client-urls="http://0.0.0.0:2379" --advertise-client-urls="http://192.168.1.101:2379" --peer-urls="http://0.0.0.0:2380" --advertise-peer-urls="http://192.168.1.101:2380" --initial-cluster="pd1=http://192.168.1.101:2380,pd2=http://192.168.1.102:2380,pd3=http://192.168.1.103:2380" --config="/pd.toml""}, {"url": "https://pingcap.com/docs-cn/v1.0/op-guide/docker-deployment/", "title": "TiDB Docker 部署方案", "content": " TiDB Docker 部署方案 本篇将展示如何在多台主机上使用 Docker 部署一个 TiDB 集群。阅读本章前,请先确保阅读 TiDB 整体架构 及 部署建议。环境准备 安装 Docker Docker 可以方便地在 Linux / Mac OS / Windows 平台安装,安装方法请参考 Docker 官方文档。拉取 TiDB 的 Docker 镜像 部署 TiDB 集群主要包括 3 个服务组件: TiDB TiKV PD 对应的最新 Docker 镜像可以通过 Docker 官方镜像仓库 获取:docker pull pingcap/tidb:latest docker pull pingcap/tikv:latest docker pull pingcap/pd:latest 部署一个多节点集群 假设我们打算在 6 台主机上部署一个 TiDB 集群: 主机名 IP 部署服务 数据盘挂载 host1 192.168.1.101 PD1 & TiDB /data host2 192.168.1.102 PD2 /data host3 192.168.1.103 PD3 /data host4 192.168.1.104 TiKV1 /data host5 192.168.1.105 TiKV2 /data host6 192.168.1.106 TiKV3 /data 启动 PD 登录 host1 执行:docker run -d --name pd1 -p 2379:2379 -p 2380:2380 -v /etc/localtime:/etc/localtime:ro -v /data:/data pingcap/pd:latest --name="pd1" --data-dir="/data/pd1" --client-urls="http://0.0.0.0:2379" --advertise-client-urls="http://192.168.1.101:2379" --peer-urls="http://0.0.0.0:2380" --advertise-peer-urls="http://192.168.1.101:2380" --initial-cluster="pd1=http://192.168.1.101:2380,pd2=http://192.168.1.102:2380,pd3=http://192.168.1.103:2380" 登录 host2 执行:docker run -d --name pd2 -p 2379:2379 -p 2380:2380 -v /etc/localtime:/etc/localtime:ro -v /data:/data pingcap/pd:latest --name="pd2" --data-dir="/data/pd2" --client-urls="http://0.0.0.0:2379" --advertise-client-urls="http://192.168.1.102:2379" --peer-urls="http://0.0.0.0:2380" --advertise-peer-urls="http://192.168.1.102:2380" --initial-cluster="pd1=http://192.168.1.101:2380,pd2=http://192.168.1.102:2380,pd3=http://192.168.1.103:2380" 登录 host3 执行:docker run -d --name pd3 -p 2379:2379 -p 2380:2380 -v /etc/localtime:/etc/localtime:ro -v /data:/data pingcap/pd:latest --name="pd3" --data-dir="/data/pd3" --client-urls="http://0.0.0.0:2379" --advertise-client-urls="http://192.168.1.103:2379" --peer-urls="http://0.0.0.0:2380" --advertise-peer-urls="http://192.168.1.103:2380" --initial-cluster="pd1=http://192.168.1.101:2380,pd2=http://192.168.1.102:2380,pd3=http://192.168.1.103:2380" 启动 TiKV 登录 host4 执行:docker run -d --name tikv1 -p 20160:20160 --ulimit nofile=1000000:1000000 -v /etc/localtime:/etc/localtime:ro -v /data:/data pingcap/tikv:latest --addr="0.0.0.0:20160" --advertise-addr="192.168.1.104:20160" --data-dir="/data/tikv1" --pd="192.168.1.101:2379,192.168.1.102:2379,192.168.1.103:2379" 登录 host5 执行:docker run -d --name tikv2 -p 20160:20160 --ulimit nofile=1000000:1000000 -v /etc/localtime:/etc/localtime:ro -v /data:/data pingcap/tikv:latest --addr="0.0.0.0:20160" --advertise-addr="192.168.1.105:20160" --data-dir="/data/tikv2" --pd="192.168.1.101:2379,192.168.1.102:2379,192.168.1.103:2379" 登录 host6 执行:docker run -d --name tikv3 -p 20160:20160 --ulimit nofile=1000000:1000000 -v /etc/localtime:/etc/localtime:ro -v /data:/data pingcap/tikv:latest --addr="0.0.0.0:20160" --advertise-addr="192.168.1.106:20160" --data-dir="/data/tikv3" --pd="192.168.1.101:2379,192.168.1.102:2379,192.168.1.103:2379" 启动 TiDB 登录 host1 执行:docker run -d --name tidb -p 4000:4000 -p 10080:10080 -v /etc/localtime:/etc/localtime:ro pingcap/tidb:latest --store=tikv --path="192.168.1.101:2379,192.168.1.102:2379,192.168.1.103:2379" 使用 MySQL 标准客户端连接 TiDB 测试 登录 host1 并确保已安装 MySQL 命令行客户端,执行:$ mysql -h 127.0.0.1 -P 4000 -u root -D test mysql> show databases; +--------------------+ | Database | +--------------------+ | INFORMATION_SCHEMA | | PERFORMANCE_SCHEMA | | mysql | | test | +--------------------+ 4 rows in set (0.00 sec) 如何自定义配置文件 TiKV 和 PD 可以通过指定配置文件的方式来加载更加丰富的启动参数,用于性能调优。假定配置文件在宿主机上的存放路径 /path/to/config/pd.toml 和 /path/to/config/tikv.toml。启动 Docker 时需要调整相应的启动参数,以 tikv1 和 pd1 为例:docker run -d --name tikv1 -p 20160:20160 -v /etc/localtime:/etc/localtime:ro -v /data:/data -v /path/to/config/tikv.toml:/tikv.toml:ro pingcap/tikv:latest --addr="0.0.0.0:20160" --advertise-addr="192.168.1.104:20160" --data-dir="/data/tikv1" --pd="192.168.1.101:2379,192.168.1.102:2379,192.168.1.103:2379" --config="/tikv.toml"docker run -d --name pd1 -p 2379:2379 -p 2380:2380 -v /etc/localtime:/etc/localtime:ro -v /data:/data -v /path/to/config/pd.toml:/pd.toml:ro pingcap/pd:latest --name="pd1" --data-dir="/data/pd1" --client-urls="http://0.0.0.0:2379" --advertise-client-urls="http://192.168.1.101:2379" --peer-urls="http://0.0.0.0:2380" --advertise-peer-urls="http://192.168.1.101:2380" --initial-cluster="pd1=http://192.168.1.101:2380,pd2=http://192.168.1.102:2380,pd3=http://192.168.1.103:2380" --config="/pd.toml""}, {"url": "https://pingcap.com/docs-cn/v2.0/op-guide/docker-deployment/", "title": "TiDB Docker 部署方案", "content": " TiDB Docker 部署方案 本篇将展示如何在多台主机上使用 Docker 部署一个 TiDB 集群。阅读本章前,请先确保阅读 TiDB 整体架构 及 部署建议。环境准备 安装 Docker Docker 可以方便地在 Linux / Mac OS / Windows 平台安装,安装方法请参考 Docker 官方文档。拉取 TiDB 的 Docker 镜像 部署 TiDB 集群主要包括 3 个服务组件: TiDB TiKV PD 对应的最新 Docker 镜像可以通过 Docker 官方镜像仓库 获取:docker pull pingcap/tidb:latest docker pull pingcap/tikv:latest docker pull pingcap/pd:latest 部署一个多节点集群 假设我们打算在 6 台主机上部署一个 TiDB 集群: 主机名 IP 部署服务 数据盘挂载 host1 192.168.1.101 PD1 & TiDB /data host2 192.168.1.102 PD2 /data host3 192.168.1.103 PD3 /data host4 192.168.1.104 TiKV1 /data host5 192.168.1.105 TiKV2 /data host6 192.168.1.106 TiKV3 /data 启动 PD 登录 host1 执行:docker run -d --name pd1 -p 2379:2379 -p 2380:2380 -v /etc/localtime:/etc/localtime:ro -v /data:/data pingcap/pd:latest --name="pd1" --data-dir="/data/pd1" --client-urls="http://0.0.0.0:2379" --advertise-client-urls="http://192.168.1.101:2379" --peer-urls="http://0.0.0.0:2380" --advertise-peer-urls="http://192.168.1.101:2380" --initial-cluster="pd1=http://192.168.1.101:2380,pd2=http://192.168.1.102:2380,pd3=http://192.168.1.103:2380" 登录 host2 执行:docker run -d --name pd2 -p 2379:2379 -p 2380:2380 -v /etc/localtime:/etc/localtime:ro -v /data:/data pingcap/pd:latest --name="pd2" --data-dir="/data/pd2" --client-urls="http://0.0.0.0:2379" --advertise-client-urls="http://192.168.1.102:2379" --peer-urls="http://0.0.0.0:2380" --advertise-peer-urls="http://192.168.1.102:2380" --initial-cluster="pd1=http://192.168.1.101:2380,pd2=http://192.168.1.102:2380,pd3=http://192.168.1.103:2380" 登录 host3 执行:docker run -d --name pd3 -p 2379:2379 -p 2380:2380 -v /etc/localtime:/etc/localtime:ro -v /data:/data pingcap/pd:latest --name="pd3" --data-dir="/data/pd3" --client-urls="http://0.0.0.0:2379" --advertise-client-urls="http://192.168.1.103:2379" --peer-urls="http://0.0.0.0:2380" --advertise-peer-urls="http://192.168.1.103:2380" --initial-cluster="pd1=http://192.168.1.101:2380,pd2=http://192.168.1.102:2380,pd3=http://192.168.1.103:2380" 启动 TiKV 登录 host4 执行:docker run -d --name tikv1 -p 20160:20160 --ulimit nofile=1000000:1000000 -v /etc/localtime:/etc/localtime:ro -v /data:/data pingcap/tikv:latest --addr="0.0.0.0:20160" --advertise-addr="192.168.1.104:20160" --data-dir="/data/tikv1" --pd="192.168.1.101:2379,192.168.1.102:2379,192.168.1.103:2379" 登录 host5 执行:docker run -d --name tikv2 -p 20160:20160 --ulimit nofile=1000000:1000000 -v /etc/localtime:/etc/localtime:ro -v /data:/data pingcap/tikv:latest --addr="0.0.0.0:20160" --advertise-addr="192.168.1.105:20160" --data-dir="/data/tikv2" --pd="192.168.1.101:2379,192.168.1.102:2379,192.168.1.103:2379" 登录 host6 执行:docker run -d --name tikv3 -p 20160:20160 --ulimit nofile=1000000:1000000 -v /etc/localtime:/etc/localtime:ro -v /data:/data pingcap/tikv:latest --addr="0.0.0.0:20160" --advertise-addr="192.168.1.106:20160" --data-dir="/data/tikv3" --pd="192.168.1.101:2379,192.168.1.102:2379,192.168.1.103:2379" 启动 TiDB 登录 host1 执行:docker run -d --name tidb -p 4000:4000 -p 10080:10080 -v /etc/localtime:/etc/localtime:ro pingcap/tidb:latest --store=tikv --path="192.168.1.101:2379,192.168.1.102:2379,192.168.1.103:2379" 使用 MySQL 标准客户端连接 TiDB 测试 登录 host1 并确保已安装 MySQL 命令行客户端,执行:$ mysql -h 127.0.0.1 -P 4000 -u root -D test mysql> show databases; +--------------------+ | Database | +--------------------+ | INFORMATION_SCHEMA | | PERFORMANCE_SCHEMA | | mysql | | test | +--------------------+ 4 rows in set (0.00 sec) 如何自定义配置文件 TiKV 和 PD 可以通过指定配置文件的方式来加载更加丰富的启动参数,用于性能调优。假定配置文件在宿主机上的存放路径 /path/to/config/pd.toml 和 /path/to/config/tikv.toml。启动 Docker 时需要调整相应的启动参数,以 tikv1 和 pd1 为例:docker run -d --name tikv1 -p 20160:20160 -v /etc/localtime:/etc/localtime:ro -v /data:/data -v /path/to/config/tikv.toml:/tikv.toml:ro pingcap/tikv:latest --addr="0.0.0.0:20160" --advertise-addr="192.168.1.104:20160" --data-dir="/data/tikv1" --pd="192.168.1.101:2379,192.168.1.102:2379,192.168.1.103:2379" --config="/tikv.toml"docker run -d --name pd1 -p 2379:2379 -p 2380:2380 -v /etc/localtime:/etc/localtime:ro -v /data:/data -v /path/to/config/pd.toml:/pd.toml:ro pingcap/pd:latest --name="pd1" --data-dir="/data/pd1" --client-urls="http://0.0.0.0:2379" --advertise-client-urls="http://192.168.1.101:2379" --peer-urls="http://0.0.0.0:2380" --advertise-peer-urls="http://192.168.1.101:2380" --initial-cluster="pd1=http://192.168.1.101:2380,pd2=http://192.168.1.102:2380,pd3=http://192.168.1.103:2380" --config="/pd.toml""}, {"url": "https://pingcap.com/docs-cn/FAQ/", "title": "TiDB FAQ", "content": " FAQ 一、 TiDB 介绍、架构、原理 1.1 TiDB 介绍及整体架构 1.1.1 TiDB 整体架构 https://pingcap.com/docs-cn/overview/1.1.2 TiDB 是什么? TiDB 是一个分布式 NewSQL 数据库。它支持水平弹性扩展、ACID 事务、标准 SQL、MySQL 语法和 MySQL 协议,具有数据强一致的高可用特性,是一个不仅适合 OLTP 场景还适合 OLAP 场景的混合数据库。1.1.3 TiDB 是基于 MySQL 开发的吗? 不是,虽然 TiDB 支持 MySQL 语法和协议,但是 TiDB 是由 PingCAP 团队完全自主开发的产品。1.1.4 TiDB、TiKV、Placement Driver (PD) 主要作用? TiDB 是 Server 计算层,主要负责 SQL 的解析、制定查询计划、生成执行器。 TiKV 是分布式 Key-Value 存储引擎,用来存储真正的数据,简而言之,TiKV 是 TiDB 的存储引擎。 PD 是 TiDB 集群的管理组件,负责存储 TiKV 的元数据,同时也负责分配时间戳以及对 TiKV 做负载均衡调度。 1.1.5 TiDB 易用性如何? TiDB 使用起来很简单,可以将 TiDB 集群当成 MySQL 来用,你可以将 TiDB 用在任何以 MySQL 作为后台存储服务的应用中,并且基本上不需要修改应用代码,同时你可以用大部分流行的 MySQL 管理工具来管理 TiDB。1.1.6 TiDB 和 MySQL 兼容性如何? TiDB 目前还不支持触发器、存储过程、自定义函数、外键,除此之外,TiDB 支持绝大部分 MySQL 5.7 的语法。详情参见与 MySQL 兼容性对比。1.1.7 TiDB 具备高可用的特性吗? TiDB 天然具备高可用特性,TiDB、TiKV、PD 这三个组件都能容忍部分实例失效,不影响整个集群的可用性。具体见 TiDB 高可用性。1.1.8 TiDB 数据是强一致的吗? TiDB 使用 Raft 在多个副本之间做数据同步,从而保证数据的强一致,单个副本失效时,不影响数据的可靠性。1.1.9 TiDB 支持分布式事务吗? TiDB 支持 ACID 分布式事务,事务模型是以 Google 的 Percolator 模型为基础,并做了一些优化。这个模型需要一个时间戳分配器,分配唯一且递增的时间戳。在 TiDB 集群中,PD 承担时间戳分配器的角色。1.1.10 TiDB 支持哪些编程语言? 只要支持 MySQL Client/Driver 的编程语言,都可以直接使用 TiDB。1.1.11 TiDB 是否支持其他存储引擎? 是的,除了 TiKV 之外,TiDB 还支持一些流行的单机存储引擎,比如 GolevelDB、RocksDB、BoltDB 等。如果一个存储引擎是支持事务的 KV 引擎,并且能提供一个满足 TiDB 接口要求的 Client,即可接入 TiDB。1.1.12 官方有没有三中心跨机房多活部署的推荐方案? 从 TiDB 架构来讲,支持真正意义上的跨中心异地多活,从操作层面讲,依赖数据中心之间的网络延迟和稳定性,一般建议延迟在 5ms 以下,目前我们已经有相似客户方案,具体请咨询官方 info@pingcap.com。1.1.13 除了官方文档,有没有其他 TiDB 知识获取途径? 目前官方文档是获取 TiDB 相关知识最主要、最及时的发布途径。除此之外,我们也有一些技术沟通群,如有需求可发邮件至 info@pingcap.com 获取。1.1.14 TiDB 对哪些 MySQL variables 兼容? 详细可参考系统变量。1.1.15 TiDB 是否支持 select for update? 支持,但语义上和 MySQL 有区别,TiDB 是分布式数据库,采用的乐观锁机制,也就说 select for update 不在事务开启就锁住数据,而是其他事务在提交的时候进行冲突检查,如有冲突,会进行回滚。1.1.16 TiDB 的 codec 能保证 UTF8 的字符串是 memcomparable 的吗?我们的 key 需要支持 UTF8,有什么编码建议吗? TiDB 字符集默认就是 UTF8 而且目前只支持 UTF8,字符串就是 memcomparable 格式的。1.1.17 TiDB 用户名长度限制? 在 TiDB 中用户名最长为 32 字符。1.1.18 一个事务中的语句数量最大是多少? 一个事务中的语句数量,默认限制最大为 5000 条。1.1.19 TiDB 是否支持 XA? 虽然 TiDB 的 JDBC 驱动用的就是 MySQL JDBC(Connector / J),但是当使用 Atomikos 的时候,数据源要配置成类似这样的配置:type="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource"。MySQL JDBC XADataSource 连接 TiDB 的模式目前是不支持的。MySQL JDBC 中配置好的 XADataSource 模式,只对 MySQL 数据库起作用(DML 去修改 redo 等)。Atomikos 配好两个数据源后,JDBC 驱动都要设置成 XA 模式,然后 Atomikos 在操作 TM 和 RM(DB)的时候,会通过数据源的配置,发起带有 XA 指令到 JDBC 层,JDBC 层 XA 模式启用的情况下,会对 InnoDB(如果是 MySQL 的话)下发操作一连串 XA 逻辑的动作,包括 DML 去变更 redo log 等,就是两阶段递交的那些操作。TiDB 目前的引擎版本中,没有对上层应用层 JTA / XA 的支持,不解析这些 Atomikos 发过来的 XA 类型的操作。MySQL 是单机数据库,只能通过 XA 来满足跨数据库事务,而 TiDB 本身就通过 Google 的 Percolator 事务模型支持分布式事务,性能稳定性比 XA 要高出很多,所以不会也不需要支持 XA。1.1.20 show processlist 是否显示系统进程号? TiDB 的 show processlist 与 MySQL 的 show processlist 显示内容基本一样,不会显示系统进程号,而 ID 表示当前的 session ID。其中 TiDB 的 show processlist 和 MySQL 的 show processlist 区别如下:1)由于 TiDB 是分布式数据库,tidb-server 实例是无状态的 SQL 解析和执行引擎(详情可参考 TiDB 整体架构),用户使用 MySQL 客户端登录的是哪个 tidb-server,show processlist 就会显示当前连接的这个 tidb-server 中执行的 session 列表,不是整个集群中运行的全部 session 列表;而 MySQL 是单机数据库,show processlist 列出的是当前整个 MySQL 数据库的全部执行 SQL 列表。2)TiDB 的 show processlist 显示内容比起 MySQL 来讲,多了一个当前 session 使用内存的估算值(单位 Byte)。1.1.21 如何修改用户名密码和权限? TiDB 作为分布式数据库,在 TiDB 中修改用户密码建议使用 set password for 'root'@'%' = '0101001'; 或 alter 方法,不推荐使用 update mysql.user 的方法进行,这种方法可能会造成其它节点刷新不及时的情况。修改权限也一样,都建议采用官方的标准语法。详情可参考 TiDB 用户账户管理。1.1.22 TiDB 中,为什么出现后插入数据的自增 ID 反而小? TiDB 的自增 ID (AUTO_INCREMENT) 只保证自增且唯一,并不保证连续分配。TiDB 目前采用批量分配的方式,所以如果在多台 TiDB 上同时插入数据,分配的自增 ID 会不连续。当多个线程并发往不同的 tidb-server 插入数据的时候,有可能会出现后插入的数据自增 ID 小的情况。此外,TiDB允许给整型类型的字段指定 AUTO_INCREMENT,且一个表只允许一个属性为 AUTO_INCREMENT 的字段。详情可参考数据定义语句。1.1.23 sql_mode 默认除了通过命令 set 修改,配置文件怎么修改? TiDB 的 sql_mode 与 MySQL 的 sql_mode 设置方法有一些差别,TiDB 不支持配置文件配置设置数据库的 sql_mode,而只能使用 set 命令去设置,具体方法为:set @@global.sql_mode = 'STRICT_TRANS_TABLES';。1.1.24 TiDB 支持哪些认证协议,过程是怎样的? 这一层跟 MySQL 一样,走的 SASL 认证协议,用于用户登陆认证,对密码的处理流程。客户端连接 TiDB 的时候,走的是 challenge-response(挑战-应答)的认证模式,过程如下:第一步:客户端连接服务器;第二步:服务器发送随机字符串 challenge 给客户端;第三步:客户端发送 username + response 给服务器;第四步:服务器验证 response。1.2 TiDB 原理 1.2.1 存储 TiKV 1.2.1.1 TiKV 详细解读 http://t.cn/RTKRRWv1.2.2 计算 TiDB 1.2.2.1 TiDB 详细解读 http://t.cn/RTKRkBh1.2.3 调度 PD 1.2.3.1 PD 详细解读 http://t.cn/RTKEZ0U二、安装部署升级 2.1 环境准备 2.1.1 操作系统版本要求 Linux 操作系统平台 版本 Red Hat Enterprise Linux 7.3 及以上 CentOS 7.3 及以上 Oracle Enterprise Linux 7.3 及以上 2.1.1.1 为什么要在 CentOS 7 上部署 TiDB 集群? TiDB 作为一款开源分布式 NewSQL 数据库,可以很好的部署和运行在 Intel 架构服务器环境及主流虚拟化环境,并支持绝大多数的主流硬件网络,作为一款高性能数据库系统,TiDB 支持主流的 Linux 操作系统环境,具体可以参考 TiDB 的官方部署要求。其中 TiDB 在 CentOS 7.3 的环境下进行大量的测试,同时也有很多这个操作系统的部署最佳实践,因此,我们推荐客户在部署 TiDB 的时候使用 CentOS 7.3+ 以上的Linux 操作系统。2.1.2 硬件要求 TiDB 支持部署和运行在 Intel x86-64 架构的 64 位通用硬件服务器平台。对于开发,测试,及生产环境的服务器硬件配置有以下要求和建议:2.1.2.1 开发及测试环境 组件 CPU 内存 本地存储 网络 实例数量(最低要求) TiDB 8核+ 16 GB+ SAS, 200 GB+ 千兆网卡 1(可与 PD 同机器) PD 8核+ 16 GB+ SAS, 200 GB+ 千兆网卡 1(可与 TiDB 同机器) TiKV 8核+ 32 GB+ SSD, 200 GB+ 千兆网卡 3 服务器总计 4 2.1.2.2 线上环境 组件 CPU 内存 硬盘类型 网络 实例数量(最低要求) TiDB 16核+ 48 GB+ SAS 万兆网卡(2块最佳) 2 PD 8核+ 16 GB+ SSD 万兆网卡(2块最佳) 3 TiKV 16核+ 48 GB+ SSD 万兆网卡(2块最佳) 3 监控 8核+ 16 GB+ SAS 千兆网卡 1 服务器总计 9 2.1.2.3 2 块网卡的目的是?万兆的目的是? 作为一个分布式集群,TiDB 对时间的要求还是比较高的,尤其是 PD 需要分发唯一的时间戳,如果 PD 时间不统一,如果有 PD 切换,将会等待更长的时间。2 块网卡可以做 bond,保证数据传输的稳定,万兆可以保证数据传输的速度,千兆网卡容易出现瓶颈,我们强烈建议使用万兆网卡。2.1.2.4 SSD 不做 RAID 是否可行? 资源可接受的话,我们建议做 RAID 10,如果资源有限,也可以不做 RAID。2.1.2.5 TiDB 集群各个组件的配置推荐? TiDB 需要 CPU 和内存比较好的机器,参考官网配置要求,如果后期需要开启 Binlog,根据业务量的评估和 GC 时间的要求,也需要本地磁盘大一点,不要求 SSD 磁盘; PD 里面存了集群元信息,会有频繁的读写请求,对磁盘 I/O 要求相对比较高,磁盘太差会影响整个集群性能,推荐 SSD 磁盘,空间不用太大。另外集群 Region 数量越多对 CPU、内存的要求越高; TiKV 对 CPU、内存、磁盘要求都比较高,一定要用 SSD 磁盘。 详情可参考 TiDB 软硬件环境需求。2.2 安装部署 2.2.1 Ansible 部署方式(强烈推荐) 详细可参考 TiDB Ansible 部署方案。2.2.1.1 为什么修改了 TiKV/PD 的 toml 配置文件,却没有生效? 这种情况一般是因为没有使用 --config 参数来指定配置文件(目前只会出现在 binary 部署的场景),TiKV/PD 会按默认值来设置。如果要使用配置文件,请设置 TiKV/PD 的 --config 参数。对于 TiKV 组件,修改配置后重启服务即可;对于 PD 组件,只会在第一次启动时读取配置文件,之后可以使用 pd-ctl 的方式来修改配置,详情可参考 https://pingcap.com/docs-cn/tools/pd-control/。2.2.1.2 TiDB 监控框架 Prometheus + Grafana 监控机器建议单独还是多台部署? 监控机建议单独部署。建议 CPU 8 core,内存 16 GB 以上,硬盘 500 GB 以上。2.2.1.3 有一部分监控信息显示不出来? 查看访问监控的机器时间跟集群内机器的时间差,如果比较大,更正时间后即可显示正常。2.2.1.4 supervise/svc/svstat 服务具体起什么作用? supervise 守护进程 svc 启停服务 svstat 查看进程状态 2.2.1.5 inventory.ini 变量参数解读 变量 含义 cluster_name 集群名称,可调整 tidb_version TiDB 版本,TiDB-Ansible 各分支默认已配置 deployment_method 部署方式,默认为 binary,可选 docker process_supervision 进程监管方式,默认为 systemd,可选 supervise timezone 修改部署目标机器时区,默认为 Asia/Shanghai, 可调整,与set_timezone 变量结合使用 set_timezone 默认为 True,即修改部署目标机器时区,关闭可修改为 False enable_elk 目前不支持,请忽略 enable_firewalld 开启防火墙,默认不开启 enable_ntpd 检测部署目标机器 NTP 服务,默认为 True,请勿关闭 machine_benchmark 检测部署目标机器磁盘 IOPS,默认为 True,请勿关闭 set_hostname 根据 IP 修改部署目标机器主机名,默认为 False enable_binlog 是否部署 pump 并开启 binlog,默认为 False,依赖 Kafka 集群,参见 zookeeper_addrs 变量 zookeeper_addrs binlog Kafka 集群的 zookeeper 地址 enable_slow_query_log TiDB 慢查询日志记录到单独文件({{ deploy_dir }}/log/tidb_slow_query.log),默认为 False,记录到 tidb 日志 deploy_without_tidb KV 模式,不部署 TiDB 服务,仅部署 PD、TiKV 及监控服务,请将 inventory.ini 文件中 tidb_servers 主机组 IP 设置为空。 2.2.2 TiDB 离线 Ansible 部署方案 首先这不是我们建议的方式,如果中控机没有外网,也可以通过离线 Ansible 部署方式,详情可参考 https://pingcap.com/docs-cn/op-guide/offline-ansible-deployment/。2.2.3 Docker Compose 快速构建集群(单机部署) 使用 docker-compose 在本地一键拉起一个集群,包括集群监控,还可以根据需求自定义各个组件的软件版本和实例个数,以及自定义配置文件,这种只限于开发环境,详细可参考官方文档。2.2.4 如何单独记录 TiDB 中的慢查询日志,如何定位慢查询 SQL? 1)TiDB 中,对慢查询的定义在 tidb-ansible 的 conf/tidb.yml 配置文件中,slow-threshold: 300,这个参数是配置慢查询记录阈值的,单位是 ms。慢查询日志默认记录到 tidb.log 中,如果希望生成单独的慢查询日志文件,修改 inventory.ini 配置文件的参数 enable_slow_query_log 为 True。如上配置修改之后,需要执行 ansible-playbook rolling_update.yml --tags=tidb,对 tidb-server 实例进行滚动升级,升级完成后,tidb-server 将在 tidb_slow_query.log 文件中记录慢查询日志。2)如果出现了慢查询,可以从 Grafana 监控定位到出现慢查询的 tidb-server 以及时间点,然后在对应节点查找日志中记录的 SQL 信息。2.2.5 首次部署 TiDB 集群时,没有配置 tikv 的 Label 信息,在后续如何添加配置 Label? TiDB 的 Label 设置是与集群的部署架构相关的,是集群部署中的重要内容,是 PD 进行全局管理和调度的依据。如果集群在初期部署过程中没有设置 Label,需要在后期对部署结构进行调整,就需要手动通过 PD 的管理工具 pd-ctl 来添加 location-labels 信息,例如:config set location-labels "zone, rack, host"(根据实际的 label 层级名字配置)。pd-ctl 的使用参考 PD Control 使用说明。2.2.6 为什么测试磁盘的 dd …"}, {"url": "https://pingcap.com/docs-cn/v1.0/FAQ/", "title": "TiDB FAQ", "content": " 一、 TiDB 介绍、架构、原理 1.1 TiDB 介绍及整体架构 1.1.1 TiDB 整体架构 https://pingcap.com/docs-cn/overview/1.1.2 TiDB 是什么? TiDB 是一个分布式 NewSQL 数据库。它支持水平弹性扩展、ACID 事务、标准 SQL、MySQL 语法和 MySQL 协议,具有数据强一致的高可用特性,是一个不仅适合 OLTP 场景还适合 OLAP 场景的混合数据库。1.1.3 TiDB 是基于 MySQL 开发的吗? 不是,虽然 TiDB 支持 MySQL 语法和协议,但是 TiDB 是由 PingCAP 团队完全自主开发的产品。1.1.4 TiDB、TiKV、Placement Driver (PD) 主要作用? TiDB 是 Server 计算层,主要负责 SQL 的解析、制定查询计划、生成执行器。 TiKV 是分布式 Key-Value 存储引擎,用来存储真正的数据,简而言之,TiKV 是 TiDB 的存储引擎。 PD 是 TiDB 集群的管理组件,负责存储 TiKV 的元数据,同时也负责分配时间戳以及对 TiKV 做负载均衡调度。 1.1.5 TiDB 易用性如何? TiDB 使用起来很简单,可以将 TiDB 集群当成 MySQL 来用,你可以将 TiDB 用在任何以 MySQL 作为后台存储服务的应用中,并且基本上不需要修改应用代码,同时你可以用大部分流行的 MySQL 管理工具来管理 TiDB。1.1.6 TiDB 和 MySQL 兼容性如何? TiDB 目前还不支持触发器、存储过程、自定义函数、外键,除此之外,TiDB 支持绝大部分 MySQL 5.7 的语法。详情参见:与 MySQL 兼容性对比。1.1.7 TiDB 具备高可用的特性吗? TiDB 天然具备高可用特性,TiDB、TiKV、PD 这三个组件都能容忍部分实例失效,不影响整个集群的可用性。具体见 TiDB 高可用性。1.1.8 TiDB 数据是强一致的吗? TiDB 使用 Raft 在多个副本之间做数据同步,从而保证数据的强一致,单个副本失效时,不影响数据的可靠性。1.1.9 TiDB 支持分布式事务吗? TiDB 支持 ACID 分布式事务,事务模型是以 Google 的 Percolator 模型为基础,并做了一些优化。这个模型需要一个时间戳分配器,分配唯一且递增的时间戳。在 TiDB 集群中,PD 承担时间戳分配器的角色。1.1.10 TiDB 支持哪些编程语言? 只要支持 MySQL Client/Driver 的编程语言,都可以直接使用 TiDB。1.1.11 TiDB 是否支持其他存储引擎? 是的,除了 TiKV 之外,TiDB 还支持一些流行的单机存储引擎,比如 GolevelDB、RocksDB、BoltDB 等。如果一个存储引擎是支持事务的 KV 引擎,并且能提供一个满足 TiDB 接口要求的 Client,即可接入 TiDB。1.1.12 官方有没有三中心跨机房多活部署的推荐方案? 从 TiDB 架构来讲,支持真正意义上的跨中心异地多活,从操作层面讲,依赖数据中心之间的网络延迟和稳定性,一般建议延迟在 5ms 以下,目前我们已经有相似客户方案,具体请咨询官方: info@pingcap.com。1.1.13 除了官方文档,有没有其他 TiDB 知识获取途径? 目前 官方文档是获取 TiDB 相关知识最主要、最及时的发布途径。除此之外,我们也有一些技术沟通群,如有需求可发邮件至 info@pingcap.com 获取。1.1.14 TiDB 对那些 MySQL variables 兼容? 详细可参考:系统变量1.1.15 TiDB 是否支持 select for update 吗? 支持,但语义上和 MySQL 有区别,TiDB 是分布式数据库,采用的乐观锁机制,也就说 select for update 不在事务开启就锁住数据,而是其他事务在提交的时候进行冲突检查,如有冲突,会进行回滚。1.1.16 TiDB 的 codec 能保证 UTF8 的字符串是 memcomparable 的吗?我们的 key 需要支持 UTF8,有什么编码建议吗? TiDB 字符集默认就是 UTF8 而且目前只支持 UTF8,字符串就是 memcomparable 格式的。1.2 TiDB 原理 1.2.1 存储 TiKV 1.2.1.1 TiKV 详细解读 http://t.cn/RTKRRWv1.2.2 计算 TiDB 1.2.2.1 TiDB 详细解读 http://t.cn/RTKRkBh1.2.3 调度 PD 1.2.3.1 PD 详细解读 http://t.cn/RTKEZ0U二、安装部署升级 2.1 环境准备 2.1.1 操作系统版本要求 Linux 操作系统平台 版本 Red Hat Enterprise Linux 7.3 及以上 CentOS 7.3 及以上 Oracle Enterprise Linux 7.3 及以上 2.1.1.1 为什么要在 CentOS 7 上部署 TiDB 集群? TiDB 作为一款开源分布式 NewSQL 数据库,可以很好的部署和运行在 Intel 架构服务器环境及主流虚拟化环境,并支持绝大多数的主流硬件网络,作为一款高性能数据库系统,TiDB 支持主流的 Linux 操作系统环境,具体可以参考 TiDB 的官方部署要求。 其中 TiDB 在 CentOS 7.3 的环境下进行大量的测试,同时也有很多这个操作系统的部署最佳实践,因此,我们推荐客户在部署 TiDB 的时候使用 CentOS 7.3+ 以上的Linux 操作系统。2.1.2 硬件要求 TiDB 支持部署和运行在 Intel x86-64 架构的 64 位通用硬件服务器平台。对于开发,测试,及生产环境的服务器硬件配置有以下要求和建议:2.1.2.1 开发及测试环境 组件 CPU 内存 本地存储 网络 实例数量(最低要求) TiDB 8核+ 16 GB+ SAS, 200 GB+ 千兆网卡 1(可与 PD 同机器) PD 8核+ 16 GB+ SAS, 200 GB+ 千兆网卡 1(可与 TiDB 同机器) TiKV 8核+ 32 GB+ SSD, 200 GB+ 千兆网卡 3 服务器总计 4 2.1.2.2 线上环境 组件 CPU 内存 硬盘类型 网络 实例数量(最低要求) TiDB 16核+ 48 GB+ SAS 万兆网卡(2块最佳) 2 PD 8核+ 16 GB+ SSD 万兆网卡(2块最佳) 3 TiKV 16核+ 48 GB+ SSD 万兆网卡(2块最佳) 3 监控 8核+ 16 GB+ SAS 千兆网卡 1 服务器总计 9 2.1.2.3 2 块网卡的目的是?万兆的目的是? 作为一个分布式集群,TiDB 对时间的要求还是比较高的,尤其是 PD 需要分发唯一的时间戳,如果 PD 时间不统一,如果有 PD 切换,将会等待更长的时间。2 块网卡可以做 bond,保证数据传输的稳定,万兆可以保证数据传输的速度,千兆网卡容易出现瓶颈,我们强烈建议使用万兆网卡。2.1.2.4 SSD 不做 RAID 是否可行? 资源可接受的话,我们建议做 RAID 10,如果资源有限,也可以不做 RAID。2.2 安装部署 2.2.1 Ansible 部署方式(强烈推荐) 详细可参考:TiDB Ansible 部署方案2.2.1.1 为什么修改了 TiKV/PD 的 toml 配置文件,却没有生效? 这种情况一般是因为没有使用 --config 参数来指定配置文件(目前只会出现在 binary 部署的场景),TiKV/PD 会按默认值来设置。如果要使用配置文件,请设置 TiKV/PD 的 --config 参数。对于 TiKV 组件,修改配置后重启服务即可;对于 PD 组件,只会在第一次启动时读取配置文件,之后可以使用 pd-ctl 的方式来修改配置,详情可参考:https://pingcap.com/docs-cn/tools/pd-control/2.2.1.2 TiDB 监控框架 Prometheus + Grafana 监控机器建议单独还是多台部署? 监控机建议单独部署。建议 CPU 8 core,内存 16 GB 以上,硬盘 500 GB 以上。2.2.1.3 有一部分监控信息显示不出来? 查看访问监控的机器时间跟集群内机器的时间差,如果比较大,更正时间后即可显示正常。2.2.1.4 supervise/svc/svstat 服务具体起什么作用? supervise 守护进程 svc 启停服务 svstat 查看进程状态 2.2.1.5 inventory.ini 变量参数解读 变量 含义 cluster_name 集群名称,可调整 tidb_version TiDB 版本,TiDB-Ansible 各分支默认已配置 deployment_method 部署方式,默认为 binary,可选 docker process_supervision 进程监管方式,默认为 systemd,可选 supervise timezone 修改部署目标机器时区,默认为 Asia/Shanghai, 可调整,与set_timezone 变量结合使用 set_timezone 默认为 True,即修改部署目标机器时区,关闭可修改为 False enable_elk 目前不支持,请忽略 enable_firewalld 开启防火墙,默认不开启 enable_ntpd 检测部署目标机器 NTP 服务,默认为 True,请勿关闭 machine_benchmark 检测部署目标机器磁盘 IOPS,默认为 True,请勿关闭 set_hostname 根据 IP 修改部署目标机器主机名,默认为 False enable_binlog 是否部署 pump 并开启 binlog,默认为 False,依赖 Kafka 集群,参见 zookeeper_addrs 变量 zookeeper_addrs binlog Kafka 集群的 zookeeper 地址 enable_slow_query_log TiDB 慢查询日志记录到单独文件({{ deploy_dir }}/log/tidb_slow_query.log),默认为 False,记录到 tidb 日志 deploy_without_tidb KV 模式,不部署 TiDB 服务,仅部署 PD、TiKV 及监控服务,请将 inventory.ini 文件中 tidb_servers 主机组 IP 设置为空。 2.2.2 TiDB 离线 Ansible 部署方案 首先这不是我们建议的方式,如果中控机没有外网,也可以通过离线 Ansible 部署方式,详情可参考:https://pingcap.com/docs-cn/op-guide/offline-ansible-deployment/2.2.3 Docker Compose 快速构建集群(单机部署) 使用 docker-compose 在本地一键拉起一个集群,包括集群监控,还可以根据需求自定义各个组件的软件版本和实例个数,以及自定义配置文件,这种只限于开发环境,详细可参考:官方文档。2.3 升级 2.3.1 如何使用 Ansible 滚动升级? 滚动升级 TiKV 节点( 只升级单独服务 )ansible-playbook rolling_update.yml --tags=tikv滚动升级所有服务ansible-playbook rolling_update.yml2.3.2 滚动升级有那些影响? 滚动升级 TiDB 服务,滚动升级期间不影响业务运行,需要配置最小集群拓扑(TiDB * 2、PD * 3、TiKV * 3),如果集群环境中有 Pump/Drainer 服务,建议先停止 Drainer 后滚动升级(升级 TiDB 时会升级 Pump)。2.3.3 Binary 如何升级? Binary 不是我们建议的安装方式,对升级支持也不友好,建议换成 Ansible 部署。2.3.4 一般升级选择升级 TiKV 还是所有组件都升级? 常规需要一起升,因为整个版本都是一起测试的,单独升级只限当发生一个紧急故障时,需要单独对一个有问题的角色做升级。2.3.5 启动集群或者升级集群过程中出现 “Timeout when waiting for search string 200 OK” 是什么原因?如何处理? 可能有以下几种原因:进程没有正常启动;端口被占用;进程没有正常停掉;停掉集群的情况下使用 rolling_update.yml 来升级集群(操作错误)。处理方式:登录到相应节点查看进程或者端口的状态;纠正错误的操作步骤。三、集群管理 3.1 集群日常管理 3.1.1 Ansible 常见运维操作有那些? 任务 Playbook 启动集群 ansible-playbook start.yml 停止集群 ansible-playbook stop.yml 销毁集群 ansible-playbook unsafe_cleanup.yml (若部署目录为挂载点,会报错,可忽略) 清除数据(测试用) ansible-playbook cleanup_data.yml 滚动升级 ansible-playbook rolling_update.yml 滚动升级 TiKV ansible-playbook rolling_update.yml –tags=tikv 滚动升级除 PD 外模块 ansible-playbook rolling_update.yml –skip-tags=pd 滚动升级监控组件 ansible-playbook rolling_update_monitor.yml 3.1.2 TiDB 如何登陆? 和 MySQL 登陆方式一样,可以按照下面例子进行登陆。mysql -h 127.0.0.1 -uroot -P40003.1.3 TiDB 如何修改数据库系统变量? 和 MySQL 一样,TiDB 也分为静态参数和固态参数,静态参数可以直接通过set global xxx = n的方式进行修改,不过新参数值只限于该实例生命周期有效。3.1.4 TiDB (TiKV) 有哪些数据目录? 默认在 ${data-dir}/data/ 目录下,其中包括 backup、db、raft、snap 四个目录,分别存储备份、数据、raft 数据及镜像数据。3.1.5 TiDB 有哪些系统表? 和 MySQL 类似,TiDB 中也有系统表,用于存放数据库运行时所需信息,具体信息参考:TiDB 系统数据库文档。3.1.6 TiDB 各节点服务器下是否有日志文件,如何管理? 默认情况下各节点服务器会在日志中输出标准错误,如果启动的时候通过 --log-file 参数指定了日志文件,那么日志会输出到指定的文件中,并且按天做 rotation。3.1.7 如何规范停止 TiDB? 如果是用 Ansible 部署的,可以使用 ansible-playbook stop.yml 命令停止 TiDB 集群。如果不是 Ansible 部署的,可以直接 kill 掉所有服务。如果使用 kill 命令,TiDB 的组件会做 graceful 的 shutdown。3.1.8 TiDB 里面可以执行 kill 命令吗? 可以 kill DML 语句,首先使用 show processlist,找到对应 session 的 id,然后执行 kill id。可以 kill DDL 语句,首先使用 admin show ddl jobs,查找需要 kill 的 DDL job ID,然后执行 admin cancel ddl jobs 'job_id' [, 'job_id'] ...。具体可以参考 admin 操作。3.1.9 TiDB 是否支持会话超时? TiDB 暂不支持数据库层面的会话超时,目前想要实现超时,在没 LB(Load Balancing)的时候,需要应用侧记录发起的 Session 的 ID,通过应用自定义超时,超时以后需要到发起 Query 的节点上用 kill id 来杀掉 SQL。目前建议使用应用程序来实现会话超时,当达到超时时间,应用层就会抛出异常继续执行后续的程序段。3.1.10 TiDB 生产环境的版本管理策略是怎么样的?如何尽可能避免频繁升级? TiDB 版本目前逐步标准化,每次 Release 都包含详细的 Change log,版本功能 变化详情,生产环境是否有必要升级取决于业务系统,建议升级之前详细了解前后版本的功能差异。版本号说明参考:Release Version: v1.0.3-1-ga80e796,v1.0.3 表示 GA 标准版 -1 表示该版本 commit 1 次,ga80e796 代表版本的 git-hash。3.1.11 分不清 TiDB master 版本之间的区别,经常用错 TiDB-Ansible 版本? TiDB 目前社区非常活跃,在 GA 版本发布后,还在不断的优化和修改 BUG,因此 TiDB 的版本更新周期比较快,会不定期有新版本发布,请关注我们的 新版本发布官方网站。此外 TiDB 安装推荐使用 TiDB-Ansible 进行安装,TiDB-Ansible 的版本也会随着 TiDB 的版本发布进行更新,因此建议用户在安装升级新版本的时候使用最新的 TiDB-Ansible 安装包版本进行安装。 此外,在 TiDB 版本 GA 后,对 TiDB 的版本号进行了统一管理,TiDB 的版本可以通过几种方式进行查看: 通过 select tidb_version() 进行查看; 通过执行 tidb-server -V 进行查看。 3.1.12 有没有图形化部署 TiDB 的工具? 暂时没有。3.1.13 TiDB 如何进行水平扩展? 当您的业务不断增长时,数据库可能会面临三方面瓶颈,第一是存储空间,第二是计算资源,第三是读写容量,这时可以对 TiDB 集群做水平扩展。 如果是存储资源不够,可以通过添加 TiKV Server 节点来解决,新节点启动后,PD 会自动将其他节点的部分数据迁移过去,无需人工介入。 如果是计算资源不够,可以查看 TiDB Server 和 TiKV Server 节点的 CPU 消耗情况,再考虑添加 TiDB Server 节点或者是 TiKV Server 节点来解决,如添加 TiDB Server 节点,将其添加到前端 Load Balancer 配置之中即可。 如果是容量跟不上,一般可以考虑同时增加 TiDB Server 和 TiKV …"}, {"url": "https://pingcap.com/docs-cn/v2.0/FAQ/", "title": "TiDB FAQ", "content": " 一、 TiDB 介绍、架构、原理 1.1 TiDB 介绍及整体架构 1.1.1 TiDB 整体架构 https://pingcap.com/docs-cn/overview/1.1.2 TiDB 是什么? TiDB 是一个分布式 NewSQL 数据库。它支持水平弹性扩展、ACID 事务、标准 SQL、MySQL 语法和 MySQL 协议,具有数据强一致的高可用特性,是一个不仅适合 OLTP 场景还适合 OLAP 场景的混合数据库。1.1.3 TiDB 是基于 MySQL 开发的吗? 不是,虽然 TiDB 支持 MySQL 语法和协议,但是 TiDB 是由 PingCAP 团队完全自主开发的产品。1.1.4 TiDB、TiKV、Placement Driver (PD) 主要作用? TiDB 是 Server 计算层,主要负责 SQL 的解析、制定查询计划、生成执行器。 TiKV 是分布式 Key-Value 存储引擎,用来存储真正的数据,简而言之,TiKV 是 TiDB 的存储引擎。 PD 是 TiDB 集群的管理组件,负责存储 TiKV 的元数据,同时也负责分配时间戳以及对 TiKV 做负载均衡调度。 1.1.5 TiDB 易用性如何? TiDB 使用起来很简单,可以将 TiDB 集群当成 MySQL 来用,你可以将 TiDB 用在任何以 MySQL 作为后台存储服务的应用中,并且基本上不需要修改应用代码,同时你可以用大部分流行的 MySQL 管理工具来管理 TiDB。1.1.6 TiDB 和 MySQL 兼容性如何? TiDB 目前还不支持触发器、存储过程、自定义函数、外键,除此之外,TiDB 支持绝大部分 MySQL 5.7 的语法。详情参见:与 MySQL 兼容性对比。1.1.7 TiDB 具备高可用的特性吗? TiDB 天然具备高可用特性,TiDB、TiKV、PD 这三个组件都能容忍部分实例失效,不影响整个集群的可用性。具体见 TiDB 高可用性。1.1.8 TiDB 数据是强一致的吗? TiDB 使用 Raft 在多个副本之间做数据同步,从而保证数据的强一致,单个副本失效时,不影响数据的可靠性。1.1.9 TiDB 支持分布式事务吗? TiDB 支持 ACID 分布式事务,事务模型是以 Google 的 Percolator 模型为基础,并做了一些优化。这个模型需要一个时间戳分配器,分配唯一且递增的时间戳。在 TiDB 集群中,PD 承担时间戳分配器的角色。1.1.10 TiDB 支持哪些编程语言? 只要支持 MySQL Client/Driver 的编程语言,都可以直接使用 TiDB。1.1.11 TiDB 是否支持其他存储引擎? 是的,除了 TiKV 之外,TiDB 还支持一些流行的单机存储引擎,比如 GolevelDB、RocksDB、BoltDB 等。如果一个存储引擎是支持事务的 KV 引擎,并且能提供一个满足 TiDB 接口要求的 Client,即可接入 TiDB。1.1.12 官方有没有三中心跨机房多活部署的推荐方案? 从 TiDB 架构来讲,支持真正意义上的跨中心异地多活,从操作层面讲,依赖数据中心之间的网络延迟和稳定性,一般建议延迟在 5ms 以下,目前我们已经有相似客户方案,具体请咨询官方: info@pingcap.com。1.1.13 除了官方文档,有没有其他 TiDB 知识获取途径? 目前 官方文档是获取 TiDB 相关知识最主要、最及时的发布途径。除此之外,我们也有一些技术沟通群,如有需求可发邮件至 info@pingcap.com 获取。1.1.14 TiDB 对那些 MySQL variables 兼容? 详细可参考:系统变量1.1.15 TiDB 是否支持 select for update 吗? 支持,但语义上和 MySQL 有区别,TiDB 是分布式数据库,采用的乐观锁机制,也就说 select for update 不在事务开启就锁住数据,而是其他事务在提交的时候进行冲突检查,如有冲突,会进行回滚。1.1.16 TiDB 的 codec 能保证 UTF8 的字符串是 memcomparable 的吗?我们的 key 需要支持 UTF8,有什么编码建议吗? TiDB 字符集默认就是 UTF8 而且目前只支持 UTF8,字符串就是 memcomparable 格式的。1.1.17 TiDB 用户名长度限制? 在 TiDB 中用户名最长为 32 字符。1.1.18 一个事务中的语句数量最大是多少? 一个事务中的语句数量,默认限制最大为 5000 条。1.2 TiDB 原理 1.2.1 存储 TiKV 1.2.1.1 TiKV 详细解读 http://t.cn/RTKRRWv1.2.2 计算 TiDB 1.2.2.1 TiDB 详细解读 http://t.cn/RTKRkBh1.2.3 调度 PD 1.2.3.1 PD 详细解读 http://t.cn/RTKEZ0U二、安装部署升级 2.1 环境准备 2.1.1 操作系统版本要求 Linux 操作系统平台 版本 Red Hat Enterprise Linux 7.3 及以上 CentOS 7.3 及以上 Oracle Enterprise Linux 7.3 及以上 2.1.1.1 为什么要在 CentOS 7 上部署 TiDB 集群? TiDB 作为一款开源分布式 NewSQL 数据库,可以很好的部署和运行在 Intel 架构服务器环境及主流虚拟化环境,并支持绝大多数的主流硬件网络,作为一款高性能数据库系统,TiDB 支持主流的 Linux 操作系统环境,具体可以参考 TiDB 的官方部署要求。 其中 TiDB 在 CentOS 7.3 的环境下进行大量的测试,同时也有很多这个操作系统的部署最佳实践,因此,我们推荐客户在部署 TiDB 的时候使用 CentOS 7.3+ 以上的Linux 操作系统。2.1.2 硬件要求 TiDB 支持部署和运行在 Intel x86-64 架构的 64 位通用硬件服务器平台。对于开发,测试,及生产环境的服务器硬件配置有以下要求和建议:2.1.2.1 开发及测试环境 组件 CPU 内存 本地存储 网络 实例数量(最低要求) TiDB 8核+ 16 GB+ SAS, 200 GB+ 千兆网卡 1(可与 PD 同机器) PD 8核+ 16 GB+ SAS, 200 GB+ 千兆网卡 1(可与 TiDB 同机器) TiKV 8核+ 32 GB+ SSD, 200 GB+ 千兆网卡 3 服务器总计 4 2.1.2.2 线上环境 组件 CPU 内存 硬盘类型 网络 实例数量(最低要求) TiDB 16核+ 48 GB+ SAS 万兆网卡(2块最佳) 2 PD 8核+ 16 GB+ SSD 万兆网卡(2块最佳) 3 TiKV 16核+ 48 GB+ SSD 万兆网卡(2块最佳) 3 监控 8核+ 16 GB+ SAS 千兆网卡 1 服务器总计 9 2.1.2.3 2 块网卡的目的是?万兆的目的是? 作为一个分布式集群,TiDB 对时间的要求还是比较高的,尤其是 PD 需要分发唯一的时间戳,如果 PD 时间不统一,如果有 PD 切换,将会等待更长的时间。2 块网卡可以做 bond,保证数据传输的稳定,万兆可以保证数据传输的速度,千兆网卡容易出现瓶颈,我们强烈建议使用万兆网卡。2.1.2.4 SSD 不做 RAID 是否可行? 资源可接受的话,我们建议做 RAID 10,如果资源有限,也可以不做 RAID。2.2 安装部署 2.2.1 Ansible 部署方式(强烈推荐) 详细可参考:TiDB Ansible 部署方案2.2.1.1 为什么修改了 TiKV/PD 的 toml 配置文件,却没有生效? 这种情况一般是因为没有使用 --config 参数来指定配置文件(目前只会出现在 binary 部署的场景),TiKV/PD 会按默认值来设置。如果要使用配置文件,请设置 TiKV/PD 的 --config 参数。对于 TiKV 组件,修改配置后重启服务即可;对于 PD 组件,只会在第一次启动时读取配置文件,之后可以使用 pd-ctl 的方式来修改配置,详情可参考:https://pingcap.com/docs-cn/tools/pd-control/2.2.1.2 TiDB 监控框架 Prometheus + Grafana 监控机器建议单独还是多台部署? 监控机建议单独部署。建议 CPU 8 core,内存 16 GB 以上,硬盘 500 GB 以上。2.2.1.3 有一部分监控信息显示不出来? 查看访问监控的机器时间跟集群内机器的时间差,如果比较大,更正时间后即可显示正常。2.2.1.4 supervise/svc/svstat 服务具体起什么作用? supervise 守护进程 svc 启停服务 svstat 查看进程状态 2.2.1.5 inventory.ini 变量参数解读 变量 含义 cluster_name 集群名称,可调整 tidb_version TiDB 版本,TiDB-Ansible 各分支默认已配置 deployment_method 部署方式,默认为 binary,可选 docker process_supervision 进程监管方式,默认为 systemd,可选 supervise timezone 修改部署目标机器时区,默认为 Asia/Shanghai, 可调整,与set_timezone 变量结合使用 set_timezone 默认为 True,即修改部署目标机器时区,关闭可修改为 False enable_elk 目前不支持,请忽略 enable_firewalld 开启防火墙,默认不开启 enable_ntpd 检测部署目标机器 NTP 服务,默认为 True,请勿关闭 machine_benchmark 检测部署目标机器磁盘 IOPS,默认为 True,请勿关闭 set_hostname 根据 IP 修改部署目标机器主机名,默认为 False enable_binlog 是否部署 pump 并开启 binlog,默认为 False,依赖 Kafka 集群,参见 zookeeper_addrs 变量 zookeeper_addrs binlog Kafka 集群的 zookeeper 地址 enable_slow_query_log TiDB 慢查询日志记录到单独文件({{ deploy_dir }}/log/tidb_slow_query.log),默认为 False,记录到 tidb 日志 deploy_without_tidb KV 模式,不部署 TiDB 服务,仅部署 PD、TiKV 及监控服务,请将 inventory.ini 文件中 tidb_servers 主机组 IP 设置为空。 2.2.2 TiDB 离线 Ansible 部署方案 首先这不是我们建议的方式,如果中控机没有外网,也可以通过离线 Ansible 部署方式,详情可参考:https://pingcap.com/docs-cn/op-guide/offline-ansible-deployment/2.2.3 Docker Compose 快速构建集群(单机部署) 使用 docker-compose 在本地一键拉起一个集群,包括集群监控,还可以根据需求自定义各个组件的软件版本和实例个数,以及自定义配置文件,这种只限于开发环境,详细可参考:官方文档。2.3 升级 2.3.1 如何使用 Ansible 滚动升级? 滚动升级 TiKV 节点( 只升级单独服务 )ansible-playbook rolling_update.yml --tags=tikv滚动升级所有服务ansible-playbook rolling_update.yml2.3.2 滚动升级有那些影响? 滚动升级 TiDB 服务,滚动升级期间不影响业务运行,需要配置最小集群拓扑(TiDB * 2、PD * 3、TiKV * 3),如果集群环境中有 Pump/Drainer 服务,建议先停止 Drainer 后滚动升级(升级 TiDB 时会升级 Pump)。2.3.3 Binary 如何升级? Binary 不是我们建议的安装方式,对升级支持也不友好,建议换成 Ansible 部署。2.3.4 一般升级选择升级 TiKV 还是所有组件都升级? 常规需要一起升,因为整个版本都是一起测试的,单独升级只限当发生一个紧急故障时,需要单独对一个有问题的角色做升级。2.3.5 启动集群或者升级集群过程中出现 “Timeout when waiting for search string 200 OK” 是什么原因?如何处理? 可能有以下几种原因:进程没有正常启动;端口被占用;进程没有正常停掉;停掉集群的情况下使用 rolling_update.yml 来升级集群(操作错误)。处理方式:登录到相应节点查看进程或者端口的状态;纠正错误的操作步骤。三、集群管理 3.1 集群日常管理 3.1.1 Ansible 常见运维操作有那些? 任务 Playbook 启动集群 ansible-playbook start.yml 停止集群 ansible-playbook stop.yml 销毁集群 ansible-playbook unsafe_cleanup.yml (若部署目录为挂载点,会报错,可忽略) 清除数据(测试用) ansible-playbook cleanup_data.yml 滚动升级 ansible-playbook rolling_update.yml 滚动升级 TiKV ansible-playbook rolling_update.yml –tags=tikv 滚动升级除 PD 外模块 ansible-playbook rolling_update.yml –skip-tags=pd 滚动升级监控组件 ansible-playbook rolling_update_monitor.yml 3.1.2 TiDB 如何登陆? 和 MySQL 登陆方式一样,可以按照下面例子进行登陆。mysql -h 127.0.0.1 -uroot -P40003.1.3 TiDB 如何修改数据库系统变量? 和 MySQL 一样,TiDB 也分为静态参数和固态参数,静态参数可以直接通过set global xxx = n的方式进行修改,不过新参数值只限于该实例生命周期有效。3.1.4 TiDB (TiKV) 有哪些数据目录? 默认在 ${data-dir}/data/ 目录下,其中包括 backup、db、raft、snap 四个目录,分别存储备份、数据、raft 数据及镜像数据。3.1.5 TiDB 有哪些系统表? 和 MySQL 类似,TiDB 中也有系统表,用于存放数据库运行时所需信息,具体信息参考:TiDB 系统数据库文档。3.1.6 TiDB 各节点服务器下是否有日志文件,如何管理? 默认情况下各节点服务器会在日志中输出标准错误,如果启动的时候通过 --log-file 参数指定了日志文件,那么日志会输出到指定的文件中,并且按天做 rotation。3.1.7 如何规范停止 TiDB? 如果是用 Ansible 部署的,可以使用 ansible-playbook stop.yml 命令停止 TiDB 集群。如果不是 Ansible 部署的,可以直接 kill 掉所有服务。如果使用 kill 命令,TiDB 的组件会做 graceful 的 shutdown。3.1.8 TiDB 里面可以执行 kill 命令吗? 可以 kill DML 语句,首先使用 show processlist,找到对应 session 的 id,然后执行 kill id。可以 kill DDL 语句,首先使用 admin show ddl jobs,查找需要 kill 的 DDL job ID,然后执行 admin cancel ddl jobs 'job_id' [, 'job_id'] ...。具体可以参考 admin 操作。3.1.9 TiDB 是否支持会话超时? TiDB 暂不支持数据库层面的会话超时,目前想要实现超时,在没 LB(Load Balancing)的时候,需要应用侧记录发起的 Session 的 ID,通过应用自定义超时,超时以后需要到发起 Query 的节点上用 kill id 来杀掉 SQL。目前建议使用应用程序来实现会话超时,当达到超时时间,应用层就会抛出异常继续执行后续的程序段。3.1.10 TiDB 生产环境的版本管理策略是怎么样的?如何尽可能避免频繁升级? TiDB 版本目前逐步标准化,每次 Release 都包含详细的 Change log,版本功能 变化详情,生产环境是否有必要升级取决于业务系统,建议升级之前详细了解前后版本的功能差异。版本号说明参考:Release Version: v1.0.3-1-ga80e796,v1.0.3 表示 GA 标准版 -1 表示该版本 commit 1 次,ga80e796 代表版本的 git-hash。3.1.11 分不清 TiDB master 版本之间的区别,经常用错 TiDB-Ansible 版本? TiDB 目前社区非常活跃,在 GA 版本发布后,还在不断的优化和修改 BUG,因此 TiDB 的版本更新周期比较快,会不定期有新版本发布,请关注我们的 新版本发布官方网站。此外 TiDB 安装推荐使用 TiDB-Ansible 进行安装,TiDB-Ansible 的版本也会随着 TiDB 的版本发布进行更新,因此建议用户在安装升级新版本的时候使用最新的 TiDB-Ansible 安装包版本进行安装。 此外,在 TiDB 版本 GA 后,对 TiDB 的版本号进行了统一管理,TiDB 的版本可以通过几种方式进行查看: 通过 select tidb_version() 进行查看; 通过执行 tidb-server -V 进行查看。 3.1.12 有没有图形化部署 TiDB 的工具? 暂时没有。3.1.13 TiDB 如何进行水平扩展? 当您的业务不断增长时,数据库可能会面临三方面瓶颈,第一是存储空间,第二是计算资源,第三是读写容量,这时可以对 TiDB 集群做水平扩展。 如果是存储资源不够,可以通过添加 TiKV Server 节点来解决,新节点启动后,PD 会自动将其他节点的部分数据迁移过去,无需人工介入。 如果是计算资源不够,可以查看 TiDB Server 和 TiKV Server 节点的 CPU 消耗情况,再考虑添加 TiDB Server 节点或者是 TiKV Server 节点来解决,如 …"}, {"url": "https://pingcap.com/docs/FAQ/", "title": "TiDB FAQ", "content": " TiDB FAQ This document lists the Most Frequently Asked Questions about TiDB.About TiDB TiDB introduction and architecture What is TiDB? TiDB is a distributed SQL database that features in horizontal scalability, high availability and consistent distributed transactions. It also enables you to use MySQL’s SQL syntax and protocol to manage and retrieve data.What is TiDB’s architecture? The TiDB cluster has three components: the TiDB server, the PD (Placement Driver) server, and the TiKV server. For more details, see TiDB architecture.Is TiDB based on MySQL? No. TiDB supports MySQL syntax and protocol, but it is a new open source database that is developed and maintained by PingCAP, Inc.What is the respective responsibility of TiDB, TiKV and PD (Placement Driver)? TiDB works as the SQL computing layer, mainly responsible for parsing SQL, specifying query plan, and generating executor. TiKV works as a distributed Key-Value storage engine, used to store the real data. In short, TiKV is the storage engine of TiDB. PD works as the cluster manager of TiDB, which manages TiKV metadata, allocates timestamps, and makes decisions for data placement and load balancing. Is it easy to use TiDB? Yes, it is. When all the required services are started, you can use TiDB as easily as a MySQL server. You can replace MySQL with TiDB to power your applications without changing a single line of code in most cases. You can also manage TiDB using the popular MySQL management tools.How is TiDB compatible with MySQL? Currently, TiDB supports the majority of MySQL 5.7 syntax, but does not support trigger, stored procedures, user-defined functions, and foreign keys. For more details, see Compatibility with MySQL.How is TiDB highly available? TiDB is self-healing. All of the three components, TiDB, TiKV and PD, can tolerate failures of some of their instances. With its strong consistency guarantee, whether it’s data machine failures or even downtime of an entire data center, your data can be recovered automatically. For more information, see TiDB architecture.How is TiDB strongly consistent? TiDB uses the Raft consensus algorithm to ensure consistency among multiple replicas. At the bottom layer, TiDB uses a model of replication log + State Machine to replicate data. For the write requests, the data is written to a Leader and the Leader then replicates the command to its Followers in the form of log. When the majority of nodes in the cluster receive this log, this log is committed and can be applied into the State Machine. TiDB has the latest data even if a minority of the replicas are lost.Does TiDB support distributed transactions? Yes. The transaction model in TiDB is inspired by Google’s Percolator, a paper published in 2006. It’s mainly a two-phase commit protocol with some practical optimizations. This model relies on a timestamp allocator to assign monotone increasing timestamp for each transaction, so the conflicts can be detected. PD works as the timestamp allocator in a TiDB cluster.What programming language can I use to work with TiDB? Any language supported by MySQL client or driver.Can I use other Key-Value storage engines with TiDB? Yes. TiKV and TiDB support many popular standalone storage engines, such as GolevelDB and BoltDB. If the storage engine is a KV engine that supports transactions and it provides a client that meets the interface requirement of TiDB, then it can connect to TiDB.What’s the recommended solution for the deployment of three geo-distributed data centers? The architecture of TiDB guarantees that it fully supports geo-distribution and multi-activeness. Your data and applications are always-on. All the outages are transparent to your applications and your data can recover automatically. The operation depends on the network latency and stability. It is recommended to keep the latency within 5ms. Currently, we already have similar use cases. For details, contact info@pingcap.com.Does TiDB provide any other knowledge resource besides the documentation? Currently, TiDB documentation is the most important and timely way to get knowledge of TiDB. In addition, we also have some technical communication groups. If you have any needs, contact info@pingcap.com.What are the MySQL variables that TiDB is compatible with? See The System Variables.Does TiDB support select for update? Yes. But it differs from MySQL in syntax. As a distributed database, TiDB uses the optimistic lock. select for update does not lock data when the transaction is started, but checks conflicts when the transaction is committed. If the check reveals conflicts, the committing transaction rolls back.Can the codec of TiDB guarantee that the UTF-8 string is memcomparable? Is there any coding suggestion if our key needs to support UTF-8? The character sets of TiDB use UTF-8 by default and currently only support UTF-8. The string of TiDB uses the memcomparable format.What is the length limit for the TiDB user name? 32 characters at most.What is the maximum number of statements in a transaction? 5000 at most.Does TiDB support XA? No. The JDBC drive of TiDB is MySQL JDBC (Connector/J). When using Atomikos, set the data source to type="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource". TiDB does not support the connection with MySQL JDBC XADataSource. MySQL JDBC XADataSource only works for MySQL (for example, using DML to modify the redo log).After you configure the two data sources of Atomikos, set the JDBC drives to XA. When Atomikos operates TM and RM (DB), Atomikos sends the command including XA to the JDBC layer. Taking MySQL for an example, when XA is enabled in the JDBC layer, JDBC will send a series of XA logic operations to InnoDB, including using DML to change the redo log. This is the operation of the two-phase commit. The current TiDB version does not support the upper application layer JTA/XA and does not parse XA operations sent by Atomikos.As a standalone database, MySQL can only implement across-database transactions using XA; while TiDB supports distributed transactions using Google Percolator transaction model and its performance stability is higher than XA, so TiDB does not support XA and there is no need for TiDB to support XA.Does show processlist display the system process ID? The display content of TiDB show processlist is almost the same as that of MySQL show processlist. TiDB show processlist does not display the system process ID. The ID that it displays is the current session ID. The differences between TiDB show processlist and MySQL show processlist are as follows: As TiDB is a distributed database, the tidb-server instance is a stateless engine for parsing and executing the SQL statements (for details, see TiDB architecture). show processlist displays the session list executed in the tidb-server instance that the user logs in to from the MySQL client, not the list of all the sessions running in the cluster. But MySQL is a standalone database and its show processlist displays all the SQL statements executed in MySQL. TiDB show processlist displays the estimated memory usage (unit: Byte) of the current session, which is not displayed in MySQL show processlist. How to modify the user password and privilege? To modify the user password in TiDB, it is recommended to use set password for 'root'@'%' = '0101001'; or alter, not update mysql.user which might lead to the condition that the password in other nodes is not refreshed timely.It is recommended to use the official standard statements when modifying the user password and privilege. For details, see TiDB user account management.Why does the auto-increment ID of the later inserted data is smaller than that of the earlier inserted data in TiDB? The auto-increment ID feature in TiDB is only guaranteed to be automatically incremental and unique but is not guaranteed to be allocated sequentially. Currently, TiDB is allocating IDs in batches. If data is inserted into multiple TiDB servers …"}, {"url": "https://pingcap.com/docs/v1.0/FAQ/", "title": "TiDB FAQ", "content": " TiDB FAQ This document lists the Most Frequently Asked Questions about TiDB.About TiDB TiDB introduction and architecture What is TiDB? TiDB is a distributed SQL database that features in horizontal scalability, high availability and consistent distributed transactions. It also enables you to use MySQL’s SQL syntax and protocol to manage and retrieve data.What is TiDB’s architecture? The TiDB cluster has three components: the TiDB server, the PD (Placement Driver) server, and the TiKV server. For more details, see TiDB architecture.Is TiDB based on MySQL? No. TiDB supports MySQL syntax and protocol, but it is a new open source database that is developed and maintained by PingCAP, Inc.What is the respective responsibility of TiDB, TiKV and PD (Placement Driver)? TiDB works as the SQL computing layer, mainly responsible for parsing SQL, specifying query plan, and generating executor. TiKV works as a distributed Key-Value storage engine, used to store the real data. In short, TiKV is the storage engine of TiDB. PD works as the cluster manager of TiDB, which manages TiKV metadata, allocates timestamps, and makes decisions for data placement and load balancing. Is it easy to use TiDB? Yes, it is. When all the required services are started, you can use TiDB as easily as a MySQL server. You can replace MySQL with TiDB to power your applications without changing a single line of code in most cases. You can also manage TiDB using the popular MySQL management tools.How is TiDB compatible with MySQL? Currently, TiDB supports the majority of MySQL 5.7 syntax, but does not support trigger, stored procedures, user-defined functions, and foreign keys. For more details, see Compatibility with MySQL.How is TiDB highly available? TiDB is self-healing. All of the three components, TiDB, TiKV and PD, can tolerate failures of some of their instances. With its strong consistency guarantee, whether it’s data machine failures or even downtime of an entire data center, your data can be recovered automatically. For more information, see High availability.How is TiDB strongly consistent? TiDB uses the Raft consensus algorithm to ensure consistency among multiple replicas. At the bottom layer, TiDB uses a model of replication log + State Machine to replicate data. For the write requests, the data is written to a Leader and the Leader then replicates the command to its Followers in the form of log. When the majority of nodes in the cluster receive this log, this log is committed and can be applied into the State Machine. TiDB has the latest data even if a minority of the replicas are lost.Does TiDB support distributed transactions? Yes. The transaction model in TiDB is inspired by Google’s Percolator, a paper published in 2006. It’s mainly a two-phase commit protocol with some practical optimizations. This model relies on a timestamp allocator to assign monotone increasing timestamp for each transaction, so the conflicts can be detected. PD works as the timestamp allocator in a TiDB cluster.What programming language can I use to work with TiDB? Any language supported by MySQL client or driver.Can I use other Key-Value storage engines with TiDB? Yes. Besides TiKV, TiDB supports many popular standalone storage engines, such as GolevelDB and BoltDB. If the storage engine is a KV engine that supports transactions and it provides a client that meets the interface requirement of TiDB, then it can connect to TiDB.What’s the recommended solution for the deployment of three geo-distributed data centers? The architecture of TiDB guarantees that it fully supports geo-distribution and multi-activeness. Your data and applications are always-on. All the outages are transparent to your applications and your data can recover automatically. The operation depends on the network latency and stability. It is recommended to keep the latency within 5ms. Currently, we already have similar use cases. For details, contact info@pingcap.com.Does TiDB provide any other knowledge resource besides the documentation? Currently, TiDB documentation is the most important and timely way to get knowledge of TiDB. In addition, we also have some technical communication groups. If you have any needs, contact info@pingcap.com.What are the MySQL variables that TiDB is compatible with? See The System Variables.Does TiDB support select for update? Yes. But it differs from MySQL in syntax. As a distributed database, TiDB uses the optimistic lock. select for update does not lock data when the transaction is started, but checks conflicts when the transaction is committed. If the check reveals conflicts, the committing transaction rolls back.Can the codec of TiDB guarantee that the UTF-8 string is memcomparable? Is there any coding suggestion if our key needs to support UTF-8? The character sets of TiDB use UTF-8 by default and currently only support UTF-8. The string of TiDB uses the memcomparable format.TiDB techniques TiKV for data storage See TiDB Internal (I) - Data Storage.TiDB for data computing See TiDB Internal (II) - Computing.PD for scheduling See TiDB Internal (III) - Scheduling.Install, deploy and upgrade Prepare Operating system version requirements Linux OS Platform Version Red Hat Enterprise Linux 7.3 or later CentOS 7.3 or later Oracle Enterprise Linux 7.3 or later Why it is recommended to deploy the TiDB cluster on CentOS 7? As an open source distributed NewSQL database with high performance, TiDB can be deployed in the Intel architecture server and major virtualization environments and runs well. TiDB supports most of the major hardware networks and Linux operating systems. For details, see Software and Hardware Requirements for deploying TiDB.Server requirements You can deploy and run TiDB on the 64-bit generic hardware server platform in the Intel x86-64 architecture. The requirements and recommendations about server hardware configuration for development, testing and production environments are as follows:Development and testing environments Component CPU Memory Local Storage Network Instance Number (Minimum Requirement) TiDB 8 core+ 16 GB+ SAS, 200 GB+ Gigabit network card 1 (can be deployed on the same machine with PD) PD 8 core+ 16 GB+ SAS, 200 GB+ Gigabit network card 1 (can be deployed on the same machine with TiDB) TiKV 8 core+ 32 GB+ SAS, 200 GB+ Gigabit network card 3 Total Server Number 4 Production environment Component CPU Memory Hard Disk Type Network Instance Number (Minimum Requirement) TiDB 16 core+ 48 GB+ SAS 10 Gigabit network card (2 preferred) 2 PD 8 core+ 16 GB+ SSD 10 Gigabit network card (2 preferred) 3 TiKV 16 core+ 48 GB+ SSD 10 Gigabit network card (2 preferred) 3 Monitor 8 core+ 16 GB+ SAS Gigabit network card 1 Total Server Number 9 What’s the purposes of 2 network cards of 10 gigabit? As a distributed cluster, TiDB has a high demand on time, especially for PD, because PD needs to distribute unique timestamps. If the time in the PD servers is not consistent, it takes longer waiting time when switching the PD server. The bond of two network cards guarantees the stability of data transmission, and 10 gigabit guarantees the transmission speed. Gigabit network cards are prone to meet bottlenecks, therefore it is strongly recommended to use 10 gigabit network cards.Is it feasible if we don’t use RAID for SSD? If the resources are adequate, it is recommended to use RAID for SSD. If the resources are inadequate, it is acceptable not to use RAID for SSD.Install and deploy Deploy TiDB using Ansible (recommended) See Ansible Deployment.Why the modified toml configuration for TiKV/PD does not take effect? You need to set the --config parameter in TiKV/PD to make the toml configuration effective. TiKV/PD does not read the configuration by default. Currently, this issue only occurs when deploying using Binary. For TiKV, edit the configuration and restart the service. For PD, the configuration file is only …"}, {"url": "https://pingcap.com/docs/v2.0/FAQ/", "title": "TiDB FAQ", "content": " TiDB FAQ This document lists the Most Frequently Asked Questions about TiDB.About TiDB TiDB introduction and architecture What is TiDB? TiDB is a distributed SQL database that features in horizontal scalability, high availability and consistent distributed transactions. It also enables you to use MySQL’s SQL syntax and protocol to manage and retrieve data.What is TiDB’s architecture? The TiDB cluster has three components: the TiDB server, the PD (Placement Driver) server, and the TiKV server. For more details, see TiDB architecture.Is TiDB based on MySQL? No. TiDB supports MySQL syntax and protocol, but it is a new open source database that is developed and maintained by PingCAP, Inc.What is the respective responsibility of TiDB, TiKV and PD (Placement Driver)? TiDB works as the SQL computing layer, mainly responsible for parsing SQL, specifying query plan, and generating executor. TiKV works as a distributed Key-Value storage engine, used to store the real data. In short, TiKV is the storage engine of TiDB. PD works as the cluster manager of TiDB, which manages TiKV metadata, allocates timestamps, and makes decisions for data placement and load balancing. Is it easy to use TiDB? Yes, it is. When all the required services are started, you can use TiDB as easily as a MySQL server. You can replace MySQL with TiDB to power your applications without changing a single line of code in most cases. You can also manage TiDB using the popular MySQL management tools.How is TiDB compatible with MySQL? Currently, TiDB supports the majority of MySQL 5.7 syntax, but does not support trigger, stored procedures, user-defined functions, and foreign keys. For more details, see Compatibility with MySQL.How is TiDB highly available? TiDB is self-healing. All of the three components, TiDB, TiKV and PD, can tolerate failures of some of their instances. With its strong consistency guarantee, whether it’s data machine failures or even downtime of an entire data center, your data can be recovered automatically. For more information, see High availability.How is TiDB strongly consistent? TiDB uses the Raft consensus algorithm to ensure consistency among multiple replicas. At the bottom layer, TiDB uses a model of replication log + State Machine to replicate data. For the write requests, the data is written to a Leader and the Leader then replicates the command to its Followers in the form of log. When the majority of nodes in the cluster receive this log, this log is committed and can be applied into the State Machine. TiDB has the latest data even if a minority of the replicas are lost.Does TiDB support distributed transactions? Yes. The transaction model in TiDB is inspired by Google’s Percolator, a paper published in 2006. It’s mainly a two-phase commit protocol with some practical optimizations. This model relies on a timestamp allocator to assign monotone increasing timestamp for each transaction, so the conflicts can be detected. PD works as the timestamp allocator in a TiDB cluster.What programming language can I use to work with TiDB? Any language supported by MySQL client or driver.Can I use other Key-Value storage engines with TiDB? Yes. TiKV and TiDB support many popular standalone storage engines, such as GolevelDB and BoltDB. If the storage engine is a KV engine that supports transactions and it provides a client that meets the interface requirement of TiDB, then it can connect to TiDB.What’s the recommended solution for the deployment of three geo-distributed data centers? The architecture of TiDB guarantees that it fully supports geo-distribution and multi-activeness. Your data and applications are always-on. All the outages are transparent to your applications and your data can recover automatically. The operation depends on the network latency and stability. It is recommended to keep the latency within 5ms. Currently, we already have similar use cases. For details, contact info@pingcap.com.Does TiDB provide any other knowledge resource besides the documentation? Currently, TiDB documentation is the most important and timely way to get knowledge of TiDB. In addition, we also have some technical communication groups. If you have any needs, contact info@pingcap.com.What are the MySQL variables that TiDB is compatible with? See The System Variables.Does TiDB support select for update? Yes. But it differs from MySQL in syntax. As a distributed database, TiDB uses the optimistic lock. select for update does not lock data when the transaction is started, but checks conflicts when the transaction is committed. If the check reveals conflicts, the committing transaction rolls back.Can the codec of TiDB guarantee that the UTF-8 string is memcomparable? Is there any coding suggestion if our key needs to support UTF-8? The character sets of TiDB use UTF-8 by default and currently only support UTF-8. The string of TiDB uses the memcomparable format.What is the length limit for the TiDB user name? 32 characters at most.What is the maximum number of statements in a transaction? 5000 at most.Does TiDB support XA? No. The JDBC drive of TiDB is MySQL JDBC (Connector/J). When using Atomikos, set the data source to type="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource". TiDB does not support the connection with MySQL JDBC XADataSource. MySQL JDBC XADataSource only works for MySQL (for example, using DML to modify the redo log).After you configure the two data sources of Atomikos, set the JDBC drives to XA. When Atomikos operates TM and RM (DB), Atomikos sends the command including XA to the JDBC layer. Taking MySQL for an example, when XA is enabled in the JDBC layer, JDBC will send a series of XA logic operations to InnoDB, including using DML to change the redo log. This is the operation of the two-phase commit. The current TiDB version does not support the upper application layer JTA/XA and does not parse XA operations sent by Atomikos.As a standalone database, MySQL can only implement across-database transactions using XA; while TiDB supports distributed transactions using Google Percolator transaction model and its performance stability is higher than XA, so TiDB does not support XA and there is no need for TiDB to support XA.Does show processlist display the system process ID? The display content of TiDB show processlist is almost the same as that of MySQL show processlist. TiDB show processlist does not display the system process ID. The ID that it displays is the current session ID. The differences between TiDB show processlist and MySQL show processlist are as follows: As TiDB is a distributed database, the tidb-server instance is a stateless engine for parsing and executing the SQL statements (for details, see TiDB architecture). show processlist displays the session list executed in the tidb-server instance that the user logs in to from the MySQL client, not the list of all the sessions running in the cluster. But MySQL is a standalone database and its show processlist displays all the SQL statements executed in MySQL. TiDB show processlist displays the estimated memory usage (unit: Byte) of the current session, which is not displayed in MySQL show processlist. How to modify the user password and privilege? To modify the user password in TiDB, it is recommended to use set password for 'root'@'%' = '0101001'; or alter, not update mysql.user which might lead to the condition that the password in other nodes is not refreshed timely.It is recommended to use the official standard statements when modifying the user password and privilege. For details, see TiDB user account management.Why does the auto-increment ID of the later inserted data is smaller than that of the earlier inserted data in TiDB? The auto-increment ID feature in TiDB is only guaranteed to be automatically incremental and unique but is not guaranteed to be allocated sequentially. Currently, TiDB is allocating IDs in batches. If data is inserted into multiple TiDB servers …"}, {"url": "https://pingcap.com/docs/op-guide/gc/", "title": "TiDB Garbage Collection (GC)", "content": " TiDB Garbage Collection (GC) TiDB uses MVCC to control concurrency. When you update or delete data, the original data is not deleted immediately but is kept for a period during which it can be read. Thus the write operation and the read operation are not mutually exclusive and it is possible to read the history versions of the data.The data versions whose duration exceeds a specific time and that are not used any more will be cleared, otherwise they will occupy the disk space and affect TiDB’s performance. TiDB uses Garbage Collection (GC) to clear the obsolete data.Working mechanism GC runs periodically on TiDB. When a TiDB server is started, a gc_worker is enabled in the background. In each TiDB cluster, one gc_worker is elected to be the leader which is used to maintain the GC status and send GC commands to all the TiKV Region leaders.Configuration and monitor The GC configuration and operational status are recorded in the mysql.tidb system table as below, which can be monitored and configured using SQL statements:mysql> select VARIABLE_NAME, VARIABLE_VALUE from mysql.tidb; +-----------------------+------------------------------------------------------------------------------------------------+ | VARIABLE_NAME | VARIABLE_VALUE | +-----------------------+------------------------------------------------------------------------------------------------+ | bootstrapped | True | | tidb_server_version | 18 | | tikv_gc_leader_uuid | 58accebfa7c0004 | | tikv_gc_leader_desc | host:ip-172-16-30-5, pid:95472, start at 2018-04-11 13:43:30.73076656 +0800 CST m=+0.068873865 | | tikv_gc_leader_lease | 20180418-11:02:30 +0800 CST | | tikv_gc_run_interval | 10m0s | | tikv_gc_life_time | 10m0s | | tikv_gc_last_run_time | 20180418-10:59:30 +0800 CST | | tikv_gc_safe_point | 20180418-10:58:30 +0800 CST | | tikv_gc_concurrency | 1 | +-----------------------+------------------------------------------------------------------------------------------------+ 10 rows in set (0.02 sec) In the table above, tikv_gc_run_interval, tikv_gc_life_time and tikv_gc_concurrency can be configured manually. Other variables with the tikv_gc prefix record the current status, which are automatically updated by TiDB. Do not modify these variables. tikv_gc_leader_uuid, tikv_gc_leader_desc, tikv_gc_leader_lease: the current GC leader information. tikv_gc_run_interval: the interval of GC work. The value is 10 min by default and cannot be smaller than 10 min. tikv_gc_life_time: the retention period of data versions; The value is 10 min by default and cannot be smaller than 10 min.When GC works, the outdated data is cleared. You can set it using the SQL statement. For example, if you want to retain the data within a day, you can execute the operation as below:update mysql.tidb set VARIABLE_VALUE = '24h' where VARIABLE_NAME = 'tikv_gc_life_time'; The duration strings are a sequence of a number with the time unit, such as 24h, 2h30m and 2.5h. The time units you can use include “h”, “m” and “s”. Note: When you set tikv_gc_life_time to a large number (like days or even months) in a scenario where data is updated frequently, some problems as follows may occur: The more versions of the data, the more disk storage space is occupied. A large number of history versions might slow down the query. They may affect range queries like select count(*) from t. If tikv_gc_life_time is suddenly turned to a smaller value during operation, a great deal of old data may be deleted in a short time, causing I/O pressure. tikv_gc_last_run_time: the last time GC works. tikv_gc_safe_point: the time before which versions are cleared by GC and after which versions are readable. tikv_gc_concurrency: the GC concurrency. It is set to 1 by default. In this case, a single thread operates and threads send request to each Region and wait for the response one by one. You can set the variable value larger to improve the system performance, but keep the value smaller than 128. Implementation details The GC implementation process is complex. When the obsolete data is cleared, data consistency is guaranteed. The process of doing GC is as below:1. Resolve locks The TiDB transaction model is inspired by Google’s Percolator. It’s mainly a two-phase commit protocol with some practical optimizations. When the first phase is finished, all the related keys are locked. Among these locks, one is the primary lock and the others are secondary locks which contain a pointer of the primary locks; in the secondary phase, the key with the primary lock gets a write record and its lock is removed. The write record indicates the write or delete operation in the history or the transactional rollback record of this key. Replacing the primary lock with which write record indicates whether the corresponding transaction is committed successfully. Then all the secondary locks are replaced successively. If the threads fail to replace the secondary locks, these locks are retained. During GC, the lock whose timestamp is before the safe point is replaced with the corresponding write record based on the transaction committing status. Note: This is a required step. Once GC has cleared the write record of the primary lock, you can never know whether this transaction is successful or not. As a result, data consistency cannot be guaranteed. 2. Delete ranges DeleteRanges is usually executed after operations like drop table, used to delete a range which might be very large. If the use_delete_range option of TiKV is not enabled, TiKV deletes the keys in the range.3. Do GC Clear the data before the safe point of each key and the write record. Note: If the last record in all the write records of Put and Delete types before the safe point is Put, this record and its data cannot be deleted directly. Otherwise, you cannot successfully perform the read operation whose timestamp is after the safe point and before the next version of the key. "}, {"url": "https://pingcap.com/docs/v2.0/op-guide/gc/", "title": "TiDB Garbage Collection (GC)", "content": " TiDB Garbage Collection (GC) TiDB uses MVCC to control concurrency. When you update or delete data, the original data is not deleted immediately but is kept for a period during which it can be read. Thus the write operation and the read operation are not mutually exclusive and it is possible to read the history versions of the data.The data versions whose duration exceeds a specific time and that are not used any more will be cleared, otherwise they will occupy the disk space and affect TiDB’s performance. TiDB uses Garbage Collection (GC) to clear the obsolete data.Working mechanism GC runs periodically on TiDB. When a TiDB server is started, a gc_worker is enabled in the background. In each TiDB cluster, one gc_worker is elected to be the leader which is used to maintain the GC status and send GC commands to all the TiKV Region leaders.Configuration and monitor The GC configuration and operational status are recorded in the mysql.tidb system table as below, which can be monitored and configured using SQL statements:mysql> select VARIABLE_NAME, VARIABLE_VALUE from mysql.tidb; +-----------------------+------------------------------------------------------------------------------------------------+ | VARIABLE_NAME | VARIABLE_VALUE | +-----------------------+------------------------------------------------------------------------------------------------+ | bootstrapped | True | | tidb_server_version | 18 | | tikv_gc_leader_uuid | 58accebfa7c0004 | | tikv_gc_leader_desc | host:ip-172-16-30-5, pid:95472, start at 2018-04-11 13:43:30.73076656 +0800 CST m=+0.068873865 | | tikv_gc_leader_lease | 20180418-11:02:30 +0800 CST | | tikv_gc_run_interval | 10m0s | | tikv_gc_life_time | 10m0s | | tikv_gc_last_run_time | 20180418-10:59:30 +0800 CST | | tikv_gc_safe_point | 20180418-10:58:30 +0800 CST | | tikv_gc_concurrency | 1 | +-----------------------+------------------------------------------------------------------------------------------------+ 10 rows in set (0.02 sec) In the table above, tikv_gc_run_interval, tikv_gc_life_time and tikv_gc_concurrency can be configured manually. Other variables with the tikv_gc prefix record the current status, which are automatically updated by TiDB. Do not modify these variables. tikv_gc_leader_uuid, tikv_gc_leader_desc, tikv_gc_leader_lease: the current GC leader information. tikv_gc_run_interval: the interval of GC work. The value is 10 min by default and cannot be smaller than 10 min. tikv_gc_life_time: the retention period of data versions; The value is 10 min by default and cannot be smaller than 10 min.When GC works, the outdated data is cleared. You can set it using the SQL statement. For example, if you want to retain the data within a day, you can execute the operation as below:update mysql.tidb set VARIABLE_VALUE = '24h' where VARIABLE_NAME = 'tikv_gc_life_time'; The duration strings are a sequence of a number with the time unit, such as 24h, 2h30m and 2.5h. The time units you can use include “h”, “m” and “s”. Note: When you set tikv_gc_life_time to a large number (like days or even months) in a scenario where data is updated frequently, some problems as follows may occur: The more versions of the data, the more disk storage space is occupied. A large number of history versions might slow down the query. They may affect range queries like select count(*) from t. If tikv_gc_life_time is suddenly turned to a smaller value during operation, a great deal of old data may be deleted in a short time, causing I/O pressure. tikv_gc_last_run_time: the last time GC works. tikv_gc_safe_point: the time before which versions are cleared by GC and after which versions are readable. tikv_gc_concurrency: the GC concurrency. It is set to 1 by default. In this case, a single thread operates and threads send request to each Region and wait for the response one by one. You can set the variable value larger to improve the system performance, but keep the value smaller than 128. Implementation details The GC implementation process is complex. When the obsolete data is cleared, data consistency is guaranteed. The process of doing GC is as below:1. Resolve locks The TiDB transaction model is inspired by Google’s Percolator. It’s mainly a two-phase commit protocol with some practical optimizations. When the first phase is finished, all the related keys are locked. Among these locks, one is the primary lock and the others are secondary locks which contain a pointer of the primary locks; in the secondary phase, the key with the primary lock gets a write record and its lock is removed. The write record indicates the write or delete operation in the history or the transactional rollback record of this key. Replacing the primary lock with which write record indicates whether the corresponding transaction is committed successfully. Then all the secondary locks are replaced successively. If the threads fail to replace the secondary locks, these locks are retained. During GC, the lock whose timestamp is before the safe point is replaced with the corresponding write record based on the transaction committing status. Note: This is a required step. Once GC has cleared the write record of the primary lock, you can never know whether this transaction is successful or not. As a result, data consistency cannot be guaranteed. 2. Delete ranges DeleteRanges is usually executed after operations like drop table, used to delete a range which might be very large. If the use_delete_range option of TiKV is not enabled, TiKV deletes the keys in the range.3. Do GC Clear the data before the safe point of each key and the write record. Note: If the last record in all the write records of Put and Delete types before the safe point is Put, this record and its data cannot be deleted directly. Otherwise, you cannot successfully perform the read operation whose timestamp is after the safe point and before the next version of the key. "}, {"url": "https://pingcap.com/docs/overview/", "title": "TiDB Introduction", "content": " TiDB Introduction TiDB (The pronunciation is: /‘taɪdiːbi:/ tai-D-B, etymology: titanium) is an open-source distributed scalable Hybrid Transactional and Analytical Processing (HTAP) database. It features horizontal scalability, strong consistency, and high availability. TiDB is MySQL compatible and serves as a one-stop data warehouse for both OLTP (Online Transactional Processing) and OLAP (Online Analytical Processing) workloads. Horizontal scalabilityTiDB provides horizontal scalability simply by adding new nodes. Never worry about infrastructure capacity ever again. MySQL compatibilityEasily replace MySQL with TiDB to power your applications without changing a single line of code in most cases and still benefit from the MySQL ecosystem. Distributed transactionTiDB is your source of truth, guaranteeing ACID compliance, so your data is accurate and reliable anytime, anywhere. Cloud NativeTiDB is designed to work in the cloud – public, private, or hybrid – making deployment, provisioning, and maintenance drop-dead simple. Minimize ETLETL (Extract, Transform and Load) is no longer necessary with TiDB’s hybrid OLTP/OLAP architecture, enabling you to create new values for your users, easier and faster. High availabilityWith TiDB, your data and applications are always on and continuously available, so your users are never disappointed. TiDB is designed to support both OLTP and OLAP scenarios. For complex OLAP scenarios, use TiSpark.Read the following three articles to understand TiDB techniques: Data Storage Computing Scheduling "}, {"url": "https://pingcap.com/docs/sql/tidb-memory-control/", "title": "TiDB Memory Control", "content": " TiDB Memory Control Currently, TiDB can track the memory quota of a single SQL query and take actions to prevent OOM (out of memory) or troubleshoot OOM when the memory usage exceeds a specific threshold value. In the TiDB configuration file, you can configure the options as below to control TiDB behaviors when the memory quota exceeds the threshold value:# Valid options: ["log", "cancel"] oom-action = "log" If the configuration item above uses “log”, when the memory quota of a single SQL query exceeds the threshold value which is controlled by the tidb_mem_quota_query variable, TiDB prints an entry of log. Then the SQL query continues to be executed. If OOM occurs, you can find the corresponding SQL query in the log. If the configuration item above uses “cancel”, when the memory quota of a single SQL query exceeds the threshold value, TiDB stops executing the SQL query immediately and returns an error to the client. The error information clearly shows the memory usage of each physical execution operator that consumes much memory in the SQL execution process. Configure the memory quota of a query In the configuration file, you can set the default Memory Quota for each Query. The following example sets it to 32GB:mem-quota-query = 34359738368 In addition, you can control the memory quota of a query using the following session variables. Generally, you only need to configure tidb_mem_quota_query. Other variables are used for advanced configuration which most users do not need to care about. Variable Name Description Unit Default Value tidb_mem_quota_query Control the memory quota of a query Byte 32 << 30 tidb_mem_quota_hashjoin Control the memory quota of “HashJoinExec” Byte 32 << 30 tidb_mem_quota_mergejoin Control the memory quota of “MergeJoinExec” Byte 32 << 30 tidb_mem_quota_sort Control the memory quota of “SortExec” Byte 32 << 30 tidb_mem_quota_topn Control the memory quota of “TopNExec” Byte 32 << 30 tidb_mem_quota_indexlookupreader Control the memory quota of “IndexLookUpExecutor” Byte 32 << 30 tidb_mem_quota_indexlookupjoin Control the memory quota of “IndexLookUpJoin” Byte 32 << 30 tidb_mem_quota_nestedloopapply Control the memory quota of “NestedLoopApplyExec” Byte 32 << 30 Some usage examples:-- Set the threshold value of memory quota for a single SQL query to 8GB: set @@tidb_mem_quota_query = 8 << 30; -- Set the threshold value of memory quota for a single SQL query to 8MB: set @@tidb_mem_quota_query = 8 << 20; -- Set the threshold value of memory quota for a single SQL query to 8KB: set @@tidb_mem_quota_query = 8 << 10;"}, {"url": "https://pingcap.com/docs/v2.0/sql/tidb-memory-control/", "title": "TiDB Memory Control", "content": " TiDB Memory Control Currently, TiDB can track the memory quota of a single SQL query and take actions to prevent OOM (out of memory) or troubleshoot OOM when the memory usage exceeds a specific threshold value. In the TiDB configuration file, you can configure the options as below to control TiDB behaviors when the memory quota exceeds the threshold value:# Valid options: ["log", "cancel"] oom-action = "log" If the configuration item above uses “log”, when the memory quota of a single SQL query exceeds the threshold value which is controlled by the tidb_mem_quota_query variable, TiDB prints an entry of log. Then the SQL query continues to be executed. If OOM occurs, you can find the corresponding SQL query in the log. If the configuration item above uses “cancel”, when the memory quota of a single SQL query exceeds the threshold value, TiDB stops executing the SQL query immediately and returns an error to the client. The error information clearly shows the memory usage of each physical execution operator that consumes much memory in the SQL execution process. Configure the memory quota of a query You can control the memory quota of a query using the following session variables. Generally, you only need to configure tidb_mem_quota_query. Other variables are used for advanced configuration which most users do not need to care about. Variable Name Description Unit Default Value tidb_mem_quota_query Control the memory quota of a query Byte 32 << 30 tidb_mem_quota_hashjoin Control the memory quota of “HashJoinExec” Byte 32 << 30 tidb_mem_quota_mergejoin Control the memory quota of “MergeJoinExec” Byte 32 << 30 tidb_mem_quota_sort Control the memory quota of “SortExec” Byte 32 << 30 tidb_mem_quota_topn Control the memory quota of “TopNExec” Byte 32 << 30 tidb_mem_quota_indexlookupreader Control the memory quota of “IndexLookUpExecutor” Byte 32 << 30 tidb_mem_quota_indexlookupjoin Control the memory quota of “IndexLookUpJoin” Byte 32 << 30 tidb_mem_quota_nestedloopapply Control the memory quota of “NestedLoopApplyExec” Byte 32 << 30 Some usage examples:-- Set the threshold value of memory quota for a single SQL query to 8GB: set @@tidb_mem_quota_query = 8 << 30; -- Set the threshold value of memory quota for a single SQL query to 8MB: set @@tidb_mem_quota_query = 8 << 20; -- Set the threshold value of memory quota for a single SQL query to 8KB: set @@tidb_mem_quota_query = 8 << 10;"}, {"url": "https://pingcap.com/docs/op-guide/monitor-overview/", "title": "TiDB Monitoring Framework Overview", "content": " TiDB Monitoring Framework Overview The TiDB monitoring framework adopts two open source projects: Prometheus and Grafana. TiDB uses Prometheus to store the monitoring and performance metrics and Grafana to visualize these metrics.About Prometheus in TiDB As a time series database, Prometheus has a multi-dimensional data model and flexible query language. As one of the most popular open source projects, many companies and organizations have adopted Prometheus, and the project has a very active community. PingCAP is one of the active developers and adopters of Prometheus for monitoring and alerting in TiDB, TiKV and PD.Prometheus consists of multiple components. Currently, TiDB uses the following of them: The Prometheus Server to scrape and store time series data. The client libraries to customize necessary metrics in the application. A push GateWay to receive the data from Client Push for the Prometheus main server. An AlertManager for the alerting mechanism. The diagram is as follows:About Grafana in TiDB Grafana is an open source project for analyzing and visualizing metrics. TiDB uses Grafana to display the performance metrics as follows:"}, {"url": "https://pingcap.com/docs/op-guide/tidb-dashboard-info/", "title": "TiDB Monitoring Metrics", "content": " TiDB Monitoring Metrics If you use Ansible to deploy the TiDB cluster, the monitoring system is deployed at the same time. For more information, see TiDB Monitoring Framework Overview.The Grafana dashboard is divided into a series of sub dashboards which include Overview, PD, TiDB, TiKV, Node_exporter, Disk Performance, and so on. A lot of metrics are there to help you diagnose.This document describes some key monitoring metrics displayed on the TiDB dashboard.Key metrics description To understand the key metrics displayed on the TiDB dashboard, check the following list: Query Summary Duration: the execution time of a SQL statement Statement OPS: the statistics of executed SQL statements (including SELECT, INSERT, UPDATE and so on) QPS By Instance: the QPS on each TiDB instance Query Detail Internal SQL OPS: the statistics of the executed SQL statements within TiDB Server Connection Count: the number of clients connected to each TiDB instance Failed Query OPM: the statistics of failed SQL statements, such as grammar mistake, primary key, and so on Heap Memory Usage: the heap memory size used by each TiDB instance Events OPM: the statistics of key events, such as “start”, “close”, “graceful-shutdown”,“kill”, “hang”, and so on Uncommon Error OPM: the statistics of abnormal TiDB errors, including panic, binlog write failure, and so on Transaction Transaction OPS: the statistics of executed transactions Transaction Duration: the execution time of a transaction Session Retry Error OPS: the number of errors encountered during the transaction retry Executor Expensive Executor OPS: the statistics of the operators that consume many system resources, including Merge Join, Hash Join, Index Look Up Join, Hash Agg, Stream Agg, Sort, TopN, and so on Queries Using Plan Cache OPS: the statistics of queries using the Plan Cache Distsql Distsql Duration: the processing time of Distsql statements Distsql QPS: the statistics of Distsql statements KV Errors KV Retry Duration: the time that a KV retry request lasts TiClient Region Error OPS: the number of Region related error messages returned by TiKV KV Backoff OPS: the number of error messages (transaction conflicts and so on) returned by TiKV Lock Resolve OPS: the number of errors related to transaction conflicts Other Errors OPS: the number of other types of errors, including clearing locks and updating SafePoint KV Duration KV Cmd Duration 99: the execution time of KV commands KV Count KV Cmd OPS: the statistics of executed KV commands Txn OPS: the statistics of started transactions Load SafePoint OPS: the statistics of operations that update SafePoint PD Client PD TSO OPS: the number of TSO that TiDB obtains from PD PD TSO Wait Duration: the time it takes TiDB to obtain TSO from PD PD Client CMD OPS: the statistics of commands executed by PD Client PD Client CMD Duration: the time it takes PD Client to execute commands PD Client CMD Fail OPS: the statistics of failed commands executed by PD Client Schema Load Load Schema Duration: the time it takes TiDB to obtain the schema from TiKV Load Schema OPS: the statistics of the schemas that TiDB obtains from TiKV Schema Lease Error OPM: the Schema Lease error, including two types named “change” and “outdate”; an alarm is triggered when an “outdate” error occurs DDL DDL Duration 95: the statistics of DDL statements processing time DDL Batch Add Index Duration 100: the statistics of the time that it takes each Batch to create the index DDL Deploy Syncer Duration: the time consumed by Schema Version Syncer initialization, restart, and clearing up operations Owner Handle Syncer Duration: the time that it takes the DDL Owner to update, obtain, and check the Schema Version Update Self Version Duration: the time consumed by updating the version information of Schema Version Syncer Statistics Auto Analyze Duration 95: the time consumed by automatic ANALYZE Auto Analyze QPS: the statistics of automatic ANALYZE Stats Inaccuracy Rate: the information of the statistics inaccuracy rate Pseudo Estimation OPS: the number of the SQL statements optimized using pseudo statistics Dump Feedback OPS: the number of stored statistical Feedbacks Update Stats OPS: the statistics of using Feedback to update the statistics information Meta AutoID QPS: AutoID related statistics, including three operations (global ID allocation, a single table AutoID allocation, a single table AutoID Rebase) AutoID Duration: the time consumed by AutoID related operations GC Worker Action OPM: the statistics of GC related operations, including run_job, resolve_lock, and delete_range Duration 99: the time consumed by GC related operations GC Failure OPM: the number of failed GC related operations Too Many Locks Error OPM: the number of the error that GC clears up too many locks "}, {"url": "https://pingcap.com/tidb-academy/mysql_dbas/tidb-overview/tidb-platform/", "title": "TiDB Platform", "content": " TiDB Platform Transcript When comparing TiDB to MySQL and discussing architecture, not everything is an apples-to-apples comparison. While TiDB speaks the MySQL protocol, it is important to clarify it does not share any MySQL source code in common.TiDB is a NewSQL database that was inspired by the design of Google’s internal Spanner project. It is distributed by design and consists of several components that together make what we call the TiDB Platform. So let’s go over what each of those components are: To start with, we have TiKV. TiKV is a distributed transactional key-value store. Its role in the TiDB platform is to provide scale out storage with native replication to provide high availability. Using MySQL terminology, you can think of every table in the TiDB architecture as automatically partitioned by range. In TiDB terminology, we call each range a “Region”, and automatically re-partition as required to keep the Regions at 96MB each (though this size is configurable depending on use case).TiKV keeps three copies of each Region by default, and uses Raft to ensure that this redundancy is always maintained. We won’t go into Raft in this course but it is a popular consensus protocol used in distributed systems to maintain quorum.Also, don’t let the KV name fool you; unlike other key-value stores, it is an ACID compliant store, and also preserves key order, so you can perform range operations like between X and Y. It forms the storage foundation for which the TiDB platform is built. Sitting above TiKV is TiDB. TiDB is the component that speaks the MySQL protocol, and converts it to requests to be sent to TiKV. It doesn’t store any data itself, which makes it stateless and very easy to scale. A simplified way of thinking of it is like an intelligent proxy which translates SQL into KV requests. It’s worth emphasizing that we built this layer from scratch in order to take advantage of the distributed nature of TiKV, which I’ll do a deep dive on when we talk about Coprocessor. Just remember for now that it’s not a MySQL fork. The last mandatory component to describe is Placement Driver or PD. PD is the cluster manager. It handles all of the TiKV Region rebalancing when there are data hotspots, or Regions that require merging. It is also responsible for the metadata such as SQL DDL. One of the critical services PD also provides is time synchronization for the TiDB platform. We will cover more on what that means and why it is required later. So a quick recap on the mandatory components and their roles: TiKV provides scale out storage. It natively replicates data between nodes and keeps redundancy. TiDB provides a stateless SQL layer that speaks MySQL. PD provides cluster management. In this course, we will use the terms TiDB Platform to refer to all of the components collectively, and TiDB server to refer to the stateless SQL layer. While outside the scope of this course, it is technically possible to run TiKV without TiDB and just use a key-value interface directly to your data."}, {"url": "https://pingcap.com/docs-cn/releases/prega/", "title": "TiDB Pre-GA Release Notes", "content": " TiDB Pre-GA Release Notes 2017 年 8 月 30 日,TiDB 发布 Pre-GA 版。该版本对 MySQL 兼容性、SQL 优化器、系统稳定性、性能做了大量的工作。TiDB: SQL 查询优化器 调整代价模型 优化索引选择,支持不同类型字段比较的索引选择 支持基于贪心算法的 Join Reorder 大量 MySQL 兼容性相关功能 支持 Natural Join 完成 JSON 类型支持 (Experimental),包括对 JSON 中的字段查询、更新、建索引 裁剪无用数据,减小执行器内存消耗 支持在 SQL 语句中设置优先级,并根据查询类型自动设置部分语句的优先级 完成表达式重构,执行速度提升 30% 左右 PD: 支持手动切换 PD 集群 Leader TiKV: Raft Log 使用独立的 RocksDB 实例 使用 DeleteRange 加快删除副本速度 Coprocessor 支持更多运算符下推 提升性能,提升稳定性 TiSpark Beta Release: 支持谓词下推 支持聚合下推 支持范围裁剪 通过 TPC-H 测试 (除去一个需要 View 的 Query) "}, {"url": "https://pingcap.com/docs-cn/v1.0/releases/prega/", "title": "TiDB Pre-GA Release Notes", "content": " TiDB Pre-GA Release Notes 8 月 30 日,TiDB 发布 Pre-GA 版。该版本对 MySQL 兼容性、SQL 优化器、系统稳定性、性能做了大量的工作。TiDB: SQL 查询优化器 调整代价模型 优化索引选择,支持不同类型字段比较的索引选择 支持基于贪心算法的 Join Reorder 大量 MySQL 兼容性相关功能 支持 Natural Join 完成 JSON 类型支持 (Experimental),包括对 JSON 中的字段查询、更新、建索引 裁剪无用数据,减小执行器内存消耗 支持在 SQL 语句中设置优先级,并根据查询类型自动设置部分语句的优先级 完成表达式重构,执行速度提升 30% 左右 PD: 支持手动切换 PD 集群 Leader TiKV: Raft Log 使用独立的 RocksDB 实例 使用 DeleteRange 加快删除副本速度 Coprocessor 支持更多运算符下推 提升性能,提升稳定性 TiSpark Beta Release: 支持谓词下推 支持聚合下推 支持范围裁剪 通过 TPC-H 测试 (除去一个需要 View 的 Query) "}, {"url": "https://pingcap.com/docs-cn/v2.0/releases/prega/", "title": "TiDB Pre-GA Release Notes", "content": " TiDB Pre-GA Release Notes 8 月 30 日,TiDB 发布 Pre-GA 版。该版本对 MySQL 兼容性、SQL 优化器、系统稳定性、性能做了大量的工作。TiDB: SQL 查询优化器 调整代价模型 优化索引选择,支持不同类型字段比较的索引选择 支持基于贪心算法的 Join Reorder 大量 MySQL 兼容性相关功能 支持 Natural Join 完成 JSON 类型支持 (Experimental),包括对 JSON 中的字段查询、更新、建索引 裁剪无用数据,减小执行器内存消耗 支持在 SQL 语句中设置优先级,并根据查询类型自动设置部分语句的优先级 完成表达式重构,执行速度提升 30% 左右 PD: 支持手动切换 PD 集群 Leader TiKV: Raft Log 使用独立的 RocksDB 实例 使用 DeleteRange 加快删除副本速度 Coprocessor 支持更多运算符下推 提升性能,提升稳定性 TiSpark Beta Release: 支持谓词下推 支持聚合下推 支持范围裁剪 通过 TPC-H 测试 (除去一个需要 View 的 Query) "}, {"url": "https://pingcap.com/docs/QUICKSTART/", "title": "TiDB Quick Start Guide", "content": " TiDB Quick Start Guide As an open source distributed scalable HTAP database, TiDB can be deployed on-premise or in-cloud. The following deployment options are officially supported by PingCAP. Ansible Deployment: This guide describes how to deploy TiDB using Ansible. It is strongly recommended for production deployment. Ansible Offline Deployment: If your environment has no access to the internet, you can follow this guide to see how to deploy a TiDB cluster offline using Ansible. Docker Deployment: This guide describes how to deploy TiDB using Docker. Docker Compose Deployment: This guide describes how to deploy TiDB using Docker compose. You can follow this guide to quickly deploy a TiDB cluster for testing and development on your local drive. Kubernetes Deployment (beta): This guide describes how to deploy TiDB on Kubernetes using TiDB Operator. You can follow this guide to see how to deploy TiDB on Google Kubernetes Engine or deploy TiDB locally using Docker in Docker. Community Provided Blog Posts & Tutorials The following list collects deployment guides and tutorials from the community. The content is subject to change by the contributors. How To Spin Up an HTAP Database in 5 Minutes with TiDB + TiSpark Developer install guide (single machine) Your contribution is also welcome! Feel free to open a pull request to add additional links.Source Code Source code for all components of the TiDB platform is available on GitHub. TiDB TiKV PD TiSpark TiDB Operator "}, {"url": "https://pingcap.com/docs/v1.0/QUICKSTART/", "title": "TiDB Quick Start Guide", "content": " TiDB Quick Start Guide About TiDB TiDB (The pronunciation is: /’taɪdiːbi:/ tai-D-B, etymology: titanium) is a Hybrid Transactional/Analytical Processing (HTAP) database. Inspired by the design of Google F1 and Google Spanner, TiDB features infinite horizontal scalability, strong consistency, and high availability. The goal of TiDB is to serve as a one-stop solution for online transactions and analyses.About this guide This guide outlines how to perform a quick deployment of a TiDB cluster using TiDB-Ansible and walks you through the basic TiDB operations and administrations.Deploy the TiDB cluster This section describes how to deploy a TiDB cluster. A TiDB cluster consists of different components: TiDB servers, TiKV servers, and Placement Driver (PD) servers.The architecture is as follows:For details of deploying a TiDB cluster, see Ansible Deployment.Try TiDB This section describes some basic CRUD operations in TiDB.Create, show, and drop a database You can use the CREATE DATABASE statement to create a database.The Syntax is as follows:CREATE DATABASE db_name [options]; For example, the following statement creates a database with the name samp_db:CREATE DATABASE IF NOT EXISTS samp_db; You can use the SHOW DATABASES statement to show the databases:SHOW DATABASES; You can use the DROP DATABASE statement to delete a database, for example:DROP DATABASE samp_db; Create, show, and drop a table Use the CREATE TABLE statement to create a table. The Syntax is as follows:CREATE TABLE table_name column_name data_type constraint; For example:CREATE TABLE person ( number INT(11), name VARCHAR(255), birthday DATE ); Add IF NOT EXISTS to prevent an error if the table exists:CREATE TABLE IF NOT EXISTS person ( number INT(11), name VARCHAR(255), birthday DATE ); Use the SHOW CREATE statement to see the statement that creates the table. For example:SHOW CREATE table person; Use the SHOW FULL COLUMNS statement to display the information about all the columns in a table. For example:SHOW FULL COLUMNS FROM person; Use the DROP TABLE statement to delete a table. For example:DROP TABLE person; orDROP TABLE IF EXISTS person; Use the SHOW TABLES statement to show all the tables in a database. For example:SHOW TABLES FROM samp_db; Create, show, and drop an index For the columns whose value is not unique, you can use the CREATE INDEX or ALTER TABLE statements. For example:CREATE INDEX person_num ON person (number); orALTER TABLE person ADD INDEX person_num (number); You can also create unique indexes for the columns whose value is unique. For example:CREATE UNIQUE INDEX person_num ON person (number); orALTER TABLE person ADD UNIQUE person_num on (number); Use the SHOW INDEX to display all the indexes in a table:SHOW INDEX from person; Use the ALTER TABLE or DROP INDEX to delete an index. Like the CREATE INDEX statement, DROP INDEX can also be embedded in the ALTER TABLE statement. For example:DROP INDEX person_num ON person; ALTER TABLE person DROP INDEX person_num; Insert, select, update, and delete data Use the INSERT statement to insert data into a table. For example:INSERT INTO person VALUES("1","tom","20170912"); Use the SELECT statement to see the data in a table. For example:SELECT * FROM person; +--------+------+------------+ | number | name | birthday | +--------+------+------------+ | 1 | tom | 2017-09-12 | +--------+------+------------+ Use the UPDATE statement to update the data in a table. For example:UPDATE person SET birthday='20171010' WHERE name='tom'; SELECT * FROM person; +--------+------+------------+ | number | name | birthday | +--------+------+------------+ | 1 | tom | 2017-10-10 | +--------+------+------------+ Use the DELETE statement to delete the data in a table. For example:DELETE FROM person WHERE number=1; SELECT * FROM person; Empty set (0.00 sec) Create, authorize, and delete a user Use the CREATE USER statement to create a user named tiuser with the password 123456:CREATE USER 'tiuser'@'localhost' IDENTIFIED BY '123456'; Grant tiuser the privilege to retrieve the tables in the samp_db database:GRANT SELECT ON samp_db .* TO 'tiuser'@'localhost'; Check the privileges of tiuser:SHOW GRANTS for tiuser@localhost; Delete tiuser:DROP USER 'tiuser'@'localhost'; Monitor the TiDB cluster Open a browser to access the monitoring platform: http://172.16.10.3:3000.The default account and password are: admin/admin.About the key metrics Service Panel Name Description Normal Range PD Storage Capacity the total storage capacity of the TiDB cluster PD Current Storage Size the occupied storage capacity of the TiDB cluster PD Store Status – up store the number of TiKV nodes that are up PD Store Status – down store the number of TiKV nodes that are down 0. If the number is bigger than 0, it means some node(s) are not down. PD Store Status – offline store the number of TiKV nodes that are manually offline PD Store Status – Tombstone store the number of TiKV nodes that are Tombstone PD Current storage usage the storage occupancy rate of the TiKV cluster If it exceeds 80%, you need to consider adding more TiKV nodes. PD 99% completed cmds duration seconds the 99th percentile duration to complete a pd-server request less than 5ms PD average completed cmds duration seconds the average duration to complete a pd-server request less than 50ms PD leader balance ratio the leader ratio difference of the nodes with the biggest leader ratio and the smallest leader ratio It is less than 5% for a balanced situation. It becomes bigger when a node is restarting. PD region balance ratio the region ratio difference of the nodes with the biggest region ratio and the smallest region ratio It is less than 5% for a balanced situation. It becomes bigger when adding or removing a node. TiDB handle requests duration seconds the response time to get TSO from PD less than 100ms TiDB tidb server QPS the QPS of the cluster application specific TiDB connection count the number of connections from application servers to the database Application specific. If the number of connections hops, you need to find out the reasons. If it drops to 0, you can check if the network is broken; if it surges, you need to check the application. TiDB statement count the number of different types of statement within a given time application specific TiDB Query Duration 99th percentile the 99th percentile query time TiKV 99% & 99.99% scheduler command duration the 99th percentile and 99.99th percentile scheduler command duration For 99%, it is less than 50ms; for 99.99%, it is less than 100ms. TiKV 95% & 99.99% storage async_request duration the 95th percentile and 99.99th percentile Raft command duration For 95%, it is less than 50ms; for 99.99%, it is less than 100ms. TiKV server report failure message There might be an issue with the network or the message might not come from this cluster. If there are large amount of messages which contains unreachable, there might be an issue with the network. If the message contains store not match, the message does not come from this cluster. TiKV Vote the frequency of the Raft vote Usually, the value only changes when there is a split. If the value of Vote remains high for a long time, the system might have a severe issue and some nodes are not working. TiKV 95% and 99% coprocessor request duration the 95th percentile and the 99th percentile coprocessor request duration Application specific. Usually, the value does not remain high. TiKV Pending task the number of pending tasks Except for PD worker, it is not normal if the value is too high. TiKV stall RocksDB stall time If the value is bigger than 0, it means that RocksDB is too busy, and you need to pay attention to IO and CPU usage. TiKV channel full The channel is full and the threads are too busy. If the value is bigger than 0, the …"}, {"url": "https://pingcap.com/docs/v2.0/QUICKSTART/", "title": "TiDB Quick Start Guide", "content": " TiDB Quick Start Guide About TiDB TiDB (The pronunciation is: /‘taɪdiːbi:/ tai-D-B, etymology: titanium) is an open-source distributed scalable Hybrid Transactional and Analytical Processing (HTAP) database. It features infinite horizontal scalability, strong consistency, and high availability. TiDB is MySQL compatible and serves as a one-stop data warehouse for both OLTP (Online Transactional Processing) and OLAP (Online Analytical Processing) workloads.About this guide This guide outlines how to perform a quick deployment of a TiDB cluster using TiDB-Ansible and walks you through the basic TiDB operations and administrations.Deploy the TiDB cluster This section describes how to deploy a TiDB cluster. A TiDB cluster consists of different components: TiDB servers, TiKV servers, and Placement Driver (PD) servers.The architecture is as follows:To quickly deploy a TiDB testing cluster, see Deploy TiDB Using Docker Compose.Try TiDB This section describes some basic CRUD operations in TiDB.Create, show, and drop a database To create a database, use the CREATE DATABASE statement. The Syntax is as follows:CREATE DATABASE db_name [options]; For example, the following statement creates a database with the name samp_db:CREATE DATABASE IF NOT EXISTS samp_db; To show the databases, use the SHOW DATABASES statement:SHOW DATABASES; To delete a database, use the DROP DATABASE statement. For example:DROP DATABASE samp_db; Create, show, and drop a table To create a table, use the CREATE TABLE statement. The Syntax is as follows:CREATE TABLE table_name column_name data_type constraint; For example:CREATE TABLE person ( number INT(11), name VARCHAR(255), birthday DATE ); Add IF NOT EXISTS to prevent an error if the table exists:CREATE TABLE IF NOT EXISTS person ( number INT(11), name VARCHAR(255), birthday DATE ); To view the statement that creates the table, use the SHOW CREATE statement. For example:SHOW CREATE table person; To show all the tables in a database, use the SHOW TABLES statement. For example:SHOW TABLES FROM samp_db; To show the information about all the columns in a table, use the SHOW FULL COLUMNS statement. For example:SHOW FULL COLUMNS FROM person; To delete a table, use the DROP TABLE statement. For example:DROP TABLE person; orDROP TABLE IF EXISTS person; Create, show, and drop an index To create an index for the column whose value is not unique, use the CREATE INDEX or ALTER TABLE statement. For example:CREATE INDEX person_num ON person (number); orALTER TABLE person ADD INDEX person_num (number); To create a unique index for the column whose value is unique, use the CREATE UNIQUE INDEX or ALTER TABLE statement. For example:CREATE UNIQUE INDEX person_num ON person (number); orALTER TABLE person ADD UNIQUE person_num on (number); To show all the indexes in a table, use the SHOW INDEX statement:SHOW INDEX from person; To delete an index, use the DROP INDEX or ALTER TABLE statement. For example:DROP INDEX person_num ON person; ALTER TABLE person DROP INDEX person_num; Insert, select, update, and delete data To insert data into a table, use the INSERT statement. For example:INSERT INTO person VALUES("1","tom","20170912"); To view the data in a table, use the SELECT statement. For example:SELECT * FROM person; +--------+------+------------+ | number | name | birthday | +--------+------+------------+ | 1 | tom | 2017-09-12 | +--------+------+------------+ To update the data in a table, use the UPDATE statement. For example:UPDATE person SET birthday='20171010' WHERE name='tom'; SELECT * FROM person; +--------+------+------------+ | number | name | birthday | +--------+------+------------+ | 1 | tom | 2017-10-10 | +--------+------+------------+ To delete the data in a table, use the DELETE statement. For example:DELETE FROM person WHERE number=1; SELECT * FROM person; Empty set (0.00 sec) Create, authorize, and delete a user To create a user, use the CREATE USER statement. The following example creates a user named tiuser with the password 123456:CREATE USER 'tiuser'@'localhost' IDENTIFIED BY '123456'; To grant tiuser the privilege to retrieve the tables in the samp_db database:GRANT SELECT ON samp_db.* TO 'tiuser'@'localhost'; To check the privileges of tiuser:SHOW GRANTS for tiuser@localhost; To delete tiuser:DROP USER 'tiuser'@'localhost'; Monitor the TiDB cluster Open a browser to access the monitoring platform: http://172.16.10.3:3000.The default account and password are: admin/admin.About the key metrics Service Panel Name Description Normal Range PD Storage Capacity the total storage capacity of the TiDB cluster PD Current Storage Size the occupied storage capacity of the TiDB cluster PD Store Status – up store the number of TiKV nodes that are up PD Store Status – down store the number of TiKV nodes that are down 0. If the number is bigger than 0, it means some node(s) are not down. PD Store Status – offline store the number of TiKV nodes that are manually offline PD Store Status – Tombstone store the number of TiKV nodes that are Tombstone PD Current storage usage the storage occupancy rate of the TiKV cluster If it exceeds 80%, you need to consider adding more TiKV nodes. PD 99% completed cmds duration seconds the 99th percentile duration to complete a pd-server request less than 5ms PD average completed cmds duration seconds the average duration to complete a pd-server request less than 50ms PD leader balance ratio the leader ratio difference of the nodes with the biggest leader ratio and the smallest leader ratio It is less than 5% for a balanced situation. It becomes bigger when a node is restarting. PD region balance ratio the region ratio difference of the nodes with the biggest region ratio and the smallest region ratio It is less than 5% for a balanced situation. It becomes bigger when adding or removing a node. TiDB handle requests duration seconds the response time to get TSO from PD less than 100ms TiDB tidb server QPS the QPS of the cluster application specific TiDB connection count the number of connections from application servers to the database Application specific. If the number of connections hops, you need to find out the reasons. If it drops to 0, you can check if the network is broken; if it surges, you need to check the application. TiDB statement count the number of different types of statement within a given time application specific TiDB Query Duration 99th percentile the 99th percentile query time TiKV 99% & 99.99% scheduler command duration the 99th percentile and 99.99th percentile scheduler command duration For 99%, it is less than 50ms; for 99.99%, it is less than 100ms. TiKV 95% & 99.99% storage async_request duration the 95th percentile and 99.99th percentile Raft command duration For 95%, it is less than 50ms; for 99.99%, it is less than 100ms. TiKV server report failure message There might be an issue with the network or the message might not come from this cluster. If there are large amount of messages which contains unreachable, there might be an issue with the network. If the message contains store not match, the message does not come from this cluster. TiKV Vote the frequency of the Raft vote Usually, the value only changes when there is a split. If the value of Vote remains high for a long time, the system might have a severe issue and some nodes are not working. TiKV 95% and 99% coprocessor request duration the 95th percentile and the 99th percentile coprocessor request duration Application specific. Usually, the value does not remain high. TiKV Pending task the number of pending tasks Except for PD worker, it is not normal if the value is too high. TiKV stall RocksDB stall time If the value is bigger than 0, it means that RocksDB is too busy, and you need to pay attention to IO and CPU usage. TiKV …"}, {"url": "https://pingcap.com/docs-cn/releases/rc1/", "title": "TiDB RC1 Release Notes", "content": " TiDB RC1 Release Notes 2016 年 12 月 23 日,分布式关系型数据库 TiDB 正式发布 RC1。TiKV + 提升写入速度 + 降低磁盘空间占用 + 支持百 TB 级别数据 + 提升稳定性,集群规模支持 200 个节点 + 提供 Raw KV API,以及 Golang client PD + PD 调度策略框架优化,策略更加灵活合理 + 添加 label 支持,支持跨 DC 调度 + 提供 PD Controler,方便操作 PD 集群 TiDB + SQL 查询优化器 - 支持 eager aggregate - 更详细的 explain 信息 - union 算子并行化 - 子查询性能优化 - 条件下推优化 - 优化 CBO 框架 + 重构 time 相关类型的实现,提升和 MySQL 的兼容性 + 支持更多的 MySQL 内建函数 + Add Index 语句提速 + 支持用 change column 语句修改列名;支持使用 Alter table 的 modify column 和 change column 完成部分列类型转换 工具 + Loader:兼容 Percona 的 mydumper 数据格式,提供多线程导入、出错重试、断点续传等功能,并且针对 TiDB 有优化 + 开发完成一键部署工具"}, {"url": "https://pingcap.com/docs-cn/v1.0/releases/rc1/", "title": "TiDB RC1 Release Notes", "content": " TiDB RC1 Release Notes 2016 年 12 月 23 日,分布式关系型数据库 TiDB 正式发布 RC1。TiKV + 提升写入速度 + 降低磁盘空间占用 + 支持百 TB 级别数据 + 提升稳定性,集群规模支持 200 个节点 + 提供 Raw KV API,以及 Golang client PD + PD 调度策略框架优化,策略更加灵活合理 + 添加 label 支持,支持跨 DC 调度 + 提供 PD Controler,方便操作 PD 集群 TiDB + SQL 查询优化器 - 支持 eager aggregate - 更详细的 explain 信息 - union 算子并行化 - 子查询性能优化 - 条件下推优化 - 优化 CBO 框架 + 重构 time 相关类型的实现,提升和 MySQL 的兼容性 + 支持更多的 MySQL 内建函数 + Add Index 语句提速 + 支持用 change column 语句修改列名;支持使用 Alter table 的 modify column 和 change column 完成部分列类型转换 工具 + Loader:兼容 Percona 的 mydumper 数据格式,提供多线程导入、出错重试、断点续传等功能,并且针对 TiDB 有优化 + 开发完成一键部署工具"}, {"url": "https://pingcap.com/docs-cn/v2.0/releases/rc1/", "title": "TiDB RC1 Release Notes", "content": " TiDB RC1 Release Notes 2016 年 12 月 23 日,分布式关系型数据库 TiDB 正式发布 RC1。TiKV + 提升写入速度 + 降低磁盘空间占用 + 支持百 TB 级别数据 + 提升稳定性,集群规模支持 200 个节点 + 提供 Raw KV API,以及 Golang client PD + PD 调度策略框架优化,策略更加灵活合理 + 添加 label 支持,支持跨 DC 调度 + 提供 PD Controler,方便操作 PD 集群 TiDB + SQL 查询优化器 - 支持 eager aggregate - 更详细的 explain 信息 - union 算子并行化 - 子查询性能优化 - 条件下推优化 - 优化 CBO 框架 + 重构 time 相关类型的实现,提升和 MySQL 的兼容性 + 支持更多的 MySQL 内建函数 + Add Index 语句提速 + 支持用 change column 语句修改列名;支持使用 Alter table 的 modify column 和 change column 完成部分列类型转换 工具 + Loader:兼容 Percona 的 mydumper 数据格式,提供多线程导入、出错重试、断点续传等功能,并且针对 TiDB 有优化 + 开发完成一键部署工具"}, {"url": "https://pingcap.com/docs/releases/rc1/", "title": "TiDB RC1 Release Notes", "content": " TiDB RC1 Release Notes On December 23, 2016, TiDB RC1 is released. See the following updates in this release:TiKV: The write speed has been improved. The disk space usage is reduced. Hundreds of TBs of data can be supported. The stability is improved and TiKV can support a cluster with 200 nodes. Supports the Raw KV API and the Golang client. Placement Driver (PD): + The scheduling strategy framework is optimized and now the strategy is more flexible and reasonable. + The support for label is added to support Cross Data Center scheduling. + PD Controller is provided to operate the PD cluster more easily.TiDB: The following features are added or improved in the SQL query optimizer: Eager aggregation More detailed EXPLAIN information Parallelization of the UNION operator Optimization of the subquery performance Optimization of the conditional push-down Optimization of the Cost Based Optimizer (CBO) framework The implementation of the time related data types are refactored to improve the compatibility with MySQL. More built-in functions in MySQL are supported. The speed of the add index statement is enhanced. The following statements are supported: Use the CHANGE COLUMN statement to change the name of a column. Use MODIFY COLUMN and CHANGE COLUMN of the ALTER TABLE statement for some of the column type transfer. New tools: Loader is added to be compatible with the mydumper data format in Percona and provides the following functions: Multi-thread import Retry if error occurs Breakpoint resume Targeted optimization for TiDB The tool for one-click deployment is added. "}, {"url": "https://pingcap.com/docs/v1.0/releases/rc1/", "title": "TiDB RC1 Release Notes", "content": " TiDB RC1 Release Notes On December 23, 2016, TiDB RC1 is released. See the following updates in this release:TiKV: The write speed has been improved. The disk space usage is reduced. Hundreds of TBs of data can be supported. The stability is improved and TiKV can support a cluster with 200 nodes. Supports the Raw KV API and the Golang client. Placement Driver (PD): + The scheduling strategy framework is optimized and now the strategy is more flexible and reasonable. + The support for label is added to support Cross Data Center scheduling. + PD Controller is provided to operate the PD cluster more easily.TiDB: The following features are added or improved in the SQL query optimizer: Eager aggregation More detailed EXPLAIN information Parallelization of the UNION operator Optimization of the subquery performance Optimization of the conditional push-down Optimization of the Cost Based Optimizer (CBO) framework The implementation of the time related data types are refactored to improve the compatibility with MySQL. More built-in functions in MySQL are supported. The speed of the add index statement is enhanced. The following statements are supported: Use the CHANGE COLUMN statement to change the name of a column. Use MODIFY COLUMN and CHANGE COLUMN of the ALTER TABLE statement for some of the column type transfer. New tools: Loader is added to be compatible with the mydumper data format in Percona and provides the following functions: Multi-thread import Retry if error occurs Breakpoint resume Targeted optimization for TiDB The tool for one-click deployment is added. "}, {"url": "https://pingcap.com/docs/v2.0/releases/rc1/", "title": "TiDB RC1 Release Notes", "content": " TiDB RC1 Release Notes On December 23, 2016, TiDB RC1 is released. See the following updates in this release:TiKV: The write speed has been improved. The disk space usage is reduced. Hundreds of TBs of data can be supported. The stability is improved and TiKV can support a cluster with 200 nodes. Supports the Raw KV API and the Golang client. Placement Driver (PD): + The scheduling strategy framework is optimized and now the strategy is more flexible and reasonable. + The support for label is added to support Cross Data Center scheduling. + PD Controller is provided to operate the PD cluster more easily.TiDB: The following features are added or improved in the SQL query optimizer: Eager aggregation More detailed EXPLAIN information Parallelization of the UNION operator Optimization of the subquery performance Optimization of the conditional push-down Optimization of the Cost Based Optimizer (CBO) framework The implementation of the time related data types are refactored to improve the compatibility with MySQL. More built-in functions in MySQL are supported. The speed of the add index statement is enhanced. The following statements are supported: Use the CHANGE COLUMN statement to change the name of a column. Use MODIFY COLUMN and CHANGE COLUMN of the ALTER TABLE statement for some of the column type transfer. New tools: Loader is added to be compatible with the mydumper data format in Percona and provides the following functions: Multi-thread import Retry if error occurs Breakpoint resume Targeted optimization for TiDB The tool for one-click deployment is added. "}, {"url": "https://pingcap.com/docs-cn/releases/rc2/", "title": "TiDB RC2 Release Notes", "content": " TiDB RC2 Release Notes 2017 年 3 月 1 日,TiDB 正式发布 RC2 版。该版本对 MySQL 兼容性、SQL 优化器、系统稳定性、性能做了大量的工作。对于 OLTP 场景,读取性能提升 60%,写入性能提升 30%。另外提供了权限管理功能,用户可以按照 MySQL 的权限管理方式控制数据访问权限。TiDB SQL 查询优化器 统计信息收集和使用 关联子查询优化 优化 CBO 框架 通过 Unique Key 信息消除聚合 重构 Expression Distinct 转换为 GroupBy 支持 topn 操作下推 支持基本权限管理 新增大量 MySQL 内建函数 完善 Alter Table 语句,支持修改表名、默认值、注释 支持 Create Table Like 语句 支持 Show Warnings 语句 支持 Rename Table 语句 限制单个事务大小,避免大事务阻塞整个集群 Load Data 过程中对数据进行自动拆分 优化 AddIndex、Delete 语句性能 支持 “ANSI_QUOTES” sql_mode 完善监控 修复 Bug 修复内存泄漏问题 PD 支持 Label 对副本进行 Location 调度 基于 region 数量的快速调度 pd-ctl 支持更多功能 添加、删除 PD 通过 Key 获取 Region 信息 添加、删除 scheduler 和 operator 获取集群 label 信息 TiKV 支持 Async Apply 提升整体写入性能 使用 prefix seek 提升 Write CF 的读取性能 使用 memory hint prefix 提升 Raft CF 插入性能 优化单行读事务性能 支持更多下推功能 加入更多统计 修复 Bug "}, {"url": "https://pingcap.com/docs-cn/v1.0/releases/rc2/", "title": "TiDB RC2 Release Notes", "content": " TiDB RC2 Release Notes 2017 年 3 月 1 日,TiDB 正式发布 RC2 版。该版本对 MySQL 兼容性、SQL 优化器、系统稳定性、性能做了大量的工作。对于 OLTP 场景,读取性能提升 60%,写入性能提升 30%。另外提供了权限管理功能,用户可以按照 MySQL 的权限管理方式控制数据访问权限。TiDB SQL 查询优化器 统计信息收集和使用 关联子查询优化 优化 CBO 框架 通过 Unique Key 信息消除聚合 重构 Expression Distinct 转换为 GroupBy 支持 topn 操作下推 支持基本权限管理 新增大量 MySQL 内建函数 完善 Alter Table 语句,支持修改表名、默认值、注释 支持 Create Table Like 语句 支持 Show Warnings 语句 支持 Rename Table 语句 限制单个事务大小,避免大事务阻塞整个集群 Load Data 过程中对数据进行自动拆分 优化 AddIndex、Delete 语句性能 支持 “ANSI_QUOTES” sql_mode 完善监控 修复 Bug 修复内存泄漏问题 PD 支持 Label 对副本进行 Location 调度 基于 region 数量的快速调度 pd-ctl 支持更多功能 添加、删除 PD 通过 Key 获取 Region 信息 添加、删除 scheduler 和 operator 获取集群 label 信息 TiKV 支持 Async Apply 提升整体写入性能 使用 prefix seek 提升 Write CF 的读取性能 使用 memory hint prefix 提升 Raft CF 插入性能 优化单行读事务性能 支持更多下推功能 加入更多统计 修复 Bug "}, {"url": "https://pingcap.com/docs-cn/v2.0/releases/rc2/", "title": "TiDB RC2 Release Notes", "content": " TiDB RC2 Release Notes 2017 年 3 月 1 日,TiDB 正式发布 RC2 版。该版本对 MySQL 兼容性、SQL 优化器、系统稳定性、性能做了大量的工作。对于 OLTP 场景,读取性能提升 60%,写入性能提升 30%。另外提供了权限管理功能,用户可以按照 MySQL 的权限管理方式控制数据访问权限。TiDB SQL 查询优化器 统计信息收集和使用 关联子查询优化 优化 CBO 框架 通过 Unique Key 信息消除聚合 重构 Expression Distinct 转换为 GroupBy 支持 topn 操作下推 支持基本权限管理 新增大量 MySQL 内建函数 完善 Alter Table 语句,支持修改表名、默认值、注释 支持 Create Table Like 语句 支持 Show Warnings 语句 支持 Rename Table 语句 限制单个事务大小,避免大事务阻塞整个集群 Load Data 过程中对数据进行自动拆分 优化 AddIndex、Delete 语句性能 支持 “ANSI_QUOTES” sql_mode 完善监控 修复 Bug 修复内存泄漏问题 PD 支持 Label 对副本进行 Location 调度 基于 region 数量的快速调度 pd-ctl 支持更多功能 添加、删除 PD 通过 Key 获取 Region 信息 添加、删除 scheduler 和 operator 获取集群 label 信息 TiKV 支持 Async Apply 提升整体写入性能 使用 prefix seek 提升 Write CF 的读取性能 使用 memory hint prefix 提升 Raft CF 插入性能 优化单行读事务性能 支持更多下推功能 加入更多统计 修复 Bug "}, {"url": "https://pingcap.com/docs/releases/rc2/", "title": "TiDB RC2 Release Notes", "content": " TiDB RC2 Release Notes On August 4, 2017, TiDB RC4 is released! This release is focused on the compatibility with MySQL, SQL query optimizer, system stability and performance in this version. What’s more, a new permission management mechanism is added and users can control data access in the same way as the MySQL privilege management system.TiDB: Query optimizer Collect column/index statistics and use them in the query optimizer Optimize the correlated subquery Optimize the Cost Based Optimizer (CBO) framework Eliminate aggregation using unique key information Refactor expression evaluation framework Convert Distinct to GroupBy Support the topn operation push-down Support basic privilege management Add lots of MySQL built-in functions Improve the Alter Table statement and support the modification of table name, default value and comment Support the Create Table Like statement Support the Show Warnings statement Support the Rename Table statement Restrict the size of a single transaction to avoid the cluster blocking of large transactions Automatically split data in the process of Load Data Optimize the performance of the AddIndex and Delete statement Support “ANSI_QUOTES” sql_mode Improve the monitoring system Fix Bugs Solve the problem of memory leak PD: Support location aware replica scheduling Conduct fast scheduling based on the number of region pd-ctl support more features Add or delete PD Obtain Region information with Key Add or delete scheduler and operator Obtain cluster label information TiKV: Support Async Apply to improve the entire write performance Use prefix seek to improve the read performance of Write CF Use memory hint prefix to improve the insert performance of Raft CF Optimize the single read transaction performance Support more push-down expressions Improve the monitoring system Fix Bugs "}, {"url": "https://pingcap.com/docs/v1.0/releases/rc2/", "title": "TiDB RC2 Release Notes", "content": " TiDB RC2 Release Notes On August 4, 2017, TiDB RC4 is released! This release is focused on the compatibility with MySQL, SQL query optimizer, system stability and performance in this version. What’s more, a new permission management mechanism is added and users can control data access in the same way as the MySQL privilege management system.TiDB: Query optimizer Collect column/index statistics and use them in the query optimizer Optimize the correlated subquery Optimize the Cost Based Optimizer (CBO) framework Eliminate aggregation using unique key information Refactor expression evaluation framework Convert Distinct to GroupBy Support the topn operation push-down Support basic privilege management Add lots of MySQL built-in functions Improve the Alter Table statement and support the modification of table name, default value and comment Support the Create Table Like statement Support the Show Warnings statement Support the Rename Table statement Restrict the size of a single transaction to avoid the cluster blocking of large transactions Automatically split data in the process of Load Data Optimize the performance of the AddIndex and Delete statement Support “ANSI_QUOTES” sql_mode Improve the monitoring system Fix Bugs Solve the problem of memory leak PD: Support location aware replica scheduling Conduct fast scheduling based on the number of region pd-ctl support more features Add or delete PD Obtain Region information with Key Add or delete scheduler and operator Obtain cluster label information TiKV: Support Async Apply to improve the entire write performance Use prefix seek to improve the read performance of Write CF Use memory hint prefix to improve the insert performance of Raft CF Optimize the single read transaction performance Support more push-down expressions Improve the monitoring system Fix Bugs "}, {"url": "https://pingcap.com/docs/v2.0/releases/rc2/", "title": "TiDB RC2 Release Notes", "content": " TiDB RC2 Release Notes On August 4, 2017, TiDB RC4 is released! This release is focused on the compatibility with MySQL, SQL query optimizer, system stability and performance in this version. What’s more, a new permission management mechanism is added and users can control data access in the same way as the MySQL privilege management system.TiDB: Query optimizer Collect column/index statistics and use them in the query optimizer Optimize the correlated subquery Optimize the Cost Based Optimizer (CBO) framework Eliminate aggregation using unique key information Refactor expression evaluation framework Convert Distinct to GroupBy Support the topn operation push-down Support basic privilege management Add lots of MySQL built-in functions Improve the Alter Table statement and support the modification of table name, default value and comment Support the Create Table Like statement Support the Show Warnings statement Support the Rename Table statement Restrict the size of a single transaction to avoid the cluster blocking of large transactions Automatically split data in the process of Load Data Optimize the performance of the AddIndex and Delete statement Support “ANSI_QUOTES” sql_mode Improve the monitoring system Fix Bugs Solve the problem of memory leak PD: Support location aware replica scheduling Conduct fast scheduling based on the number of region pd-ctl support more features Add or delete PD Obtain Region information with Key Add or delete scheduler and operator Obtain cluster label information TiKV: Support Async Apply to improve the entire write performance Use prefix seek to improve the read performance of Write CF Use memory hint prefix to improve the insert performance of Raft CF Optimize the single read transaction performance Support more push-down expressions Improve the monitoring system Fix Bugs "}, {"url": "https://pingcap.com/docs-cn/releases/rc3/", "title": "TiDB RC3 Release Notes", "content": " TiDB RC3 Release Notes 2017 年 6 月 16 日,TiDB 正式发布 RC3 版。该版本对 MySQL 兼容性、SQL 优化器、系统稳定性、性能做了大量的工作。性能方面重点优化了负载均衡调度策略和流程。功能方面进一步完善权限管理功能,用户可以按照 MySQL 的权限管理方式控制数据访问权限。另外 DDL 的速度也得到显著的提升。 同时为了简化运维工作,开源了 TiDB-Ansible 项目,可以一键部署/升级/启停 TiDB 集群。TiDB SQL 查询优化器 统计信息收集和使用 关联子查询优化 优化 CBO 框架 通过 Unique Key 信息消除聚合 重构 Expression Distinct 转换为 GroupBy 支持 topn 操作下推 支持基本权限管理 新增大量 MySQL 内建函数 完善 Alter Table 语句,支持修改表名、默认值、注释 支持 Create Table Like 语句 支持 Show Warnings 语句 支持 Rename Table 语句 限制单个事务大小,避免大事务阻塞整个集群 Load Data 过程中对数据进行自动拆分 优化 AddIndex、Delete 语句性能 支持 “ANSI_QUOTES” sql_mode 完善监控 修复 Bug 修复内存泄漏问题 PD 支持 Label 对副本进行 Location 调度 基于 region 数量的快速调度 pd-ctl 支持更多功能 添加、删除 PD 通过 Key 获取 Region 信息 添加、删除 scheduler 和 operator 获取集群 label 信息 TiKV 支持 Async Apply 提升整体写入性能 使用 prefix seek 提升 Write CF 的读取性能 使用 memory hint prefix 提升 Raft CF 插入性能 优化单行读事务性能 支持更多下推功能 加入更多统计 修复 Bug "}, {"url": "https://pingcap.com/docs-cn/v1.0/releases/rc3/", "title": "TiDB RC3 Release Notes", "content": " TiDB RC3 Release Notes 2017 年 6 月 16 日,TiDB 正式发布 RC3 版。该版本对 MySQL 兼容性、SQL 优化器、系统稳定性、性能做了大量的工作。性能方面重点优化了负载均衡调度策略和流程。功能方面进一步完善权限管理功能,用户可以按照 MySQL 的权限管理方式控制数据访问权限。另外 DDL 的速度也得到显著的提升。 同时为了简化运维工作,开源了 TiDB-Ansible 项目,可以一键部署/升级/启停 TiDB 集群。TiDB SQL 查询优化器 统计信息收集和使用 关联子查询优化 优化 CBO 框架 通过 Unique Key 信息消除聚合 重构 Expression Distinct 转换为 GroupBy 支持 topn 操作下推 支持基本权限管理 新增大量 MySQL 内建函数 完善 Alter Table 语句,支持修改表名、默认值、注释 支持 Create Table Like 语句 支持 Show Warnings 语句 支持 Rename Table 语句 限制单个事务大小,避免大事务阻塞整个集群 Load Data 过程中对数据进行自动拆分 优化 AddIndex、Delete 语句性能 支持 “ANSI_QUOTES” sql_mode 完善监控 修复 Bug 修复内存泄漏问题 PD 支持 Label 对副本进行 Location 调度 基于 region 数量的快速调度 pd-ctl 支持更多功能 添加、删除 PD 通过 Key 获取 Region 信息 添加、删除 scheduler 和 operator 获取集群 label 信息 TiKV 支持 Async Apply 提升整体写入性能 使用 prefix seek 提升 Write CF 的读取性能 使用 memory hint prefix 提升 Raft CF 插入性能 优化单行读事务性能 支持更多下推功能 加入更多统计 修复 Bug "}, {"url": "https://pingcap.com/docs-cn/v2.0/releases/rc3/", "title": "TiDB RC3 Release Notes", "content": " TiDB RC3 Release Notes 2017 年 6 月 16 日,TiDB 正式发布 RC3 版。该版本对 MySQL 兼容性、SQL 优化器、系统稳定性、性能做了大量的工作。性能方面重点优化了负载均衡调度策略和流程。功能方面进一步完善权限管理功能,用户可以按照 MySQL 的权限管理方式控制数据访问权限。另外 DDL 的速度也得到显著的提升。 同时为了简化运维工作,开源了 TiDB-Ansible 项目,可以一键部署/升级/启停 TiDB 集群。TiDB SQL 查询优化器 统计信息收集和使用 关联子查询优化 优化 CBO 框架 通过 Unique Key 信息消除聚合 重构 Expression Distinct 转换为 GroupBy 支持 topn 操作下推 支持基本权限管理 新增大量 MySQL 内建函数 完善 Alter Table 语句,支持修改表名、默认值、注释 支持 Create Table Like 语句 支持 Show Warnings 语句 支持 Rename Table 语句 限制单个事务大小,避免大事务阻塞整个集群 Load Data 过程中对数据进行自动拆分 优化 AddIndex、Delete 语句性能 支持 “ANSI_QUOTES” sql_mode 完善监控 修复 Bug 修复内存泄漏问题 PD 支持 Label 对副本进行 Location 调度 基于 region 数量的快速调度 pd-ctl 支持更多功能 添加、删除 PD 通过 Key 获取 Region 信息 添加、删除 scheduler 和 operator 获取集群 label 信息 TiKV 支持 Async Apply 提升整体写入性能 使用 prefix seek 提升 Write CF 的读取性能 使用 memory hint prefix 提升 Raft CF 插入性能 优化单行读事务性能 支持更多下推功能 加入更多统计 修复 Bug "}, {"url": "https://pingcap.com/docs/releases/rc3/", "title": "TiDB RC3 Release Notes", "content": " TiDB RC3 Release Notes On June 20, 2017, TiDB RC4 is released!This release is focused on MySQL compatibility, SQL optimization, stability, and performance.Highlight: The privilege management is refined to enable users to manage the data access privileges using the same way as in MySQL. DDL is accelerated. The load balancing policy and process are optimized for performance. TiDB-Ansible is open sourced. By using TiDB-Ansilbe, you can deploy, upgrade, start and shutdown a TiDB cluster with one click. Detailed updates: TiDB: The following features are added or improved in the SQL query optimizer: Support incremental statistics Support the Merge Sort Join operator Support the Index Lookup Join operator Support the Optimizer Hint Syntax Optimize the memory consumption of the Scan, Join, Aggregation operators Optimize the Cost Based Optimizer (CBO) framework Refactor Expression Support more complete privilege management DDL acceleration Support using HTTP API to get the data distribution information of tables Support using system variables to control the query concurrency Add more MySQL built-in functions Support using system variables to automatically split a big transaction into smaller ones to commit Placement Driver (PD): Support gRPC Provide the Disaster Recovery Toolkit Use Garbage Collection to clear stale data automatically Support more efficient data balance Support hot Region scheduling to enable load balancing and speed up the data importing Performance Accelerate getting Client TSO Improve the efficiency of Region Heartbeat processing Improve the pd-ctl function Update the Replica configuration dynamically Get the Timestamp Oracle (TSO) Use ID to get the Region information TiKV: Support gRPC Support the Sorted String Table (SST) format snapshot to improve the load balancing speed of a cluster Support using the Heap Profile to uncover memory leaks Support Streaming SIMD Extensions (SSE) and speed up the CRC32 calculation Accelerate transferring leader for faster load balancing Use Batch Apply to reduce CPU usage and improve the write performance Support parallel Prewrite to improve the transaction write speed Optimize the scheduling of the coprocessor thread pool to reduce the impact of big queries on point get The new Loader supports data importing at the table level, as well as splitting a big table into smaller logical blocks to import concurrently to improve the data importing speed. "}, {"url": "https://pingcap.com/docs/v1.0/releases/rc3/", "title": "TiDB RC3 Release Notes", "content": " TiDB RC3 Release Notes On June 20, 2017, TiDB RC4 is released!This release is focused on MySQL compatibility, SQL optimization, stability, and performance.Highlight: The privilege management is refined to enable users to manage the data access privileges using the same way as in MySQL. DDL is accelerated. The load balancing policy and process are optimized for performance. TiDB-Ansible is open sourced. By using TiDB-Ansilbe, you can deploy, upgrade, start and shutdown a TiDB cluster with one click. Detailed updates: TiDB: The following features are added or improved in the SQL query optimizer: Support incremental statistics Support the Merge Sort Join operator Support the Index Lookup Join operator Support the Optimizer Hint Syntax Optimize the memory consumption of the Scan, Join, Aggregation operators Optimize the Cost Based Optimizer (CBO) framework Refactor Expression Support more complete privilege management DDL acceleration Support using HTTP API to get the data distribution information of tables Support using system variables to control the query concurrency Add more MySQL built-in functions Support using system variables to automatically split a big transaction into smaller ones to commit Placement Driver (PD): Support gRPC Provide the Disaster Recovery Toolkit Use Garbage Collection to clear stale data automatically Support more efficient data balance Support hot Region scheduling to enable load balancing and speed up the data importing Performance Accelerate getting Client TSO Improve the efficiency of Region Heartbeat processing Improve the pd-ctl function Update the Replica configuration dynamically Get the Timestamp Oracle (TSO) Use ID to get the Region information TiKV: Support gRPC Support the Sorted String Table (SST) format snapshot to improve the load balancing speed of a cluster Support using the Heap Profile to uncover memory leaks Support Streaming SIMD Extensions (SSE) and speed up the CRC32 calculation Accelerate transferring leader for faster load balancing Use Batch Apply to reduce CPU usage and improve the write performance Support parallel Prewrite to improve the transaction write speed Optimize the scheduling of the coprocessor thread pool to reduce the impact of big queries on point get The new Loader supports data importing at the table level, as well as splitting a big table into smaller logical blocks to import concurrently to improve the data importing speed. "}, {"url": "https://pingcap.com/docs/v2.0/releases/rc3/", "title": "TiDB RC3 Release Notes", "content": " TiDB RC3 Release Notes On June 20, 2017, TiDB RC4 is released!This release is focused on MySQL compatibility, SQL optimization, stability, and performance.Highlight: The privilege management is refined to enable users to manage the data access privileges using the same way as in MySQL. DDL is accelerated. The load balancing policy and process are optimized for performance. TiDB-Ansible is open sourced. By using TiDB-Ansilbe, you can deploy, upgrade, start and shutdown a TiDB cluster with one click. Detailed updates: TiDB: The following features are added or improved in the SQL query optimizer: Support incremental statistics Support the Merge Sort Join operator Support the Index Lookup Join operator Support the Optimizer Hint Syntax Optimize the memory consumption of the Scan, Join, Aggregation operators Optimize the Cost Based Optimizer (CBO) framework Refactor Expression Support more complete privilege management DDL acceleration Support using HTTP API to get the data distribution information of tables Support using system variables to control the query concurrency Add more MySQL built-in functions Support using system variables to automatically split a big transaction into smaller ones to commit Placement Driver (PD): Support gRPC Provide the Disaster Recovery Toolkit Use Garbage Collection to clear stale data automatically Support more efficient data balance Support hot Region scheduling to enable load balancing and speed up the data importing Performance Accelerate getting Client TSO Improve the efficiency of Region Heartbeat processing Improve the pd-ctl function Update the Replica configuration dynamically Get the Timestamp Oracle (TSO) Use ID to get the Region information TiKV: Support gRPC Support the Sorted String Table (SST) format snapshot to improve the load balancing speed of a cluster Support using the Heap Profile to uncover memory leaks Support Streaming SIMD Extensions (SSE) and speed up the CRC32 calculation Accelerate transferring leader for faster load balancing Use Batch Apply to reduce CPU usage and improve the write performance Support parallel Prewrite to improve the transaction write speed Optimize the scheduling of the coprocessor thread pool to reduce the impact of big queries on point get The new Loader supports data importing at the table level, as well as splitting a big table into smaller logical blocks to import concurrently to improve the data importing speed. "}, {"url": "https://pingcap.com/docs-cn/releases/rc4/", "title": "TiDB RC4 Release Notes", "content": " TiDB RC4 Release Notes 2017 年 8 月 4 日,TiDB 正式发布 RC4 版。该版本对 MySQL 兼容性、SQL 优化器、系统稳定性、性能做了大量的工作。性能方面重点优化了写入速度,计算任务调度支持优先级,避免分析型大事务影响在线事务。SQL 优化器全新改版,查询代价估算更加准确,且能够自动选择 Join 物理算子。功能方面进一步 MySQL 兼容性。 同时为了更好的支持 OLAP 业务,开源了 TiSpark 项目,可以通过 Spark 读取和分析 TiKV 中的数据。TiDB: SQL 查询优化器重构 更好的支持 TopN 查询 支持 Join 算子根据代价自动选择 更完善的 Projection Elimination Schema 版本检查区分 Table,避免 DDL 干扰其他正在执行的事务 支持 BatchIndexJoin 完善 Explain 语句 提升 Index Scan 性能 大量 MySQL 兼容性相关功能 支持 Json 类型及其操作 支持查询优先级、隔离级别的设置 PD: 支持通过 PD 设置 TiKV location labels 调度优化 支持 PD 主动向 TiKV 下发调度命令 加快 region heartbeat 响应速度 优化 balance 算法 优化数据加载,加快 failover 速度 TiKV: 支持查询优先级设置 支持 RC 隔离级别 完善 Jepsen,提升稳定性 支持 Document Store Coprocessor 支持更多下推函数 提升性能,提升稳定性 TiSpark Beta Release: 支持谓词下推 支持聚合下推 支持范围裁剪 通过 TPC-H 测试 (除去一个需要 View 的 Query) "}, {"url": "https://pingcap.com/docs-cn/v1.0/releases/rc4/", "title": "TiDB RC4 Release Notes", "content": " TiDB RC4 Release Notes 8 月 4 日,TiDB 正式发布 RC4 版。该版本对 MySQL 兼容性、SQL 优化器、系统稳定性、性能做了大量的工作。性能方面重点优化了写入速度,计算任务调度支持优先级,避免分析型大事务影响在线事务。SQL 优化器全新改版,查询代价估算更加准确,且能够自动选择 Join 物理算子。功能方面进一步 MySQL 兼容性。 同时为了更好的支持 OLAP 业务,开源了 TiSpark 项目,可以通过 Spark 读取和分析 TiKV 中的数据。TiDB: SQL 查询优化器重构 更好的支持 TopN 查询 支持 Join 算子根据代价自动选择 更完善的 Projection Elimination Schema 版本检查区分 Table,避免 DDL 干扰其他正在执行的事务 支持 BatchIndexJoin 完善 Explain 语句 提升 Index Scan 性能 大量 MySQL 兼容性相关功能 支持 Json 类型及其操作 支持查询优先级、隔离级别的设置 PD: 支持通过 PD 设置 TiKV location labels 调度优化 支持 PD 主动向 TiKV 下发调度命令 加快 region heartbeat 响应速度 优化 balance 算法 优化数据加载,加快 failover 速度 TiKV: 支持查询优先级设置 支持 RC 隔离级别 完善 Jepsen,提升稳定性 支持 Document Store Coprocessor 支持更多下推函数 提升性能,提升稳定性 TiSpark Beta Release: 支持谓词下推 支持聚合下推 支持范围裁剪 通过 TPC-H 测试 (除去一个需要 View 的 Query) "}, {"url": "https://pingcap.com/docs-cn/v2.0/releases/rc4/", "title": "TiDB RC4 Release Notes", "content": " TiDB RC4 Release Notes 8 月 4 日,TiDB 正式发布 RC4 版。该版本对 MySQL 兼容性、SQL 优化器、系统稳定性、性能做了大量的工作。性能方面重点优化了写入速度,计算任务调度支持优先级,避免分析型大事务影响在线事务。SQL 优化器全新改版,查询代价估算更加准确,且能够自动选择 Join 物理算子。功能方面进一步 MySQL 兼容性。 同时为了更好的支持 OLAP 业务,开源了 TiSpark 项目,可以通过 Spark 读取和分析 TiKV 中的数据。TiDB: SQL 查询优化器重构 更好的支持 TopN 查询 支持 Join 算子根据代价自动选择 更完善的 Projection Elimination Schema 版本检查区分 Table,避免 DDL 干扰其他正在执行的事务 支持 BatchIndexJoin 完善 Explain 语句 提升 Index Scan 性能 大量 MySQL 兼容性相关功能 支持 Json 类型及其操作 支持查询优先级、隔离级别的设置 PD: 支持通过 PD 设置 TiKV location labels 调度优化 支持 PD 主动向 TiKV 下发调度命令 加快 region heartbeat 响应速度 优化 balance 算法 优化数据加载,加快 failover 速度 TiKV: 支持查询优先级设置 支持 RC 隔离级别 完善 Jepsen,提升稳定性 支持 Document Store Coprocessor 支持更多下推函数 提升性能,提升稳定性 TiSpark Beta Release: 支持谓词下推 支持聚合下推 支持范围裁剪 通过 TPC-H 测试 (除去一个需要 View 的 Query) "}, {"url": "https://pingcap.com/docs/releases/rc4/", "title": "TiDB RC4 Release Notes", "content": " TiDB RC4 Release Notes On August 4, 2017, TiDB RC4 is released! This release is focused on MySQL compatibility, SQL optimization, stability, and performance.Highlight: For performance, the write performance is improved significantly, and the computing task scheduling supports prioritizing to avoid the impact of OLAP on OLTP. The optimizer is revised for a more accurate query cost estimating and for an automatic choice of the Join physical operator based on the cost. Many enhancements have been introduced to be more compatible with MySQL. TiSpark is now released to better support the OLAP business scenarios. You can now use Spark to access the data in TiKV. Detailed updates: TiDB: The SQL query optimizer refactoring: Better support for TopN queries Support the automatic choice of the of the Join physical operator based on the cost Improved Projection Elimination The version check of schema is based on Table to avoid the impact of DDL on the ongoing transactions Support BatchIndexJoin Improve the Explain statement Improve the Index Scan performance Many enhancements have been introduced to be more compatible with MySQL Support the JSON type and operations Support the configuration of query prioritizing and isolation level Placement Driver (PD): Support using PD to set the TiKV location labels Optimize the scheduler PD is now supported to initialize the scheduling commands to TiKV. Accelerate the response speed of the region heartbeat. Optimize the balance algorithm Optimize data loading to speed up failover TiKV: Support the configuration of query prioritizing Support the RC isolation level Improve Jepsen test results and the stability Support Document Store Coprocessor now supports more pushdown functions Improve the performance and stability TiSpark Beta Release: Implement the prediction pushdown Implement the aggregation pushdown Implement range pruning Capable of running full set of TPC-H except one query that needs view support "}, {"url": "https://pingcap.com/docs/v1.0/releases/rc4/", "title": "TiDB RC4 Release Notes", "content": " TiDB RC4 Release Notes On August 4, 2017, TiDB RC4 is released! This release is focused on MySQL compatibility, SQL optimization, stability, and performance.Highlight: For performance, the write performance is improved significantly, and the computing task scheduling supports prioritizing to avoid the impact of OLAP on OLTP. The optimizer is revised for a more accurate query cost estimating and for an automatic choice of the Join physical operator based on the cost. Many enhancements have been introduced to be more compatible with MySQL. TiSpark is now released to better support the OLAP business scenarios. You can now use Spark to access the data in TiKV. Detailed updates: TiDB: The SQL query optimizer refactoring: Better support for TopN queries Support the automatic choice of the of the Join physical operator based on the cost Improved Projection Elimination The version check of schema is based on Table to avoid the impact of DDL on the ongoing transactions Support BatchIndexJoin Improve the Explain statement Improve the Index Scan performance Many enhancements have been introduced to be more compatible with MySQL Support the JSON type and operations Support the configuration of query prioritizing and isolation level Placement Driver (PD): Support using PD to set the TiKV location labels Optimize the scheduler PD is now supported to initialize the scheduling commands to TiKV. Accelerate the response speed of the region heartbeat. Optimize the balance algorithm Optimize data loading to speed up failover TiKV: Support the configuration of query prioritizing Support the RC isolation level Improve Jepsen test results and the stability Support Document Store Coprocessor now supports more pushdown functions Improve the performance and stability TiSpark Beta Release: Implement the prediction pushdown Implement the aggregation pushdown Implement range pruning Capable of running full set of TPC-H except one query that needs view support "}, {"url": "https://pingcap.com/docs/v2.0/releases/rc4/", "title": "TiDB RC4 Release Notes", "content": " TiDB RC4 Release Notes On August 4, 2017, TiDB RC4 is released! This release is focused on MySQL compatibility, SQL optimization, stability, and performance.Highlight: For performance, the write performance is improved significantly, and the computing task scheduling supports prioritizing to avoid the impact of OLAP on OLTP. The optimizer is revised for a more accurate query cost estimating and for an automatic choice of the Join physical operator based on the cost. Many enhancements have been introduced to be more compatible with MySQL. TiSpark is now released to better support the OLAP business scenarios. You can now use Spark to access the data in TiKV. Detailed updates: TiDB: The SQL query optimizer refactoring: Better support for TopN queries Support the automatic choice of the of the Join physical operator based on the cost Improved Projection Elimination The version check of schema is based on Table to avoid the impact of DDL on the ongoing transactions Support BatchIndexJoin Improve the Explain statement Improve the Index Scan performance Many enhancements have been introduced to be more compatible with MySQL Support the JSON type and operations Support the configuration of query prioritizing and isolation level Placement Driver (PD): Support using PD to set the TiKV location labels Optimize the scheduler PD is now supported to initialize the scheduling commands to TiKV. Accelerate the response speed of the region heartbeat. Optimize the balance algorithm Optimize data loading to speed up failover TiKV: Support the configuration of query prioritizing Support the RC isolation level Improve Jepsen test results and the stability Support Document Store Coprocessor now supports more pushdown functions Improve the performance and stability TiSpark Beta Release: Implement the prediction pushdown Implement the aggregation pushdown Implement range pruning Capable of running full set of TPC-H except one query that needs view support "}, {"url": "https://pingcap.com/docs/ROADMAP/", "title": "TiDB Roadmap", "content": " TiDB Roadmap This document defines the roadmap for TiDB development.TiDB: Optimizer Refactor Ranger Optimize the cost model Cascades model planner Join Reorder Statistics Update statistics dynamically according to the query feedback Analyze table automatically Improve the accuracy of Row Count estimation Execution Engine Push down the Projection operator to the Coprocessor Improve the performance of the HashJoin operator Parallel Operators Projection Aggregation Sort Compact Row Format to reduce memory usage File Sort View Window Function Common Table Expression Table Partition Range Partition Hash Partition Cluster Index New storage row format Query Tracing Improve DDL Speed up Add Index operation Parallel DDL Support locking table Support modifying the column type Supoort modifying the primary key Support multiple DDL operations in a single statement Support utf8_general_ci collation TiKV: Raft Region Merge - Merge small Regions together to reduce overhead Local Read Thread - Process read requests in a local read thread Split Region in Batch - Speed up Region split for large Regions Raft Learner - Support Raft learner to smooth the configuration change process Raft Pre-vote - Support Raft pre-vote to avoid unnecessary leader election on network isolation Joint Consensus - Change multi members safely. Multi-thread Raftstore - Process Region Raft logic in multiple threads Multi-thread apply pool - Apply Region Raft committed entries in multiple threads Engine Titan - Separate large key-values from LSM-Tree Pluggable Engine Interface - Clean up the engine wrapper code and provide more extensibility Storage Flow Control - Do flow control in scheduler to avoid write stall in advance Transaction Optimize transaction conflicts Distributed GC - Distribute MVCC garbage collection control to TiKV Coprocessor Streaming - Cut large data set into small chunks to optimize memory consumption Chunk Execution - Process data in chunk to improve performance Request Tracing - Provide per-request execution details Tools TiKV Importer - Speed up data importing by SST file ingestion Client TiKV client (Rust crate) Batch gRPC Message - Reduce message overhead PD: Improve namespace Different replication policies for different namespaces and tables Decentralize scheduling table Regions Scheduler supports prioritization to be more controllable Use machine learning to optimize scheduling Optimize Region metadata - Save Region metadata in detached storage engine TiSpark: Limit/Order push-down Access through the DAG interface and deprecate the Select interface Index Join and parallel merge join Data Federation Tools: Tool for automating TiDB deployment High-Performance data import tool (lightning) Backup and restore tool (incremental backup supported by drainer, incremental restore supported by reparo) New TiDB-binlog with improved architecture Data online migration tool (premium edition of Syncer) Diagnostic tools "}, {"url": "https://pingcap.com/docs/v1.0/ROADMAP/", "title": "TiDB Roadmap", "content": " TiDB Roadmap This document defines the roadmap for TiDB development.TiDB: Optimizer Refactor Ranger Optimize the statistics info Optimize the cost model Executor Parallel Operators Compact Row Format to reduce memory usage File Sort Support View Support Window Function Common Table Expression Table Partition Hash time index to resolve the issue with hot regions Reverse Index Cluster Index Improve DDL Support utf8_general_ci collation TiKV: Raft Region merge Local read thread Multi-thread raftstore None voter Pre-vote RocksDB DeleteRange Transaction Optimize transaction conflicts Coprocessor Streaming Tool Import distributed data Export distributed data Disaster Recovery Flow control and degradation PD: [ ] Improve namespace [ ] Different replication policies for different namespaces and tables [ ] Decentralize scheduling table regions [ ] Scheduler supports prioritization to be more controllable [ ] Use machine learning to optimize scheduling TiSpark: Limit / Order push-down Access through the DAG interface and deprecate the Select interface Index Join and parallel merge join Data Federation SRE & tools: Kubernetes based intergration for the on-premise version Dashboard UI for the on-premise version The cluster backup and recovery tool The data migration tool (Wormhole V2) Security and system diagnosis "}, {"url": "https://pingcap.com/docs/v2.0/ROADMAP/", "title": "TiDB Roadmap", "content": " TiDB Roadmap This document defines the roadmap for TiDB development.TiDB: Optimizer Refactor Ranger Optimize the cost model Join Reorder Statistics Update statistics dynamically according to the query feedback Analyze table automatically Improve the accuracy of Row Count estimation Executor Push down the Projection operator to the Coprocessor Improve the performance of the HashJoin operator Parallel Operators Projection Aggregation Sort Compact Row Format to reduce memory usage File Sort View Window Function Common Table Expression Table Partition Cluster Index Improve DDL Speed up Add Index operation Parallel DDL Support utf8_general_ci collation TiKV: Raft Region merge Local read thread Multi-thread raftstore None voter Pre-vote Multi-thread apply pool Split region in batch Raft Engine RocksDB DeleteRange BlobDB Transaction Optimize transaction conflicts Distributed GC Coprocessor Streaming Tool Import distributed data Export distributed data Disaster Recovery Flow control and degradation PD: Improve namespace Different replication policies for different namespaces and tables Decentralize scheduling table Regions Scheduler supports prioritization to be more controllable Use machine learning to optimize scheduling Cluster Simulator TiSpark: Limit/Order push-down Access through the DAG interface and deprecate the Select interface Index Join and parallel merge join Data Federation SRE & tools: Kubernetes based integration for the on-premise version Dashboard UI for the on-premise version The cluster backup and recovery tool The data migration tool (Wormhole V2) Security and system diagnosis "}, {"url": "https://pingcap.com/tidb-planet/robot/", "title": "TiDB Robot", "content": ""}, {"url": "https://pingcap.com/docs/sql/tidb-specific/", "title": "TiDB Specific System Variables", "content": " TiDB Specific System Variables TiDB contains a number of system variables which are specific to its usage, and do not apply to MySQL. These variables start with a tidb_ prefix, and can be tuned to optimize system performance.System variables Variables can be set with the SET statement, for example:set @@tidb_distsql_scan_concurrency = 10 If you need to set the global variable, run:set @@global.tidb_distsql_scan_concurrency = 10 tidb_snapshot Scope: SESSION Default value: “” This variable is used to set the time point at which the data is read by the session. For example, when you set the variable to “2017-11-11 20:20:20” or a TSO number like “400036290571534337”, the current session reads the data of this moment. tidb_import_data Scope: SESSION Default value: 0 This variable indicates whether to import data from the dump file currently. To speed up importing, the unique index constraint is not checked when the variable is set to 1. This variable is only used by Lightning. Do not modify it. tidb_opt_agg_push_down Scope: SESSION Default value: 0 This variable is used to set whether the optimizer executes the optimization operation of pushing down the aggregate function to the position before Join. When the aggregate operation is slow in query, you can set the variable value to 1. tidb_opt_insubquery_unfold Scope: SESSION Default value: 0 This variable is used to set whether the optimizer executes the optimization operation of unfolding the “in-” subquery. tidb_build_stats_concurrency Scope: SESSION Default value: 4 This variable is used to set the concurrency of executing the ANALYZE statement. When the variable is set to a larger value, the execution performance of other queries is affected. tidb_checksum_table_concurrency Scope: SESSION Default value: 4 This variable is used to set the scan index concurrency of executing the ADMIN CHECKSUM TABLE statement. When the variable is set to a larger value, the execution performance of other queries is affected. tidb_current_ts Scope: SESSION Default value: 0 This variable is read-only. It is used to obtain the timestamp of the current transaction. tidb_config Scope: SESSION Default value: “” This variable is read-only. It is used to obtain the configuration information of the current TiDB server. tidb_distsql_scan_concurrency Scope: SESSION | GLOBAL Default value: 15 This variable is used to set the concurrency of the scan operation. Use a bigger value in OLAP scenarios, and a smaller value in OLTP scenarios. For OLAP scenarios, the maximum value cannot exceed the number of CPU cores of all the TiKV nodes. tidb_index_lookup_size Scope: SESSION | GLOBAL Default value: 20000 This variable is used to set the batch size of the index lookup operation. Use a bigger value in OLAP scenarios, and a smaller value in OLTP scenarios. tidb_index_lookup_concurrency Scope: SESSION | GLOBAL Default value: 4 This variable is used to set the concurrency of the index lookup operation. Use a bigger value in OLAP scenarios, and a smaller value in OLTP scenarios. tidb_index_lookup_join_concurrency Scope: SESSION | GLOBAL Default value: 4 This variable is used to set the concurrency of the index lookup join algorithm. tidb_hash_join_concurrency Scope: SESSION | GLOBAL Default value: 5 This variable is used to set the concurrency of the hash join algorithm. tidb_index_serial_scan_concurrency Scope: SESSION | GLOBAL Default value: 1 This variable is used to set the concurrency of the serial scan operation. Use a bigger value in OLAP scenarios, and a smaller value in OLTP scenarios. tidb_projection_concurrency Scope: SESSION | GLOBAL Default value: 4 This variable is used to set the concurrency of the Projection operator. tidb_hashagg_partial_concurrency Scope: SESSION | GLOBAL Default value: 4 This variable is used to set the concurrency of executing the concurrent hash aggregation algorithm in the partial phase. When the parameter of the aggregate function is not distinct, HashAgg is run concurrently and respectively in two phases - the partial phase and the final phase. tidb_hashagg_final_concurrency Scope: SESSION | GLOBAL Default value: 4 This variable is used to set the concurrency of executing the concurrent hash aggregation algorithm in the final phase. When the parameter of the aggregate function is not distinct, HashAgg is run concurrently and respectively in two phases - the partial phase and the final phase. tidb_index_join_batch_size Scope: SESSION | GLOBAL Default value: 25000 This variable is used to set the batch size of the index lookup join operation. Use a bigger value in OLAP scenarios, and a smaller value in OLTP scenarios. tidb_skip_utf8_check Scope: SESSION | GLOBAL Default value: 0 This variable is used to set whether to skip UTF-8 validation. Validating UTF-8 characters affects the performance. When you are sure that the input characters are valid UTF-8 characters, you can set the variable value to 1. tidb_batch_insert Scope: SESSION Default value: 0 This variable is used to set whether to divide the inserted data automatically. It is valid only when autocommit is enabled. When inserting a large amount of data, you can set the variable value to true. Then the inserted data is automatically divided into multiple batches and each batch is inserted by a single transaction. tidb_batch_delete Scope: SESSION Default value: 0 This variable is used to set whether to divide the data for deletion automatically. It is valid only when autocommit is enabled. When deleting a large amount of data, you can set the variable value to true. Then the data for deletion is automatically divided into multiple batches and each batch is deleted by a single transaction. tidb_dml_batch_size Scope: SESSION Default value: 20000 This variable is used to set the automatically divided batch size of the data for insertion/deletion. It is only valid when tidb_batch_insert or tidb_batch_delete is enabled. When the data size of a single row is very large, the overall data size of 20 thousand rows exceeds the size limit for a single transaction. In this case, set the variable to a smaller value. tidb_max_chunk_size Scope: SESSION | GLOBAL Default value: 1024 This variable is used to set the maximum number of rows in a chunk during the execution process. tidb_mem_quota_query Scope: SESSION Default value: 32 GB This variable is used to set the threshold value of memory quota for a query. If the memory quota of a query during execution exceeds the threshold value, TiDB performs the operation designated by the OOMAction option in the configuration file. tidb_mem_quota_hashjoin Scope: SESSION Default value: 32 GB This variable is used to set the threshold value of memory quota for the HashJoin operator. If the memory quota of the HashJoin operator during execution exceeds the threshold value, TiDB performs the operation designated by the OOMAction option in the configuration file. tidb_mem_quota_mergejoin Scope: SESSION Default value: 32 GB This variable is used to set the threshold value of memory quota for the MergeJoin operator. If the memory quota of the MergeJoin operator during execution exceeds the threshold value, TiDB performs the operation designated by the OOMAction option in the configuration file. tidb_mem_quota_sort Scope: SESSION Default value: 32 GB This variable is used to set the threshold value of memory quota for the Sort operator. If the memory quota of the Sort operator during execution exceeds the threshold value, TiDB performs the operation designated by the OOMAction option in the configuration file. tidb_mem_quota_topn Scope: SESSION Default value: 32 GB This variable is used to set the threshold value of memory quota for the TopN operator. If the memory quota of the TopN operator during execution exceeds the threshold value, TiDB performs the operation designated by the OOMAction option in the configuration …"}, {"url": "https://pingcap.com/docs/benchmark/sysbench-v2/", "title": "TiDB Sysbench Performance Test Report -- v2.0.0 vs. v1.0.0", "content": " TiDB Sysbench Performance Test Report – v2.0.0 vs. v1.0.0 Test purpose This test aims to compare the performances of TiDB 1.0 and TiDB 2.0.Test version, time, and place TiDB version: v1.0.8 vs. v2.0.0-rc6Time: April 2018Place: Beijing, ChinaTest environment IDC machine| Type | Name || ——– | ——— | | OS | linux (CentOS 7.3.1611) || CPU | 40 vCPUs, Intel® Xeon® CPU E5-2630 v4 @ 2.20GHz | | RAM | 128GB | | DISK | Optane 500GB SSD * 1 |Sysbench test script: https://github.com/pingcap/tidb-bench/tree/master/sysbenchTest plan TiDB version information v1.0.8 Component GitHash TiDB 571f0bbd28a0b8155a5ee831992c986b90d21ab7 TiKV 4ef5889947019e3cb55cc744f487aa63b42540e7 PD 776bcd940b71d295a2c7ed762582bc3aff7d3c0e v2.0.0-rc6 Component GitHash TiDB 82d35f1b7f9047c478f4e1e82aa0002abc8107e7 TiKV 7ed4f6a91f92cad5cd5323aaebe7d9f04b77cc79 PD 2c8e7d7e33b38e457169ce5dfb2f461fced82d65 TiKV parameter configuration v1.0.8sync-log = false grpc-concurrency = 8 grpc-raft-conn-num = 24 v2.0.0-rc6sync-log = false grpc-concurrency = 8 grpc-raft-conn-num = 24 use-delete-range: false Cluster topology Machine IP Deployment instance 172.16.21.1 1*tidb 1*pd 1*sysbench 172.16.21.2 1*tidb 1*pd 1*sysbench 172.16.21.3 1*tidb 1*pd 1*sysbench 172.16.11.4 1*tikv 172.16.11.5 1*tikv 172.16.11.6 1*tikv 172.16.11.7 1*tikv 172.16.11.8 1*tikv 172.16.11.9 1*tikv Test result Standard Select test | Version | Table count | Table size | Sysbench threads |QPS | Latency (avg/.95) | | :—: | :—: | :—: | :—: | :—: | :—: | | v2.0.0-rc6 | 32 | 10 million | 128 * 3 | 201936 | 1.9033 ms/5.67667 ms | | v2.0.0-rc6 | 32 | 10 million | 256 * 3 | 208130 | 3.69333 ms/8.90333 ms | | v2.0.0-rc6 | 32 | 10 million | 512 * 3 | 211788 | 7.23333 ms/15.59 ms | | v2.0.0-rc6 | 32 | 10 million | 1024 * 3 | 212868 | 14.5933 ms/43.2133 ms | | v1.0.8 | 32 | 10 million | 128 * 3 | 188686 | 2.03667 ms/5.99 ms | | v1.0.8 | 32 | 10 million | 256 * 3 | 195090 |3.94 ms/9.12 ms | | v1.0.8 | 32 | 10 million | 512 * 3 | 203012 | 7.57333 ms/15.3733 ms | | v1.0.8 | 32 | 10 million | 1024 * 3 | 205932 | 14.9267 ms/40.7633 ms |According to the statistics above, the Select query performance of TiDB 2.0 GA has increased by about 10% at most than that of TiDB 1.0 GA.Standard OLTP test | Version | Table count | Table size | Sysbench threads | TPS | QPS | Latency (avg/.95) | | :—: | :—: | :—: | :—: | :—: | :—: | :—:| | v2.0.0-rc6 | 32 | 10 million | 128 * 3 | 5404.22 | 108084.4 | 87.2033 ms/110 ms | | v2.0.0-rc6 | 32 | 10 million | 256 * 3 | 5578.165 | 111563.3 | 167.673 ms/275.623 ms | | v2.0.0-rc6 | 32 | 10 million | 512 * 3 | 5874.045 | 117480.9 | 315.083 ms/674.017 ms | | v2.0.0-rc6 | 32 | 10 million | 1024 * 3 | 6290.7 | 125814 | 529.183 ms/857.007 ms | | v1.0.8 | 32 | 10 million | 128 * 3 | 5523.91 | 110478 | 69.53 ms/88.6333 ms | | v1.0.8 | 32 | 10 million | 256 * 3 | 5969.43 | 119389 |128.63 ms/162.58 ms | | v1.0.8 | 32 | 10 million | 512 * 3 | 6308.93 | 126179 | 243.543 ms/310.913 ms | | v1.0.8 | 32 | 10 million | 1024 * 3 | 6444.25 | 128885 | 476.787ms/635.143 ms |According to the statistics above, the OLTP performance of TiDB 2.0 GA and TiDB 1.0 GA is almost the same.Standard Insert test | Version | Table count | Table size | Sysbench threads | QPS | Latency (avg/.95) | | :—: | :—: | :—: | :—: | :—: | :—: | | v2.0.0-rc6 | 32 | 10 million | 128 * 3 | 31707.5 | 12.11 ms/21.1167 ms | | v2.0.0-rc6 | 32 | 10 million | 256 * 3 | 38741.2 | 19.8233 ms/39.65 ms | | v2.0.0-rc6 | 32 | 10 million | 512 * 3 | 45136.8 | 34.0267 ms/66.84 ms | | v2.0.0-rc6 | 32 | 10 million | 1024 * 3 | 48667 | 63.1167 ms/121.08 ms | | v1.0.8 | 32 | 10 million | 128 * 3 | 31125.7 | 12.3367 ms/19.89 ms | | v1.0.8 | 32 | 10 million | 256 * 3 | 36800 | 20.8667 ms/35.3767 ms | | v1.0.8 | 32 | 10 million | 512 * 3 | 44123 | 34.8067 ms/63.32 ms | | v1.0.8 | 32 | 10 million | 1024 * 3 | 48496 | 63.3333 ms/118.92 ms |According to the statistics above, the Insert query performance of TiDB 2.0 GA has increased slightly than that of TiDB 1.0 GA."}, {"url": "https://pingcap.com/docs/v2.0/benchmark/sysbench-v2/", "title": "TiDB Sysbench Performance Test Report -- v2.0.0 vs. v1.0.0", "content": " TiDB Sysbench Performance Test Report – v2.0.0 vs. v1.0.0 Test purpose This test aims to compare the performances of TiDB 1.0 and TiDB 2.0.Test version, time, and place TiDB version: v1.0.8 vs. v2.0.0-rc6Time: April 2018Place: Beijing, ChinaTest environment IDC machine| Type | Name || ——– | ——— | | OS | linux (CentOS 7.3.1611) || CPU | 40 vCPUs, Intel® Xeon® CPU E5-2630 v4 @ 2.20GHz | | RAM | 128GB | | DISK | Optane 500GB SSD * 1 |Sysbench test script: https://github.com/pingcap/tidb-bench/tree/master/sysbenchTest plan TiDB version information v1.0.8 Component GitHash TiDB 571f0bbd28a0b8155a5ee831992c986b90d21ab7 TiKV 4ef5889947019e3cb55cc744f487aa63b42540e7 PD 776bcd940b71d295a2c7ed762582bc3aff7d3c0e v2.0.0-rc6 Component GitHash TiDB 82d35f1b7f9047c478f4e1e82aa0002abc8107e7 TiKV 7ed4f6a91f92cad5cd5323aaebe7d9f04b77cc79 PD 2c8e7d7e33b38e457169ce5dfb2f461fced82d65 TiKV parameter configuration v1.0.8sync-log = false grpc-concurrency = 8 grpc-raft-conn-num = 24 v2.0.0-rc6sync-log = false grpc-concurrency = 8 grpc-raft-conn-num = 24 use-delete-range: false Cluster topology Machine IP Deployment instance 172.16.21.1 1*tidb 1*pd 1*sysbench 172.16.21.2 1*tidb 1*pd 1*sysbench 172.16.21.3 1*tidb 1*pd 1*sysbench 172.16.11.4 1*tikv 172.16.11.5 1*tikv 172.16.11.6 1*tikv 172.16.11.7 1*tikv 172.16.11.8 1*tikv 172.16.11.9 1*tikv Test result Standard Select test | Version | Table count | Table size | Sysbench threads |QPS | Latency (avg/.95) | | :—: | :—: | :—: | :—: | :—: | :—: | | v2.0.0-rc6 | 32 | 10 million | 128 * 3 | 201936 | 1.9033 ms/5.67667 ms | | v2.0.0-rc6 | 32 | 10 million | 256 * 3 | 208130 | 3.69333 ms/8.90333 ms | | v2.0.0-rc6 | 32 | 10 million | 512 * 3 | 211788 | 7.23333 ms/15.59 ms | | v2.0.0-rc6 | 32 | 10 million | 1024 * 3 | 212868 | 14.5933 ms/43.2133 ms | | v1.0.8 | 32 | 10 million | 128 * 3 | 188686 | 2.03667 ms/5.99 ms | | v1.0.8 | 32 | 10 million | 256 * 3 | 195090 |3.94 ms/9.12 ms | | v1.0.8 | 32 | 10 million | 512 * 3 | 203012 | 7.57333 ms/15.3733 ms | | v1.0.8 | 32 | 10 million | 1024 * 3 | 205932 | 14.9267 ms/40.7633 ms |According to the statistics above, the Select query performance of TiDB 2.0 GA has increased by about 10% at most than that of TiDB 1.0 GA.Standard OLTP test | Version | Table count | Table size | Sysbench threads | TPS | QPS | Latency (avg/.95) | | :—: | :—: | :—: | :—: | :—: | :—: | :—:| | v2.0.0-rc6 | 32 | 10 million | 128 * 3 | 5404.22 | 108084.4 | 87.2033 ms/110 ms | | v2.0.0-rc6 | 32 | 10 million | 256 * 3 | 5578.165 | 111563.3 | 167.673 ms/275.623 ms | | v2.0.0-rc6 | 32 | 10 million | 512 * 3 | 5874.045 | 117480.9 | 315.083 ms/674.017 ms | | v2.0.0-rc6 | 32 | 10 million | 1024 * 3 | 6290.7 | 125814 | 529.183 ms/857.007 ms | | v1.0.8 | 32 | 10 million | 128 * 3 | 5523.91 | 110478 | 69.53 ms/88.6333 ms | | v1.0.8 | 32 | 10 million | 256 * 3 | 5969.43 | 119389 |128.63 ms/162.58 ms | | v1.0.8 | 32 | 10 million | 512 * 3 | 6308.93 | 126179 | 243.543 ms/310.913 ms | | v1.0.8 | 32 | 10 million | 1024 * 3 | 6444.25 | 128885 | 476.787ms/635.143 ms |According to the statistics above, the OLTP performance of TiDB 2.0 GA and TiDB 1.0 GA is almost the same.Standard Insert test | Version | Table count | Table size | Sysbench threads | QPS | Latency (avg/.95) | | :—: | :—: | :—: | :—: | :—: | :—: | | v2.0.0-rc6 | 32 | 10 million | 128 * 3 | 31707.5 | 12.11 ms/21.1167 ms | | v2.0.0-rc6 | 32 | 10 million | 256 * 3 | 38741.2 | 19.8233 ms/39.65 ms | | v2.0.0-rc6 | 32 | 10 million | 512 * 3 | 45136.8 | 34.0267 ms/66.84 ms | | v2.0.0-rc6 | 32 | 10 million | 1024 * 3 | 48667 | 63.1167 ms/121.08 ms | | v1.0.8 | 32 | 10 million | 128 * 3 | 31125.7 | 12.3367 ms/19.89 ms | | v1.0.8 | 32 | 10 million | 256 * 3 | 36800 | 20.8667 ms/35.3767 ms | | v1.0.8 | 32 | 10 million | 512 * 3 | 44123 | 34.8067 ms/63.32 ms | | v1.0.8 | 32 | 10 million | 1024 * 3 | 48496 | 63.3333 ms/118.92 ms |According to the statistics above, the Insert query performance of TiDB 2.0 GA has increased slightly than that of TiDB 1.0 GA."}, {"url": "https://pingcap.com/docs/benchmark/sysbench-v3/", "title": "TiDB Sysbench Performance Test Report -- v2.1 vs. v2.0", "content": " TiDB Sysbench Performance Test Report – v2.1 vs. v2.0 Test purpose This test aims to compare the performance of TiDB 2.1 and TiDB 2.0 for OLTP where the working set fits in memory.Test version, time, and place TiDB version: v2.1.0-rc.2 vs. v2.0.6Time: September, 2018Place: Beijing, ChinaTest environment IDC machine:| Type | Name || :-: | :-: | | OS | Linux (CentOS 7.3.1611) | | CPU | 40 vCPUs, Intel® Xeon® CPU E5-2630 v4 @ 2.20GHz | | RAM | 128GB | | DISK | Optane 500GB SSD * 1 |Sysbench version: 1.1.0Test plan Use Sysbench to import 16 tables, with 10,000,000 pieces of data in each table. With the HAProxy, requests are sent to the cluster at an incremental concurrent number. A single concurrent test lasts 5 minutes.TiDB version information v2.1.0-rc.2 Component GitHash TiDB 08e56cd3bae166b2af3c2f52354fbc9818717f62 TiKV 57e684016dafb17dc8a6837d30224be66cbc7246 PD 6a7832d2d6e5b2923c79683183e63d030f954563 v2.0.6 Component GitHash TiDB b13bc08462a584a085f377625a7bab0cc0351570 TiKV 57c83dc4ebc93d38d77dc8f7d66db224760766cc PD b64716707b7279a4ae822be767085ff17b5f3fea TiDB parameter configuration The default TiDB configuration is used in both v2.1 and v2.0.TiKV parameter configuration The following TiKV configuration is used in both v2.1 and v2.0:[readpool.storage] normal-concurrency = 8 [server] grpc-concurrency = 8 [raftstore] sync-log = false [rocksdb.defaultcf] block-cache-size = "60GB" [rocksdb.writecf] block-cache-size = "20GB" Cluster topology Machine IP Deployment instance 172.16.30.31 1*Sysbench 1*HAProxy 172.16.30.32 1*TiDB 1*pd 1*TiKV 172.16.30.33 1*TiDB 1*TiKV 172.16.30.34 1*TiDB 1*TiKV Test result Point Select test Version Threads QPS 95% Latency (ms) v2.1 64 111481.09 1.16 v2.1 128 145102.62 2.52 v2.1 256 161311.9 4.57 v2.1 512 184991.19 7.56 v2.1 1024 230282.74 10.84 v2.0 64 75285.87 1.93 v2.0 128 92141.79 3.68 v2.0 256 107464.93 6.67 v2.0 512 121350.61 11.65 v2.0 1024 150036.31 17.32 According to the statistics above, the Point Select query performance of TiDB 2.1 has increased by 50% than that of TiDB 2.0.Update Non-Index test Version Threads QPS 95% Latency (ms) v2.1 64 18946.09 5.77 v2.1 128 22022.82 12.08 v2.1 256 24679.68 25.74 v2.1 512 25107.1 51.94 v2.1 1024 27144.92 106.75 v2.0 64 16316.85 6.91 v2.0 128 20944.6 11.45 v2.0 256 24017.42 23.1 v2.0 512 25994.33 46.63 v2.0 1024 27917.52 92.42 According to the statistics above, the Update Non-Index write performance of TiDB 2.1 and TiDB 2.0 is almost the same.Update Index test Version Threads QPS 95% Latency (ms) v2.1 64 9934.49 12.08 v2.1 128 10505.95 25.28 v2.1 256 11007.7 55.82 v2.1 512 11198.81 106.75 v2.1 1024 11591.89 200.47 v2.0 64 9754.68 11.65 v2.0 128 10603.31 24.38 v2.0 256 11011.71 50.11 v2.0 512 11162.63 104.84 v2.0 1024 12067.63 179.94 According to the statistics above, the Update Index write performance of TiDB 2.1 and TiDB 2.0 is almost the same."}, {"url": "https://pingcap.com/docs-cn/benchmark/sysbench-v2/", "title": "TiDB Sysbench 性能对比测试报告 - v2.0.0 对比 v1.0.0", "content": " TiDB Sysbench 性能对比测试报告 - v2.0.0 对比 v1.0.0 测试目的 对比 TiDB 2.0 版本和 1.0 版本在 OLTP 场景下的性能。测试版本、时间、地点 TiDB 版本:v1.0.8 Vs v2.0.0-rc6时间:2018 年 4 月地点:北京测试环境 IDC 机器| 类别 | 名称 || :——–: | :———: | | OS | Linux (CentOS 7.3.1611) | | CPU | 40 vCPUs, Intel® Xeon® CPU E5-2630 v4 @ 2.20GHz | | RAM | 128GB | | DISK | Optane 500GB SSD * 1 |Sysbench 测试脚本: https://github.com/pingcap/tidb-bench/tree/master/sysbench测试方案 TiDB 版本信息 v1.0.8 组件 GitHash TiDB 571f0bbd28a0b8155a5ee831992c986b90d21ab7 TiKV 4ef5889947019e3cb55cc744f487aa63b42540e7 PD 776bcd940b71d295a2c7ed762582bc3aff7d3c0e v2.0.0-rc6 组件 GitHash TiDB 82d35f1b7f9047c478f4e1e82aa0002abc8107e7 TiKV 7ed4f6a91f92cad5cd5323aaebe7d9f04b77cc79 PD 2c8e7d7e33b38e457169ce5dfb2f461fced82d65 TiKV 参数配置 v1.0.8sync-log = false grpc-concurrency = 8 grpc-raft-conn-num = 24 v2.0.0-rc6sync-log = false grpc-concurrency = 8 grpc-raft-conn-num = 24 use-delete-range: false 集群拓扑 机器 IP 部署实例 172.16.21.1 1*tidb 1*pd 1*sysbench 172.16.21.2 1*tidb 1*pd 1*sysbench 172.16.21.3 1*tidb 1*pd 1*sysbench 172.16.11.4 1*tikv 172.16.11.5 1*tikv 172.16.11.6 1*tikv 172.16.11.7 1*tikv 172.16.11.8 1*tikv 172.16.11.9 1*tikv 测试结果 标准 Select 测试 | 版本 | table count | table size | sysbench threads |qps | latency(avg / .95) | | :—: | :—: | :—: | :—: | :—: | :—: | | v2.0.0-rc6 | 32 | 1000 万 | 128 * 3 | 201936 | 1.9033 ms / 5.67667 ms | | v2.0.0-rc6 | 32 | 1000 万 | 256 * 3 | 208130 | 3.69333 ms / 8.90333 ms | | v2.0.0-rc6 | 32 | 1000 万 | 512 * 3 | 211788 | 7.23333 ms / 15.59 ms | | v2.0.0-rc6 | 32 | 1000 万 | 1024 * 3 | 212868 | 14.5933 ms / 43.2133 ms | | v1.0.8 | 32 | 1000 万 | 128 * 3 | 188686 | 2.03667 ms / 5.99 ms | | v1.0.8 | 32 | 1000 万 | 256 * 3 | 195090 |3.94 ms / 9.12 ms | | v1.0.8 | 32 | 1000 万 | 512 * 3 | 203012 | 7.57333 ms / 15.3733 ms | | v1.0.8 | 32 | 1000 万 | 1024 * 3 | 205932 | 14.9267 ms / 40.7633 ms |GA2.0 比 GA1.0 在 Select 查询性能上,最高提升了 10% 左右。标准 OLTP 测试 | 版本 | table count | table size | sysbench threads | tps | qps | latency(avg / .95) | | :—: | :—: | :—: | :—: | :—: | :—: | :—:| | v2.0.0-rc6 | 32 | 1000 万 | 128 * 3 | 5404.22 | 108084.4 | 87.2033 ms / 110 ms | | v2.0.0-rc6 | 32 | 1000 万 | 256 * 3 | 5578.165 | 111563.3 | 167.673 ms / 275.623 ms | | v2.0.0-rc6 | 32 | 1000 万 | 512 * 3 | 5874.045 | 117480.9 | 315.083 ms / 674.017 ms | | v2.0.0-rc6 | 32 | 1000 万 | 1024 * 3 | 6290.7 | 125814 | 529.183 ms / 857.007 ms | | v1.0.8 | 32 | 1000 万 | 128 * 3 | 5523.91 | 110478 | 69.53 ms / 88.6333 ms | | v1.0.8 | 32 | 1000 万 | 256 * 3 | 5969.43 | 119389 |128.63 ms / 162.58 ms | | v1.0.8 | 32 | 1000 万 | 512 * 3 | 6308.93 | 126179 | 243.543 ms / 310.913 ms | | v1.0.8 | 32 | 1000 万 | 1024 * 3 | 6444.25 | 128885 | 476.787ms / 635.143 ms |GA2.0 比 GA1.0 在 OLTP 性能上,性能基本一致。标准 Insert 测试 | 版本 | table count | table size | sysbench threads |qps | latency(avg / .95) | | :—: | :—: | :—: | :—: | :—: | :—: | | v2.0.0-rc6 | 32 | 1000 万 | 128 * 3 | 31707.5 | 12.11 ms / 21.1167 ms | | v2.0.0-rc6 | 32 | 1000 万 | 256 * 3 | 38741.2 | 19.8233 ms / 39.65 ms | | v2.0.0-rc6 | 32 | 1000 万 | 512 * 3 | 45136.8 | 34.0267 ms / 66.84 ms | | v2.0.0-rc6 | 32 | 1000 万 | 1024 * 3 | 48667 | 63.1167 ms / 121.08 ms | | v1.0.8 | 32 | 1000 万 | 128 * 3 | 31125.7 | 12.3367 ms / 19.89 ms | | v1.0.8 | 32 | 1000 万 | 256 * 3 | 36800 | 20.8667 ms / 35.3767 ms | | v1.0.8 | 32 | 1000 万 | 512 * 3 | 44123 | 34.8067 ms / 63.32 ms | | v1.0.8 | 32 | 1000 万 | 1024 * 3 | 48496 | 63.3333 ms / 118.92 ms |GA2.0 比 GA1.0 在 Insert 性能上略有提升。"}, {"url": "https://pingcap.com/docs-cn/benchmark/sysbench-v3/", "title": "TiDB Sysbench 性能对比测试报告 - v2.1 对比 v2.0", "content": " TiDB Sysbench 性能对比测试报告 - v2.1 对比 v2.0 测试目的 对比 TiDB 2.1 版本和 2.0 版本在 OLTP 场景下的性能。测试版本、时间、地点 TiDB 版本:v2.1.0-rc.2 vs. v2.0.6时间:2018 年 9 月地点:北京测试环境 IDC 机器:| 类别 | 名称 || :-: | :-: | | OS | Linux (CentOS 7.3.1611) | | CPU | 40 vCPUs, Intel® Xeon® CPU E5-2630 v4 @ 2.20GHz | | RAM | 128GB | | DISK | Optane 500GB SSD * 1 |Sysbench 版本:1.1.0测试方案 使用 Sysbench 向集群导入 16 张表,每张数据 1000 万。通过 HAProxy 代理,分别以递增并发数向集群发送请求,单次并发测试时间 5 分钟。TiDB 版本信息 v2.1.0-rc.2 组件 GitHash TiDB 08e56cd3bae166b2af3c2f52354fbc9818717f62 TiKV 57e684016dafb17dc8a6837d30224be66cbc7246 PD 6a7832d2d6e5b2923c79683183e63d030f954563 v2.0.6 组件 GitHash TiDB b13bc08462a584a085f377625a7bab0cc0351570 TiKV 57c83dc4ebc93d38d77dc8f7d66db224760766cc PD b64716707b7279a4ae822be767085ff17b5f3fea TiDB 参数配置 两版本 TiDB 均使用默认配置。TiKV 参数配置 两版本 TiKV 均使用如下配置:[readpool.storage] normal-concurrency = 8 [server] grpc-concurrency = 8 [raftstore] sync-log = false [rocksdb.defaultcf] block-cache-size = "60GB" [rocksdb.writecf] block-cache-size = "20GB" 集群拓扑 机器 IP 部署实例 172.16.30.31 1*Sysbench 1*HAProxy 172.16.30.32 1*TiDB 1*pd 1*TiKV 172.16.30.33 1*TiDB 1*TiKV 172.16.30.34 1*TiDB 1*TiKV 测试结果 Point Select 测试 版本 threads qps 95% latency(ms) v2.1 64 111481.09 1.16 v2.1 128 145102.62 2.52 v2.1 256 161311.9 4.57 v2.1 512 184991.19 7.56 v2.1 1024 230282.74 10.84 v2.0 64 75285.87 1.93 v2.0 128 92141.79 3.68 v2.0 256 107464.93 6.67 v2.0 512 121350.61 11.65 v2.0 1024 150036.31 17.32 v2.1 比 v2.0 在 Point Select 查询性能上,提升了 50%。Update Non-Index 测试 版本 threads qps 95% latency(ms) v2.1 64 18946.09 5.77 v2.1 128 22022.82 12.08 v2.1 256 24679.68 25.74 v2.1 512 25107.1 51.94 v2.1 1024 27144.92 106.75 v2.0 64 16316.85 6.91 v2.0 128 20944.6 11.45 v2.0 256 24017.42 23.1 v2.0 512 25994.33 46.63 v2.0 1024 27917.52 92.42 v2.1 与 v2.0 在 Update Non-Index 写入性能上基本一致。Update Index 测试 版本 threads qps 95% latency(ms) v2.1 64 9934.49 12.08 v2.1 128 10505.95 25.28 v2.1 256 11007.7 55.82 v2.1 512 11198.81 106.75 v2.1 1024 11591.89 200.47 v2.0 64 9754.68 11.65 v2.0 128 10603.31 24.38 v2.0 256 11011.71 50.11 v2.0 512 11162.63 104.84 v2.0 1024 12067.63 179.94 v2.1 与 v2.0 在 Update Index 写入性能上基本一致。"}, {"url": "https://pingcap.com/docs/benchmark/tpch/", "title": "TiDB TPC-H 50G Performance Test Report V2.0", "content": " TiDB TPC-H 50G Performance Test Report Test purpose This test aims to compare the performances of TiDB 1.0 and TiDB 2.0 in the OLAP scenario. Note: Different test environments might lead to different test results. Test environment Machine information System information: Machine IP Operation system Kernel version File system type 172.16.31.2 Ubuntu 17.10 64bit 4.13.0-16-generic ext4 172.16.31.3 Ubuntu 17.10 64bit 4.13.0-16-generic ext4 172.16.31.4 Ubuntu 17.10 64bit 4.13.0-16-generic ext4 172.16.31.6 CentOS 7.4.1708 64bit 3.10.0-693.11.6.el7.x86_64 ext4 172.16.31.8 CentOS 7.4.1708 64bit 3.10.0-693.11.6.el7.x86_64 ext4 172.16.31.10 CentOS 7.4.1708 64bit 3.10.0-693.11.6.el7.x86_64 ext4 Hardware information: Type Name CPU 40 vCPUs, Intel® Xeon® CPU E5-2630 v4 @ 2.20GHz RAM 128GB, 16GB RDIMM * 8, 2400MT/s, dual channel, x8 bitwidth DISK Intel P4500 4T SSD * 2 Network Card 10 Gigabit Ethernet TPC-H tidb-bench/tpchCluster topology Machine IP Deployment Instance 172.16.31.2 TiKV * 2 172.16.31.3 TiKV * 2 172.16.31.6 TiKV * 2 172.16.31.8 TiKV * 2 172.16.31.10 TiKV * 2 172.16.31.10 PD * 1 172.16.31.4 TiDB * 1 Corresponding TiDB version information TiDB 1.0: Component Version Commit Hash TiDB v1.0.9 4c7ee3580cd0a69319b2c0c08abdc59900df7344 TiKV v1.0.8 2bb923a4cd23dbf68f0d16169fd526dc5c1a9f4a PD v1.0.8 137fa734472a76c509fbfd9cb9bc6d0dc804a3b7 TiDB 2.0: Component Version Commit Hash TiDB v2.0.0-rc.6 82d35f1b7f9047c478f4e1e82aa0002abc8107e7 TiKV v2.0.0-rc.6 8bd5c54966c6ef42578a27519bce4915c5b0c81f PD v2.0.0-rc.6 9b824d288126173a61ce7d51a71fc4cb12360201 Test result Query ID TiDB 2.0 TiDB 1.0 1 33.915s 215.305s 2 25.575s Nan 3 59.631s 196.003s 4 30.234s 249.919s 5 31.666s OOM 6 13.111s 118.709s 7 31.710s OOM 8 31.734s 800.546s 9 34.211s 630.639s 10 30.774s 133.547s 11 27.692s 78.026s 12 27.962s 124.641s 13 27.676s 174.695s 14 19.676s 110.602s 15 NaN Nan 16 24.890s 40.529s 17 245.796s NaN 18 91.256s OOM 19 37.615s NaN 20 44.167s 212.201s 21 31.466s OOM 22 31.539s 125.471s It should be noted that: In the diagram above, the orange bars represent the query results of Release 1.0 and the blue bars represent the query results of Release 2.0. The y-axis represents the processing time of queries in seconds, the shorter the faster. Query 15 is tagged with “NaN” because VIEW is currently not supported in either TiDB 1.0 or 2.0. We have plans to provide VIEW support in a future release. Queries 2, 17, and 19 in the TiDB 1.0 column are tagged with “NaN” because TiDB 1.0 did not return results for these queries. Queries 5, 7, 18, and 21 in the TiDB 1.0 column are tagged with “OOM” because the memory consumption was too high. "}, {"url": "https://pingcap.com/docs/v2.0/benchmark/tpch/", "title": "TiDB TPC-H 50G Performance Test Report V2.0", "content": " TiDB TPC-H 50G Performance Test Report Test purpose This test aims to compare the performances of TiDB 1.0 and TiDB 2.0 in the OLAP scenario. Note: Different test environments might lead to different test results. Test environment Machine information System information: Machine IP Operation system Kernel version File system type 172.16.31.2 Ubuntu 17.10 64bit 4.13.0-16-generic ext4 172.16.31.3 Ubuntu 17.10 64bit 4.13.0-16-generic ext4 172.16.31.4 Ubuntu 17.10 64bit 4.13.0-16-generic ext4 172.16.31.6 CentOS 7.4.1708 64bit 3.10.0-693.11.6.el7.x86_64 ext4 172.16.31.8 CentOS 7.4.1708 64bit 3.10.0-693.11.6.el7.x86_64 ext4 172.16.31.10 CentOS 7.4.1708 64bit 3.10.0-693.11.6.el7.x86_64 ext4 Hardware information: Type Name CPU 40 vCPUs, Intel® Xeon® CPU E5-2630 v4 @ 2.20GHz RAM 128GB, 16GB RDIMM * 8, 2400MT/s, dual channel, x8 bitwidth DISK Intel P4500 4T SSD * 2 Network Card 10 Gigabit Ethernet TPC-H tidb-bench/tpchCluster topology Machine IP Deployment Instance 172.16.31.2 TiKV * 2 172.16.31.3 TiKV * 2 172.16.31.6 TiKV * 2 172.16.31.8 TiKV * 2 172.16.31.10 TiKV * 2 172.16.31.10 PD * 1 172.16.31.4 TiDB * 1 Corresponding TiDB version information TiDB 1.0: Component Version Commit Hash TiDB v1.0.9 4c7ee3580cd0a69319b2c0c08abdc59900df7344 TiKV v1.0.8 2bb923a4cd23dbf68f0d16169fd526dc5c1a9f4a PD v1.0.8 137fa734472a76c509fbfd9cb9bc6d0dc804a3b7 TiDB 2.0: Component Version Commit Hash TiDB v2.0.0-rc.6 82d35f1b7f9047c478f4e1e82aa0002abc8107e7 TiKV v2.0.0-rc.6 8bd5c54966c6ef42578a27519bce4915c5b0c81f PD v2.0.0-rc.6 9b824d288126173a61ce7d51a71fc4cb12360201 Test result Query ID TiDB 2.0 TiDB 1.0 1 33.915s 215.305s 2 25.575s Nan 3 59.631s 196.003s 4 30.234s 249.919s 5 31.666s OOM 6 13.111s 118.709s 7 31.710s OOM 8 31.734s 800.546s 9 34.211s 630.639s 10 30.774s 133.547s 11 27.692s 78.026s 12 27.962s 124.641s 13 27.676s 174.695s 14 19.676s 110.602s 15 NaN Nan 16 24.890s 40.529s 17 245.796s NaN 18 91.256s OOM 19 37.615s NaN 20 44.167s 212.201s 21 31.466s OOM 22 31.539s 125.471s It should be noted that: In the diagram above, the orange bars represent the query results of Release 1.0 and the blue bars represent the query results of Release 2.0. The y-axis represents the processing time of queries in seconds, the shorter the faster. Query 15 is tagged with “NaN” because VIEW is currently not supported in either TiDB 1.0 or 2.0. We have plans to provide VIEW support in a future release. Queries 2, 17, and 19 in the TiDB 1.0 column are tagged with “NaN” because TiDB 1.0 did not return results for these queries. Queries 5, 7, 18, and 21 in the TiDB 1.0 column are tagged with “OOM” because the memory consumption was too high. "}, {"url": "https://pingcap.com/docs/benchmark/tpch-v2/", "title": "TiDB TPC-H 50G Performance Test Report V2.1", "content": " TiDB TPC-H 50G Performance Test Report V2.1 Test purpose This test aims to compare the performances of TiDB 2.0 and TiDB 2.1 in the OLAP scenario. Note: Different test environments might lead to different test results. Test environment Machine information System information: Machine IP Operation system Kernel version File system type 10.0.1.4 CentOS 7.5.1804 64bit 3.10.0-862.3.3.el7.x86_64 ext4 10.0.1.5 CentOS 7.5.1804 64bit 3.10.0-862.3.3.el7.x86_64 ext4 10.0.1.6 CentOS 7.5.1804 64bit 3.10.0-862.3.3.el7.x86_64 ext4 10.0.1.7 CentOS 7.5.1804 64bit 3.10.0-862.3.3.el7.x86_64 ext4 10.0.1.8 CentOS 7.5.1804 64bit 3.10.0-862.3.3.el7.x86_64 ext4 10.0.1.9 CentOS 7.5.1804 64bit 3.10.0-862.3.3.el7.x86_64 ext4 Hardware information: Type 10.0.1.4 10.0.1.5, 10.0.1.6, 10.0.1.7, 10.0.1.8, 10.0.1.9 CPU 16 vCPUs, Intel® Xeon® CPU E5-2660 0 @ 2.20GHz 8 vCPUs, Intel® Xeon® CPU E5-2660 0 @ 2.20GHz Memory 110G 55G Disk 221G SSD 111G SSD Network card 10 Gigabit Ethernet, 10000Mb/s 10 Gigabit Ethernet, 10000Mb/s TPC-H tidb-bench/tpchCluster topology Machine IP Deployment Instance 10.0.1.5 TiKV * 1 10.0.1.6 TiKV * 1 10.0.1.7 TiKV * 1 10.0.1.8 TiKV * 1 10.0.1.9 TiKV * 1 10.0.1.4 PD * 1 10.0.1.4 TiDB * 1 TiDB version information TiDB 2.0: Component Version Commit Hash TiDB v2.0.7 29ec059cb3b7d14b6f52c2f219f94a89570162bc TiKV v2.0.7 d0b8cd7c7f62f06e7ef456837bd32a47da1ca4cd PD v2.0.5 b64716707b7279a4ae822be767085ff17b5f3fea TiDB 2.1: Component Version Commit Hash TiDB v2.1.0-rc.2 16864f95b47f859ed6104555ccff0387abdc2429 TiKV v2.1.0-rc.2 8458ce53ebbd434c48baac6373fe0f0a43a54005 PD v2.1.0-rc.2 55db505e8f35e8ab4e00efd202beb27a8ecc40fb Test result Query ID TiDB 2.0 TiDB 2.1 1 121.550595999s 91.4755480289s 2 53.0638680458s 23.1186130047s 3 75.7236940861s 61.790802002s 4 30.2647120953s 26.3483440876s 6 51.4850790501s 34.6432199478s 7 216.787364006s 94.9856910706s 8 188.717588902s 181.852752209s 9 546.438174009s 414.462754965s 10 109.978317022s 37.0369961262s 11 42.9398438931s 37.6951580048s 12 60.455039978s 40.2236878872s 13 230.278712988s 70.2887151241s 14 61.2673521042s 35.8372960091s 16 30.2539310455s 18.5897550583s 17 3200.70173788s 263.095014811s 18 1035.59847498s 296.360667944s 19 54.3732938766s 40.4523630142s 20 105.094577074s 53.2429068089s 21 389.883709908s 361.034544945s 22 64.0494630337s 65.7153418064s It should be noted that: In the diagram above, the red bars represent the query results of Release 2.1 and the blue bars represent the query results of Release 2.0. The y-axis represents the processing time of queries in seconds, the shorter the faster. The result of Query 15 is not displayed because VIEW is currently not supported in either TiDB 2.1 or 2.0. The result of Query 5 is not displayed because no result is returned during a long period of time caused by the Join Order issue. "}, {"url": "https://pingcap.com/docs-cn/benchmark/tpch-v2/", "title": "TiDB TPC-H 50G 性能测试报告", "content": " TiDB TPC-H 50G 性能测试报告 测试目的 测试 TiDB 在 OLAP 场景下 2.0 和 2.1 版本的性能对比。 注意:不同的测试环境可能使测试结果发生改变。 测试环境 测试机器信息 系统信息 机器 IP 操作系统 内核版本 文件系统类型 10.0.1.4 CentOS 7.5.1804 64bit 3.10.0-862.3.3.el7.x86_64 ext4 10.0.1.5 CentOS 7.5.1804 64bit 3.10.0-862.3.3.el7.x86_64 ext4 10.0.1.6 CentOS 7.5.1804 64bit 3.10.0-862.3.3.el7.x86_64 ext4 10.0.1.7 CentOS 7.5.1804 64bit 3.10.0-862.3.3.el7.x86_64 ext4 10.0.1.8 CentOS 7.5.1804 64bit 3.10.0-862.3.3.el7.x86_64 ext4 10.0.1.9 CentOS 7.5.1804 64bit 3.10.0-862.3.3.el7.x86_64 ext4 硬件信息 类别 10.0.1.4 10.0.1.5, 10.0.1.6, 10.0.1.7, 10.0.1.8, 10.0.1.9 CPU 16 vCPUs, Intel® Xeon® CPU E5-2660 0 @ 2.20GHz 8 vCPUs, Intel® Xeon® CPU E5-2660 0 @ 2.20GHz 内存 110G 55G 磁盘 221G SSD 111G SSD 网卡 万兆网卡, 10000Mb/s 万兆网卡, 10000Mb/s TPC-H tidb-bench/tpch集群拓扑 机器 IP 部署的实例 10.0.1.5 TiKV * 1 10.0.1.6 TiKV * 1 10.0.1.7 TiKV * 1 10.0.1.8 TiKV * 1 10.0.1.9 TiKV * 1 10.0.1.4 PD * 1 10.0.1.4 TiDB * 1 TiDB 版本信息 TiDB 2.0: 组件名 版本号 commit hash TiDB v2.0.7 29ec059cb3b7d14b6f52c2f219f94a89570162bc TiKV v2.0.7 d0b8cd7c7f62f06e7ef456837bd32a47da1ca4cd PD v2.0.5 b64716707b7279a4ae822be767085ff17b5f3fea TiDB 2.1: 组件名 版本号 commit hash TiDB v2.1.0-rc.2 16864f95b47f859ed6104555ccff0387abdc2429 TiKV v2.1.0-rc.2 8458ce53ebbd434c48baac6373fe0f0a43a54005 PD v2.1.0-rc.2 55db505e8f35e8ab4e00efd202beb27a8ecc40fb 测试结果 Query ID TiDB 2.0 TiDB 2.1 1 121.550595999s 91.4755480289s 2 53.0638680458s 23.1186130047s 3 75.7236940861s 61.790802002s 4 30.2647120953s 26.3483440876s 6 51.4850790501s 34.6432199478s 7 216.787364006s 94.9856910706s 8 188.717588902s 181.852752209s 9 546.438174009s 414.462754965s 10 109.978317022s 37.0369961262s 11 42.9398438931s 37.6951580048s 12 60.455039978s 40.2236878872s 13 230.278712988s 70.2887151241s 14 61.2673521042s 35.8372960091s 16 30.2539310455s 18.5897550583s 17 3200.70173788s 263.095014811s 18 1035.59847498s 296.360667944s 19 54.3732938766s 40.4523630142s 20 105.094577074s 53.2429068089s 21 389.883709908s 361.034544945s 22 64.0494630337s 65.7153418064s 说明: - 图中橙色为 Release 2.1,蓝色为 Release 2.0,纵坐标是 Query 的处理时间,越低越好 - Query 15 因为 2.1 和 2.0 都还未支持视图,所以未列出结果 - Query 5 因为 Join Order 问题长时间未跑出结果来,所以未列出结果"}, {"url": "https://pingcap.com/docs-cn/benchmark/tpch/", "title": "TiDB TPC-H 50G 性能测试报告", "content": " TiDB TPC-H 50G 性能测试报告 测试目的 测试 TiDB 在 OLAP 场景下 1.0 和 2.0 版本的性能对比。 注意:不同的测试环境可能使测试结果发生改变。 测试环境 测试机器信息 系统信息 机器 IP 操作系统 内核版本 文件系统类型 172.16.31.2 Ubuntu 17.10 64bit 4.13.0-16-generic ext4 172.16.31.3 Ubuntu 17.10 64bit 4.13.0-16-generic ext4 172.16.31.4 Ubuntu 17.10 64bit 4.13.0-16-generic ext4 172.16.31.6 CentOS 7.4.1708 64bit 3.10.0-693.11.6.el7.x86_64 ext4 172.16.31.8 CentOS 7.4.1708 64bit 3.10.0-693.11.6.el7.x86_64 ext4 172.16.31.10 CentOS 7.4.1708 64bit 3.10.0-693.11.6.el7.x86_64 ext4 硬件信息 类别 名称 CPU 40 vCPUs, Intel® Xeon® CPU E5-2630 v4 @ 2.20GHz 内存 128GB, 8条16GB RDIMM, 2400MT/s, 双列, x8 带宽 磁盘 2 块 Intel P4500 系列 4T SSD 硬盘 网卡 万兆网卡 TPC-H tidb-bench/tpch集群拓扑 机器 IP 部署的实例 172.16.31.2 TiKV * 2 172.16.31.3 TiKV * 2 172.16.31.6 TiKV * 2 172.16.31.8 TiKV * 2 172.16.31.10 TiKV * 2 172.16.31.10 PD * 1 172.16.31.4 TiDB * 1 TiDB 版本信息 TiDB 1.0: 组件名 版本号 commit hash TiDB v1.0.9 4c7ee3580cd0a69319b2c0c08abdc59900df7344 TiKV v1.0.8 2bb923a4cd23dbf68f0d16169fd526dc5c1a9f4a PD v1.0.8 137fa734472a76c509fbfd9cb9bc6d0dc804a3b7 TiDB 2.0: 组件名 版本号 commit hash TiDB v2.0.0-rc.6 82d35f1b7f9047c478f4e1e82aa0002abc8107e7 TiKV v2.0.0-rc.6 8bd5c54966c6ef42578a27519bce4915c5b0c81f PD v2.0.0-rc.6 9b824d288126173a61ce7d51a71fc4cb12360201 测试结果 Query ID TiDB 2.0 TiDB 1.0 1 33.915s 215.305s 2 25.575s NaN 3 59.631s 196.003s 4 30.234s 249.919s 5 31.666s OOM 6 13.111s 118.709s 7 31.710s OOM 8 31.734s 800.546s 9 34.211s 630.639s 10 30.774s 133.547s 11 27.692s 78.026s 12 27.962s 124.641s 13 27.676s 174.695s 14 19.676s 110.602s 15 View Required View Required 16 24.890s 40.529s 17 245.796s NaN 18 91.256s OOM 19 37.615s NaN 20 44.167s 212.201s 21 31.466s OOM 22 31.539s 125.471s 说明: - 图中橙色为 Release 1.0,蓝色为 Release 2.0,纵坐标是 Query 的处理时间,越低越好 - Query 15 因为 1.0 和 2.0 都还未支持视图,所以结果标记为 “View Required” - Query 2, 17, 19 因为 TiDB 1.0 长时间未跑出结果,所以结果标记为 “Nan” - Query 5, 7, 18, 21 因为 TiDB 1.0 在跑的过程中内存占用过多被 oom-killer 杀死,所以结果标记为 “OOM”"}, {"url": "https://pingcap.com/docs/sql/transaction-isolation/", "title": "TiDB Transaction Isolation Levels", "content": " TiDB Transaction Isolation Levels Transaction isolation is one of the foundations of database transaction processing. Isolation is the I in the acronym ACID (Atomicity, Consistency, Isolation, Durability), which represents the isolation property of database transactions.The SQL-92 standard defines four levels of transaction isolation: Read Uncommitted, Read Committed, Repeatable Read and Serializable. See the following table for details: Isolation Level Dirty Read Nonrepeatable Read Phantom Read Serialization Anomaly Read Uncommitted Possible Possible Possible Possible Read Committed Not possible Possible Possible Possible Repeatable Read Not possible Not possible Not possible in TiDB Possible Serializable Not possible Not possible Not possible Not possible TiDB offers the Repeatable Read isolation level.TiDB uses the Percolator transaction model. A global read timestamp is obtained when the transaction is started, and a global commit timestamp is obtained when the transaction is committed. The execution order of transactions is confirmed based on the timestamps. To know more about the implementation of TiDB transaction model, see MVCC in TiKV.Repeatable Read The Repeatable Read isolation level only sees data committed before the transaction begins, and it never sees either uncommitted data or changes committed during transaction execution by concurrent transactions. However, the transaction statement does see the effects of previous updates executed within its own transaction, even though they are not yet committed.For transactions running on different nodes, the start and commit order depends on the order that the timestamp is obtained from PD.Transactions of the Repeatable Read isolation level cannot concurrently update a same row. When committing, if the transaction finds that the row has been updated by another transaction after it starts, then the transaction rolls back and retries automatically. For example:create table t1(id int); insert into t1 values(0); start transaction; | start transaction; select * from t1; | select * from t1; update t1 set id=id+1; | update t1 set id=id+1; commit; | | commit; -- roll back and retry atutomatically Difference between TiDB and ANSI Repeatable Read The Repeatable Read isolation level in TiDB differs from ANSI Repeatable Read isolation level, though they sharing the same name. According to the standard described in the A Critique of ANSI SQL Isolation Levels paper, TiDB implements the snapshot isolation level, and it does not allow phantom reads but allows write skews. In contrast, the ANSI Repeatable Read isolation level allows phantom reads but does not allow write skews.Difference between TiDB and MySQL Repeatable Read The Repeatable Read isolation level in TiDB differs from that in MySQL. The MySQL Repeatable Read isolation level does not check whether the current version is visible when updating, which means it can continue to update even if the row has been updated after the transaction starts. In contrast, if the row has been updated after the transaction starts, the TiDB transaction is rolled back and retried. Transaction Retries in TiDB might fail, leading to a final failure of the transaction, while in MySQL the updating transaction can be successful.The MySQL Repeatable Read isolation level is not the snapshot isolation level. The consistency of MySQL Repeatable Read isolation level is weaker than both the snapshot isolation level and TiDB Repeatable Read isolation level.Transaction retry For the insert/delete/update operation, if the transaction fails and can be retried according to the system, the transaction is automatically retried within the system.You can control the number of retries by configuring the retry-limit parameter:[performance] ... # The maximum number of retries when commit a transaction. retry-limit = 10 Description of optimistic transactions Because TiDB uses the optimistic transaction model, the final result might not be as expected if the transactions created by the explicit BEGIN statement automatically retry after meeting a conflict.Example 1: Session1 Session2 begin; begin; select balance from t where id = 1; update t set balance = balance -100 where id = 1; update t set balance = balance -100 where id = 2; // the subsequent logic depends on the result of select commit; if balance > 100 { update t set balance = balance + 100 where id = 2; } commit; // automatic retry Example 2: Session1 Session2 begin; begin; update t set balance = balance - 100 where id = 1; delete t where id = 1; commit; // the subsequent logic depends on the result of affected_rows if affected_rows > 100 { update t set balance = balance + 100 where id = 2; } commit; // automatic retry Under the automatic retry mechanism of TiDB, all the executed statements for the first time are re-executed again. When whether the subsequent statements are to be executed or not depends on the results of the previous statements, automatic retry cannot guarantee the final result is as expected.To disable the automatic retry of explicit transactions, configure the tidb_disable_txn_auto_retry global variable:set @@global.tidb_disable_txn_auto_retry = 1; This variable does not affect the implicit single statement with auto_commit = 1, so this type of statement still automatically retries.After the automatic retry of explicit transactions is disabled, if a transaction conflict occurs, the commit statement returns an error that includes the try again later string. The application layer uses this string to judge whether the error can be retried.If the application layer logic is included in the process of transaction execution, it is recommended to add the retry of explicit transactions at the application layer and disable automatic retry.Statement rollback If you execute a statement within a transaction, the statement does not take effect when an error occurs.begin; insert into test values (1); insert into tset values (2); // This statement does not take effect because "test" is misspelled as "tset". insert into test values (3); commit; In the above example, the second insert statement fails, while the other two insert statements (1 & 3) can be successfully committed.begin; insert into test values (1); insert into tset values (2); // This statement does not take effect because "test" is misspelled as "tset". insert into test values (3); rollback; In the above example, the second insert statement fails, and this transaction does not insert any data into the database because rollback is called."}, {"url": "https://pingcap.com/docs/v1.0/sql/transaction-isolation/", "title": "TiDB Transaction Isolation Levels", "content": " TiDB Transaction Isolation Levels Transaction isolation is one of the foundations of database transaction processing. Isolation is the I in the acronym ACID (Atomicity, Consistency, Isolation, Durability), which represents the isolation property of database transactions.The SQL-92 standard defines four levels of transaction isolation: Read Uncommitted, Read Committed, Repeatable Read and Serializable. See the following table for details: Isolation Level Dirty Read Nonrepeatable Read Phantom Read Serialization Anomaly Read Uncommitted Possible Possible Possible Possible Read Committed Not possible Possible Possible Possible Repeatable Read Not possible Not possible Not possible in TiDB Possible Serializable Not possible Not possible Not possible Not possible TiDB offers two transaction isolation levels: Read Committed and Repeatable Read.TiDB uses the Percolator transaction model. A global read timestamp is obtained when the transaction is started, and a global commit timestamp is obtained when the transaction is committed. The execution order of transactions is confirmed based on the timestamps. To know more about the implementation of TiDB transaction model, see MVCC in TiKV.Use the following command to set the level of transaction isolation:SET SESSION TRANSACTION ISOLATION LEVEL [read committed|repeatable read] Repeatable Read Repeatable Read is the default transaction isolation level in TiDB. The Repeatable Read isolation level only sees data committed before the transaction begins, and it never sees either uncommitted data or changes committed during transaction execution by concurrent transactions. However, the transaction statement does see the effects of previous updates executed within its own transaction, even though they are not yet committed.For transactions running on different nodes, the start and commit order depends on the order that the timestamp is obtained from PD.Transactions of the Repeatable Read isolation level cannot concurrently update a same row. When committing, if the transaction finds that the row has been updated by another transaction after it starts, then the transaction rolls back and retries automatically. For example:create table t1(id int); insert into t1 values(0); start transaction; | start transaction; select * from t1; | select * from t1; update t1 set id=id+1; | update t1 set id=id+1; commit; | | commit; -- roll back and retry atutomatically Difference between TiDB and ANSI Repeatable Read The Repeatable Read isolation level in TiDB differs from ANSI Repeatable Read isolation level, though they sharing the same name. According to the standard described in the A Critique of ANSI SQL Isolation Levels paper, TiDB implements the snapshot isolation level, and it does not allow phantom reads but allows write skews. In contrast, the ANSI Repeatable Read isolation level allows phantom reads but does not allow write skews.Difference between TiDB and MySQL Repeatable Read The Repeatable Read isolation level in TiDB differs from that in MySQL. The MySQL Repeatable Read isolation level does not check whether the current version is visible when updating, which means it can continue to update even if the row has been updated after the transaction starts. In contrast, if the row has been updated after the transaction starts, the TiDB transaction is rolled back and retried. Transaction Retries in TiDB might fail, leading to a final failure of the transaction, while in MySQL the updating transaction can be successful.The MySQL Repeatable Read isolation level is not the snapshot isolation level. The consistency of MySQL Repeatable Read isolation level is weaker than both the snapshot isolation level and TiDB Repeatable Read isolation level.Read Committed The Read Committed isolation level differs from Repeatable Read isolation level. Read Committed only guarantees the uncommitted data cannot be read.Note: Because the transaction commit is a dynamic process, the Read Committed isolation level might read the data committed by part of the transaction. It is not recommended to use the Read Committed isolation level in a database that requires strict consistency.Transaction retry For the insert/delete/update operation, if the transaction fails and can be retried according to the system, the transaction is automatically retried within the system.You can control the number of retries by configuring the retry-limit parameter:[performance] ... # The maximum number of retries when commit a transaction. retry-limit = 10"}, {"url": "https://pingcap.com/docs/v2.0/sql/transaction-isolation/", "title": "TiDB Transaction Isolation Levels", "content": " TiDB Transaction Isolation Levels Transaction isolation is one of the foundations of database transaction processing. Isolation is the I in the acronym ACID (Atomicity, Consistency, Isolation, Durability), which represents the isolation property of database transactions.The SQL-92 standard defines four levels of transaction isolation: Read Uncommitted, Read Committed, Repeatable Read and Serializable. See the following table for details: Isolation Level Dirty Read Nonrepeatable Read Phantom Read Serialization Anomaly Read Uncommitted Possible Possible Possible Possible Read Committed Not possible Possible Possible Possible Repeatable Read Not possible Not possible Not possible in TiDB Possible Serializable Not possible Not possible Not possible Not possible TiDB offers two transaction isolation levels: Read Committed and Repeatable Read.TiDB uses the Percolator transaction model. A global read timestamp is obtained when the transaction is started, and a global commit timestamp is obtained when the transaction is committed. The execution order of transactions is confirmed based on the timestamps. To know more about the implementation of TiDB transaction model, see MVCC in TiKV.Use the following command to set the isolation level of the Session or Global transaction:SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL [read committed|repeatable read] If you do not use the Session or Global keyword, this statement takes effect only for the transaction to be executed next, but not for the entire session or global transaction.SET TRANSACTION ISOLATION LEVEL [read committed|repeatable read] Repeatable Read Repeatable Read is the default transaction isolation level in TiDB. The Repeatable Read isolation level only sees data committed before the transaction begins, and it never sees either uncommitted data or changes committed during transaction execution by concurrent transactions. However, the transaction statement does see the effects of previous updates executed within its own transaction, even though they are not yet committed.For transactions running on different nodes, the start and commit order depends on the order that the timestamp is obtained from PD.Transactions of the Repeatable Read isolation level cannot concurrently update a same row. When committing, if the transaction finds that the row has been updated by another transaction after it starts, then the transaction rolls back and retries automatically. For example:create table t1(id int); insert into t1 values(0); start transaction; | start transaction; select * from t1; | select * from t1; update t1 set id=id+1; | update t1 set id=id+1; commit; | | commit; -- roll back and retry atutomatically Difference between TiDB and ANSI Repeatable Read The Repeatable Read isolation level in TiDB differs from ANSI Repeatable Read isolation level, though they sharing the same name. According to the standard described in the A Critique of ANSI SQL Isolation Levels paper, TiDB implements the snapshot isolation level, and it does not allow phantom reads but allows write skews. In contrast, the ANSI Repeatable Read isolation level allows phantom reads but does not allow write skews.Difference between TiDB and MySQL Repeatable Read The Repeatable Read isolation level in TiDB differs from that in MySQL. The MySQL Repeatable Read isolation level does not check whether the current version is visible when updating, which means it can continue to update even if the row has been updated after the transaction starts. In contrast, if the row has been updated after the transaction starts, the TiDB transaction is rolled back and retried. Transaction Retries in TiDB might fail, leading to a final failure of the transaction, while in MySQL the updating transaction can be successful.The MySQL Repeatable Read isolation level is not the snapshot isolation level. The consistency of MySQL Repeatable Read isolation level is weaker than both the snapshot isolation level and TiDB Repeatable Read isolation level.Read Committed The Read Committed isolation level differs from Repeatable Read isolation level. Read Committed only guarantees the uncommitted data cannot be read.Note: Because the transaction commit is a dynamic process, the Read Committed isolation level might read the data committed by part of the transaction. It is not recommended to use the Read Committed isolation level in a database that requires strict consistency.Transaction retry For the insert/delete/update operation, if the transaction fails and can be retried according to the system, the transaction is automatically retried within the system.You can control the number of retries by configuring the retry-limit parameter:[performance] ... # The maximum number of retries when commit a transaction. retry-limit = 10 Description of optimistic transactions Because TiDB uses the optimistic transaction model, the final result might not be as expected if the transactions created by the explicit BEGIN statement automatically retry after meeting a conflict.Example 1: Session1 Session2 begin; begin; select balance from t where id = 1; update t set balance = balance -100 where id = 1; update t set balance = balance -100 where id = 2; // the subsequent logic depends on the result of select commit; if balance > 100 { update t set balance = balance + 100 where id = 2; } commit; // automatic retry Example 2: Session1 Session2 begin; begin; update t set balance = balance - 100 where id = 1; delete t where id = 1; commit; // the subsequent logic depends on the result of affected_rows if affected_rows > 100 { update t set balance = balance + 100 where id = 2; } commit; // automatic retry Under the automatic retry mechanism of TiDB, all the executed statements for the first time are re-executed again. When whether the subsequent statements are to be executed or not depends on the results of the previous statements, automatic retry cannot guarantee the final result is as expected.To disable the automatic retry of explicit transactions, configure the tidb_disable_txn_auto_retry global variable:set @@global.tidb_disable_txn_auto_retry = 1; This variable does not affect the implicit single statement with auto_commit = 1, so this type of statement still automatically retries.After the automatic retry of explicit transactions is disabled, if a transaction conflict occurs, the commit statement returns an error that includes the try again later string. The application layer uses this string to judge whether the error can be retried.If the application layer logic is included in the process of transaction execution, it is recommended to add the retry of explicit transactions at the application layer and disable automatic retry.Statement rollback If you execute a statement within a transaction, the statement does not take effect when an error occurs.begin; insert into test values (1); insert into tset values (2); // This statement does not take effect because "test" is misspelled as "tset". insert into test values (3); commit; In the above example, the second insert statement fails, while the other two insert statements (1 & 3) can be successfully committed.begin; insert into test values (1); insert into tset values (2); // This statement does not take effect because "test" is misspelled as "tset". insert into test values (3); rollback; In the above example, the second insert statement fails, and this transaction does not insert any data into the database because rollback is called."}, {"url": "https://pingcap.com/docs/sql/user-account-management/", "title": "TiDB User Account Management", "content": " TiDB User Account Management This document describes how to manage a TiDB user account.User names and passwords TiDB stores the user accounts in the table of the mysql.user system database. Each account is identified by a user name and the client host. Each account may have a password.You can connect to the TiDB server using the MySQL client, and use the specified account and password to login:shell> mysql --port 4000 --user xxx --password Or use the abbreviation of command line parameters:shell> mysql -P 4000 -u xxx -p Add user accounts You can create TiDB accounts in two ways: By using the standard account-management SQL statements intended for creating accounts and establishing their privileges, such as CREATE USER and GRANT. By manipulating the grant tables directly with statements such as INSERT, UPDATE, or DELETE. It is recommended to use the account-management statements, because manipulating the grant tables directly can lead to incomplete updates. You can also create accounts by using third party GUI tools.The following example uses the CREATE USER and GRANT statements to set up four accounts:mysql> CREATE USER 'finley'@'localhost' IDENTIFIED BY 'some_pass'; mysql> GRANT ALL PRIVILEGES ON *.* TO 'finley'@'localhost' WITH GRANT OPTION; mysql> CREATE USER 'finley'@'%' IDENTIFIED BY 'some_pass'; mysql> GRANT ALL PRIVILEGES ON *.* TO 'finley'@'%' WITH GRANT OPTION; mysql> CREATE USER 'admin'@'localhost' IDENTIFIED BY 'admin_pass'; mysql> GRANT RELOAD,PROCESS ON *.* TO 'admin'@'localhost'; mysql> CREATE USER 'dummy'@'localhost'; To see the privileges for an account, use SHOW GRANTS:mysql> SHOW GRANTS FOR 'admin'@'localhost'; +-----------------------------------------------------+ | Grants for admin@localhost | +-----------------------------------------------------+ | GRANT RELOAD, PROCESS ON *.* TO 'admin'@'localhost' | +-----------------------------------------------------+ Remove user accounts To remove a user account, use the DROP USER statement:mysql> DROP USER 'jeffrey'@'localhost'; Reserved user accounts TiDB creates the 'root'@'%' default account during the database initialization.Set account resource limits Currently, TiDB does not support setting account resource limits.Assign account passwords TiDB stores passwords in the mysql.user system database. Operations that assign or update passwords are permitted only to users with the CREATE USER privilege, or, alternatively, privileges for the mysql database (INSERT privilege to create new accounts, UPDATE privilege to update existing accounts).To assign a password when you create a new account, use CREATE USER and include an IDENTIFIED BY clause:CREATE USER 'jeffrey'@'localhost' IDENTIFIED BY 'mypass'; To assign or change a password for an existing account, use SET PASSWORD FOR or ALTER USER:SET PASSWORD FOR 'root'@'%' = 'xxx'; Or:ALTER USER 'jeffrey'@'localhost' IDENTIFIED BY 'mypass';"}, {"url": "https://pingcap.com/docs/v1.0/sql/user-account-management/", "title": "TiDB User Account Management", "content": " TiDB User Account Management User names and passwords TiDB stores the user accounts in the table of the mysql.user system database. Each account is identified by a user name and the client host. Each account may have a password.You can connect to the TiDB server using the MySQL client, and use the specified account and password to login:shell> mysql --port 4000 --user xxx --password Or use the abbreviation of command line parameters:shell> mysql -P 4000 -u xxx -p Add user accounts You can create TiDB accounts in two ways: By using the standard account-management SQL statements intended for creating accounts and establishing their privileges, such as CREATE USER and GRANT. By manipulating the grant tables directly with statements such as INSERT, UPDATE, or DELETE. It is recommended to use the account-management statements, because manipulating the grant tables directly can lead to incomplete updates. You can also create accounts by using third party GUI tools.The following example uses the CREATE USER and GRANT statements to set up four accounts:mysql> CREATE USER 'finley'@'localhost' IDENTIFIED BY 'some_pass'; mysql> GRANT ALL PRIVILEGES ON *.* TO 'finley'@'localhost' WITH GRANT OPTION; mysql> CREATE USER 'finley'@'%' IDENTIFIED BY 'some_pass'; mysql> GRANT ALL PRIVILEGES ON *.* TO 'finley'@'%' WITH GRANT OPTION; mysql> CREATE USER 'admin'@'localhost' IDENTIFIED BY 'admin_pass'; mysql> GRANT RELOAD,PROCESS ON *.* TO 'admin'@'localhost'; mysql> CREATE USER 'dummy'@'localhost'; To see the privileges for an account, use SHOW GRANTS:mysql> SHOW GRANTS FOR 'admin'@'localhost'; +-----------------------------------------------------+ | Grants for admin@localhost | +-----------------------------------------------------+ | GRANT RELOAD, PROCESS ON *.* TO 'admin'@'localhost' | +-----------------------------------------------------+ Remove user accounts To remove a user account, use the DROP USER statement:mysql> DROP USER 'jeffrey'@'localhost'; Reserved user accounts TiDB creates the 'root'@'%' default account during the database initialization.Set account resource limits Currently, TiDB does not support setting account resource limits.Assign account passwords TiDB stores passwords in the mysql.user system database. Operations that assign or update passwords are permitted only to users with the CREATE USER privilege, or, alternatively, privileges for the mysql database (INSERT privilege to create new accounts, UPDATE privilege to update existing accounts).To assign a password when you create a new account, use CREATE USER and include an IDENTIFIED BY clause:CREATE USER 'jeffrey'@'localhost' IDENTIFIED BY 'mypass'; To assign or change a password for an existing account, use SET PASSWORD FOR or ALTER USER:SET PASSWORD FOR 'root'@'%' = 'xxx'; Or:ALTER USER 'jeffrey'@'localhost' IDENTIFIED BY 'mypass';"}, {"url": "https://pingcap.com/docs/v2.0/sql/user-account-management/", "title": "TiDB User Account Management", "content": " TiDB User Account Management This document describes how to manage a TiDB user account.User names and passwords TiDB stores the user accounts in the table of the mysql.user system database. Each account is identified by a user name and the client host. Each account may have a password.You can connect to the TiDB server using the MySQL client, and use the specified account and password to login:shell> mysql --port 4000 --user xxx --password Or use the abbreviation of command line parameters:shell> mysql -P 4000 -u xxx -p Add user accounts You can create TiDB accounts in two ways: By using the standard account-management SQL statements intended for creating accounts and establishing their privileges, such as CREATE USER and GRANT. By manipulating the grant tables directly with statements such as INSERT, UPDATE, or DELETE. It is recommended to use the account-management statements, because manipulating the grant tables directly can lead to incomplete updates. You can also create accounts by using third party GUI tools.The following example uses the CREATE USER and GRANT statements to set up four accounts:mysql> CREATE USER 'finley'@'localhost' IDENTIFIED BY 'some_pass'; mysql> GRANT ALL PRIVILEGES ON *.* TO 'finley'@'localhost' WITH GRANT OPTION; mysql> CREATE USER 'finley'@'%' IDENTIFIED BY 'some_pass'; mysql> GRANT ALL PRIVILEGES ON *.* TO 'finley'@'%' WITH GRANT OPTION; mysql> CREATE USER 'admin'@'localhost' IDENTIFIED BY 'admin_pass'; mysql> GRANT RELOAD,PROCESS ON *.* TO 'admin'@'localhost'; mysql> CREATE USER 'dummy'@'localhost'; To see the privileges for an account, use SHOW GRANTS:mysql> SHOW GRANTS FOR 'admin'@'localhost'; +-----------------------------------------------------+ | Grants for admin@localhost | +-----------------------------------------------------+ | GRANT RELOAD, PROCESS ON *.* TO 'admin'@'localhost' | +-----------------------------------------------------+ Remove user accounts To remove a user account, use the DROP USER statement:mysql> DROP USER 'jeffrey'@'localhost'; Reserved user accounts TiDB creates the 'root'@'%' default account during the database initialization.Set account resource limits Currently, TiDB does not support setting account resource limits.Assign account passwords TiDB stores passwords in the mysql.user system database. Operations that assign or update passwords are permitted only to users with the CREATE USER privilege, or, alternatively, privileges for the mysql database (INSERT privilege to create new accounts, UPDATE privilege to update existing accounts).To assign a password when you create a new account, use CREATE USER and include an IDENTIFIED BY clause:CREATE USER 'jeffrey'@'localhost' IDENTIFIED BY 'mypass'; To assign or change a password for an existing account, use SET PASSWORD FOR or ALTER USER:SET PASSWORD FOR 'root'@'%' = 'xxx'; Or:ALTER USER 'jeffrey'@'localhost' IDENTIFIED BY 'mypass';"}, {"url": "https://pingcap.com/docs/sql/user-manual/", "title": "TiDB User Guide", "content": " TiDB User Guide TiDB supports the SQL-92 standard and is compatible with MySQL. To help you easily get started with TiDB, TiDB user guide mainly inherits the MySQL document structure with some TiDB specific changes.TiDB server administration The TiDB Server The TiDB Command Options The TiDB Data Directory The TiDB System Database The TiDB System Variables The Proprietary System Variables and Syntax in TiDB The TiDB Server Logs The TiDB Access Privilege System TiDB User Account Management Use Encrypted Connections SQL optimization Understand the Query Execution Plan Introduction to Statistics Language structure Literal Values Schema Object Names Keywords and Reserved Words User-Defined Variables Expression Syntax Comment Syntax Globalization Character Set Support Character Set Configuration Time Zone Data types Numeric Types Date and Time Types String Types JSON Types The ENUM data type The SET Type Data Type Default Values Functions and operators Function and Operator Reference Type Conversion in Expression Evaluation Operators Control Flow Functions String Functions Numeric Functions and Operators Date and Time Functions Bit Functions and Operators Cast Functions and Operators Encryption and Compression Functions Information Functions JSON Functions Functions Used with Global Transaction IDs [TBD] Aggregate (GROUP BY) Functions Miscellaneous Functions Precision Math SQL statement syntax Data Definition Statements Data Manipulation Statements Transactions Database Administration Statements Prepared SQL Statement Syntax Utility Statements TiDB SQL Syntax Diagram Generated columns Generated Columns Connectors and APIs Connectors and APIs Compatibility with MySQL Compatibility with MySQL "}, {"url": "https://pingcap.com/docs/v1.0/sql/user-manual/", "title": "TiDB User Guide", "content": " TiDB User Guide TiDB supports the SQL-92 standard and is compatible with MySQL. To help you easily get started with TiDB, TiDB user guide mainly inherits the MySQL document structure with some TiDB specific changes.TiDB server administration The TiDB Server The TiDB Command Options The TiDB Data Directory The TiDB System Database The TiDB System Variables The Proprietary System Variables and Syntax in TiDB The TiDB Server Logs The TiDB Access Privilege System TiDB User Account Management Use Encrypted Connections SQL optimization Understand the Query Execution Plan Introduction to Statistics Language structure Literal Values Schema Object Names Keywords and Reserved Words User-Defined Variables Expression Syntax Comment Syntax Globalization Character Set Support Character Set Configuration Time Zone Data types Numeric Types Date and Time Types String Types JSON Types The ENUM data type The SET Type Data Type Default Values Functions and operators Function and Operator Reference Type Conversion in Expression Evaluation Operators Control Flow Functions String Functions Numeric Functions and Operators Date and Time Functions Bit Functions and Operators Cast Functions and Operators Encryption and Compression Functions Information Functions JSON Functions Functions Used with Global Transaction IDs [TBD] Aggregate (GROUP BY) Functions Miscellaneous Functions Precision Math SQL statement syntax Data Definition Statements Data Manipulation Statements Transactions Database Administration Statements Prepared SQL Statement Syntax Utility Statements TiDB SQL Syntax Diagram JSON functions and generated column JSON Functions and Generated Column Connectors and APIs Connectors and APIs Compatibility with MySQL Compatibility with MySQL "}, {"url": "https://pingcap.com/docs/v2.0/sql/user-manual/", "title": "TiDB User Guide", "content": " TiDB User Guide TiDB supports the SQL-92 standard and is compatible with MySQL. To help you easily get started with TiDB, TiDB user guide mainly inherits the MySQL document structure with some TiDB specific changes.TiDB server administration The TiDB Server The TiDB Command Options The TiDB Data Directory The TiDB System Database The TiDB System Variables The Proprietary System Variables and Syntax in TiDB The TiDB Server Logs The TiDB Access Privilege System TiDB User Account Management Use Encrypted Connections SQL optimization Understand the Query Execution Plan Introduction to Statistics Language structure Literal Values Schema Object Names Keywords and Reserved Words User-Defined Variables Expression Syntax Comment Syntax Globalization Character Set Support Character Set Configuration Time Zone Data types Numeric Types Date and Time Types String Types JSON Types The ENUM data type The SET Type Data Type Default Values Functions and operators Function and Operator Reference Type Conversion in Expression Evaluation Operators Control Flow Functions String Functions Numeric Functions and Operators Date and Time Functions Bit Functions and Operators Cast Functions and Operators Encryption and Compression Functions Information Functions JSON Functions Functions Used with Global Transaction IDs [TBD] Aggregate (GROUP BY) Functions Miscellaneous Functions Precision Math SQL statement syntax Data Definition Statements Data Manipulation Statements Transactions Database Administration Statements Prepared SQL Statement Syntax Utility Statements TiDB SQL Syntax Diagram JSON functions and generated column JSON Functions and Generated Column Connectors and APIs Connectors and APIs Compatibility with MySQL Compatibility with MySQL "}, {"url": "https://pingcap.com/tidb-academy/mysql_dbas/mysql-compatibility/behavior-differences/", "title": "TiDB and MySQL: Behavior Differences", "content": " TiDB and MySQL: Behavior Differences Resources MySQL Compatibility Support for built-in JSON functions Support for aggregate functions Transcript In the previous video, we talked about TiDB compatibility with MySQL and how some features were not present. For example: stored procedures, triggers, views.Let’s now talk about something more subtle: the feature also exists in TiDB, but works differently. In many cases this is TiDB is a distributed database, and needs to work a little bit differently. Let’s take a look at the TiDB manual and talk specifics.Auto increment IDs The auto-increment ID feature in TiDB is only guaranteed to be automatically incremental and unique but is not guaranteed to be allocated sequentially. Each TiDB server is allocated auto-increment IDs in batches of 30 thousand. It is not a good practice to rely on auto-increment values to be sequential, but there are some applications that do do it, for example - as a shortcut for sorting rows by date.Performance schema TiDB is instrumented for collecting various performance counters about its execution, but with TiDB nodes being stateless (and without having membership) you would only be able to see statistics for an individual server at runtime. So instead in TiDB, we use a combination of best-of-breed tools with Prometheus and Grafana to centralize metrics. We will cover this in more detail when we get to ‘monitoring’. For the time being, simply know that while you can read from performance_schema tables in TiDB most will return zero results.Built-in functions TiDB supports most of MySQL’s built-in functions, such as those used when manipulating dates, manipulating strings and converting between formats. There are some exceptions to this such as geospatial functions which similar to not supporting spatial indexes, TiDB does not support yet. There are also some edge cases such as a SOUNDEX, where the function has not been added yet due to a relatively infrequent usage. At the time of recording, TiDB also does not support all of the JSON functions added in MySQL 5.7, and all aggregate functions. Both are in the process of being addressed.DDL DDL is a major advantage of TiDB over MySQL, one that is not spoken about enough. In TiDB DDL uses the online asynchronous schema change algorithm first written about in Google’s F1. It ensures that your regular operations are not impacted while DDL is being performed on the TiDB Platform. We will cover DDL in more detail later in this course, but what is relevant for now is that TiDB does not allow you to create multiple indexes or columns at the same time, as you may be used to doing in MySQL. It also does not support adding, changing or dropping the primary key on a table.Transaction Model Internally TiDB uses optimistic locking for transactions, which means that some transaction conflicts will only be checked as part of a commit process. This is similar to Group Replication in MySQL (but not regular InnoDB + Replication), and it is important that your application check for errors from commit.Large Transactions Due to the distributed + 2-phase commit requirement of TiDB, large transactions that modify data can be particularly problematic. TiDB intentionally sets some limits on transaction sizes to limit impact: Each Key-Value entry is no more than 6MB The total number of Key-Value entry is no more than 300,000 The total size of Key-Value entry is no more than 100MB (There are similar limits on Google Cloud Spanner, by which TiDB’s architecture is inspired.)Load data Related to the point above, loading large files into a table in a single transaction is not ideally suited. TiDB commits rows from load data every 20,000 rows.Storage engines TiDB actually supports a similar architecture to MySQL, in which TiKV is the distributed storage engine that sits below TiDB. But in most cases, you will be using TiKV, and for compatibility reasons when you create a table it will look like it’s InnoDB. TiKV does behave similarly to InnoDB in many respects since it is a transactional, strongly consistent engine. You can not mix-and-match engines, and there is for example no MyISAM-like equivalent in TiDB.EXPLAIN The output of the query execution plan returned from the EXPLAIN command differs from MySQL. We will walk through examples when we get to query optimization.So that’s it for major behavior differences. We covered a lot in this video, and if you have any lurking questions, I recommend giving the MySQL Compatibility documentation a read over before proceeding on."}, {"url": "https://pingcap.com/tidb-academy/mysql_dbas/mysql-compatibility/default-differences/", "title": "TiDB and MySQL: Default Differences", "content": " TiDB and MySQL: Default Differences Resources MySQL Compatibility Transcript In the previous video, I talked about TiDB’s behavior differences from MySQL. As a follow-on, I’m now going to cover differences in defaults between TiDB and MySQL 5.7. This is really an extension of behavior differences, since TiDB is behaving in a way that MySQL does not out of the box, but with a configuration change (either to TiDB or MySQL) the two systems could be made to behave the same.Character set and collation TiDB only supports UTF-8 (which behaves like utf8mb4 in MySQL parlance), and binary collations.This means that if you run a query like select * from users where name = ‘xyz’, the xyz part is case sensitive and accent sensitive. The ordering of the characters will also be based on the byte order, which may be different from the collation order in MySQL.MySQL 5.7 by contrast defaults to latin1 and case insensitive for comparisons. This changes to utf8mb4 in MySQL 8.0, but still insensitive.SQL mode Importantly, TiDB supports the ability to run MySQL in both strict and unstrict SQL mode, giving your applications an upgrade path from earlier versions of MySQL. Like MySQL 5.7, it defaults to strict mode enabled.TiDB does not yet support all of MySQL’s SQL modes. The defaults between MySQL and TiDB’s SQL mode differ slightly, but not enough to affect most applications.Lower case table name sensitivity In TiDB, names of all tables are lower case, and this change is not directly configurable. In MySQL parlance, this is the same as setting lower_case_table_names=2.And that’s it. We’ve covered all the major differences between TiDB and MySQL.In the lab for this section, we’ll be loading sample data into TiDB and exploring it in a little bit of detail. If you have MySQL installed somewhere and want to try the same steps, feel free to do so!The commands are, of course, identical."}, {"url": "https://pingcap.com/docs-cn/sql/tidb-specific/", "title": "TiDB 专用系统变量和语法", "content": " TiDB 专用系统变量和语法 TiDB 在 MySQL 的基础上,定义了一些专用的系统变量和语法用来优化性能。系统变量 变量可以通过 SET 语句设置,例如set @@tidb_distsql_scan_concurrency = 10 如果需要设值全局变量,执行set @@global.tidb_distsql_scan_concurrency = 10 tidb_snapshot 作用域: SESSION默认值: 空字符串这个变量用来设置当前会话期待读取的历史数据所处时刻。比如当设置为 “2017-11-11 20:20:20” 时或者一个 TSO 数字 “400036290571534337”,当前会话将能读取到该时刻的数据。tidb_import_data 作用域: SESSION默认值: 0这个变量用来表示当前状态是否为从 dump 文件中导入数据。 当这个变量被设置为 1 时,唯一索引约束不被检查以加速导入速度。 这个变量不对外用,只是给 lightning 使用,请用户不要自行修改。tidb_opt_agg_push_down 作用域: SESSION默认值: 0这个变量用来设置优化器是否执行聚合函数下推到 Join 之前的优化操作。 当查询中聚合操作执行很慢时,可以尝试设置该变量为 1。tidb_opt_insubquery_unfold 作用域: SESSION默认值: 0这个变量用来设置优化器是否执行 in-子查询展开的优化操作。tidb_build_stats_concurrency 作用域: SESSION默认值: 4这个变量用来设置 ANALYZE 语句执行时并发度。 当这个变量被设置得更大时,会对其它的查询语句执行性能产生一定影响。tidb_checksum_table_concurrency 作用域: SESSION默认值: 4这个变量用来设置 ADMIN CHECKSUM TABLE 语句执行时扫描索引的并发度。 当这个变量被设置得更大时,会对其它的查询语句执行性能产生一定影响。tidb_current_ts 作用域: SESSION默认值: 0这个变量是一个只读变量,用来获取当前事务的时间戳。tidb_config 作用域: SESSION默认值: 空字符串这个变量是一个只读变量,用来获取当前 TiDB Server 的配置信息。tidb_distsql_scan_concurrency 作用域: SESSION | GLOBAL默认值: 15这个变量用来设置 scan 操作的并发度,AP 类应用适合较大的值,TP 类应用适合较小的值。 对于 AP 类应用,最大值建议不要超过所有 TiKV 节点的 CPU 核数。tidb_index_lookup_size 作用域: SESSION | GLOBAL默认值: 20000这个变量用来设置 index lookup 操作的 batch 大小,AP 类应用适合较大的值,TP 类应用适合较小的值。tidb_index_lookup_concurrency 作用域: SESSION | GLOBAL默认值: 4这个变量用来设置 index lookup 操作的并发度,AP 类应用适合较大的值,TP 类应用适合较小的值。tidb_index_lookup_join_concurrency 作用域: SESSION | GLOBAL默认值: 4这个变量用来设置 index lookup join 算法的并发度。tidb_hash_join_concurrency 作用域: SESSION | GLOBAL默认值: 5这个变量用来设置 hash join 算法的并发度。tidb_index_serial_scan_concurrency 作用域:SESSION | GLOBAL默认值:1这个变量用来设置顺序 scan 操作的并发度,AP 类应用适合较大的值,TP 类应用适合较小的值。tidb_projection_concurrency 作用域:SESSION | GLOBAL默认值:4这个变量用来设置 Projection 算子的并发度。tidb_hashagg_partial_concurrency 作用域:SESSION | GLOBAL默认值:4这个变量用来设置并行 hash aggregation 算法 partial 阶段的执行并发度。对于聚合函数参数不为 distinct 的情况,HashAgg 分为 partial 和 final 阶段分别并行执行。tidb_hashagg_final_concurrency 作用域:SESSION | GLOBAL默认值:4这个变量用来设置并行 hash aggregation 算法 final 阶段的执行并发度。对于聚合函数参数不为 distinct 的情况,HashAgg 分为 partial 和 final 阶段分别并行执行。tidb_index_join_batch_size 作用域:SESSION | GLOBAL默认值:25000这个变量用来设置 index lookup join 操作的 batch 大小,AP 类应用适合较大的值,TP 类应用适合较小的值。tidb_skip_utf8_check 作用域: SESSION | GLOBAL默认值: 0这个变量用来设置是否跳过 UTF-8 字符的验证。 验证 UTF-8 字符需要消耗一定的性能,当可以确认输入的字符串为有效的 UTF-8 字符时,可以将其设置为 1。tidb_batch_insert 作用域: SESSION默认值: 0这个变量用来设置是否自动切分插入数据。仅在 autocommit 开启时有效。 当插入大量数据时,可以将其设置为 true,这样插入数据会被自动切分为多个 batch,每个 batch 使用一个单独的事务进行插入。tidb_batch_delete 作用域: SESSION默认值: 0这个变量用来设置是否自动切分待删除的数据。仅在 autocommit 开启时有效。 当删除大量数据时,可以将其设置为 true,这样待删除数据会被自动切分为多个 batch,每个 batch 使用一个单独的事务进行删除。tidb_dml_batch_size 作用域: SESSION默认值: 20000这个变量用来设置自动切分插入/待删除数据的的 batch 大小。仅在 tidb_batch_insert 或 tidb_batch_delete 开启时有效。 需要注意的是,当单行总数据大小很大时,20k 行总数据量数据会超过单个事务大小限制。因此在这种情况下,用户应当将其设置为一个较小的值。tidb_max_chunk_size 作用域: SESSION | GLOBAL默认值: 1024这个变量用来设置执行过程中一个 chunk 最大的行数。tidb_mem_quota_query 作用域:SESSION默认值:32 GB这个变量用来设置一条查询语句的内存使用阈值。 如果一条查询语句执行过程中使用的内存空间超过该阈值,会触发 TiDB 启动配置文件中 OOMAction 项所指定的行为。tidb_mem_quota_hashjoin 作用域:SESSION默认值:32 GB这个变量用来设置 HashJoin 算子的内存使用阈值。 如果 HashJoin 算子执行过程中使用的内存空间超过该阈值,会触发 TiDB 启动配置文件中 OOMAction 项所指定的行为。tidb_mem_quota_mergejoin 作用域:SESSION默认值:32 GB这个变量用来设置 MergeJoin 算子的内存使用阈值。 如果 MergeJoin 算子执行过程中使用的内存空间超过该阈值,会触发 TiDB 启动配置文件中 OOMAction 项所指定的行为。tidb_mem_quota_sort 作用域:SESSION默认值:32 GB这个变量用来设置 Sort 算子的内存使用阈值。 如果 Sort 算子执行过程中使用的内存空间超过该阈值,会触发 TiDB 启动配置文件中 OOMAction 项所指定的行为。tidb_mem_quota_topn 作用域:SESSION默认值:32 GB这个变量用来设置 TopN 算子的内存使用阈值。 如果 TopN 算子执行过程中使用的内存空间超过该阈值,会触发 TiDB 启动配置文件中 OOMAction 项所指定的行为。tidb_mem_quota_indexlookupreader 作用域:SESSION默认值:32 GB这个变量用来设置 IndexLookupReader 算子的内存使用阈值。如果 IndexLookupReader 算子执行过程中使用的内存空间超过该阈值,会触发 TiDB 启动配置文件中 OOMAction 项所指定的行为。tidb_mem_quota_indexlookupjoin 作用域:SESSION默认值:32 GB这个变量用来设置 IndexLookupJoin 算子的内存使用阈值。 如果 IndexLookupJoin 算子执行过程中使用的内存空间超过该阈值,会触发 TiDB 启动配置文件中 OOMAction 项所指定的行为。tidb_mem_quota_nestedloopapply 作用域:SESSION默认值:32 GB这个变量用来设置 NestedLoopApply 算子的内存使用阈值。 如果 NestedLoopApply 算子执行过程中使用的内存空间超过该阈值,会触发 TiDB 启动配置文件中 OOMAction 项所指定的行为。tidb_general_log 作用域:SERVER默认值:0这个变量用来设置是否在日志里记录所有的 SQL 语句。tidb_enable_streaming 作用域:SESSION默认值:0这个变量用来设置是否启用 Streaming。tidb_retry_limit 作用域:SESSION | GLOBAL默认值:10这个变量用来设置最多可重试次数, 即在一个事务执行中遇到可重试的错误(例如事务冲突、TiKV 繁忙等)时,这个事务可以被重新执行,这个变量值表明最多可重试的次数。tidb_disable_txn_auto_retry 作用域:SESSION | GLOBAL默认值:0这个变量用来设置是否禁用显式事务自动重试,设置为 1 时,不会自动重试,如果遇到冲突需要在应用层重试。 是否需要禁用自动重试,请参考自动重试的风险tidb_enable_table_partition 作用域:SESSION默认值:0这个变量用来设置是否开启 TABLE PARTITION 特性。tidb_backoff_lock_fast 作用域:SESSION | GLOBAL默认值:100这个变量用来设置读请求遇到锁的 backoff 时间。tidb_ddl_reorg_worker_cnt 作用域: SESSION | GLOBAL默认值:16这个变量用来设置 DDL 操作 re-organize 阶段的并发度。tidb_ddl_reorg_priority 作用域:SESSION | GLOBAL默认值:PRIORITY_LOW这个变量用来设置 ADD INDEX 操作 re-organize 阶段的执行优先级,可设置为 PRIORITY_LOW/PRIORITY_NORMAL/PRIORITY_HIGH。tidb_force_priority 作用域:SESSION默认值:NO_PRIORITY这个变量用于改变 TiDB server 上执行的语句的默认优先级。例如,你可以通过设置该变量来确保正在执行 OLAP 查询的用户优先级低于正在执行 OLTP 查询的用户。可设置为 NO_PRIORITY、LOW_PRIORITY、DELAYED 或 HIGH_PRIORITY。Optimizer Hints TiDB 支持 Optimizer Hints 语法,它基于 MySQL 5.7 中介绍的类似 comment 的语法,例如 /*+ TIDB_XX(t1, t2) */。当 TiDB 优化器选择的不是最优查询计划时,建议使用 Optimizer Hints。 注意:MySQL 命令行客户端在 5.7.7 版本之前默认清除了 Optimizer Hints。如果需要在这些早期版本的客户端中使用 Hint 语法,需要在启动客户端时加上 --comments 选项,例如 mysql -h 127.0.0.1 -P 4000 -uroot --comments。 TIDB_SMJ(t1, t2) SELECT /*+ TIDB_SMJ(t1, t2) */ * from t1,t2 where t1.id = t2.id 提示优化器使用 Sort Merge Join 算法,这个算法通常会占用更少的内存,但执行时间会更久。 当数据量太大,或系统内存不足时,建议尝试使用。TIDB_INLJ(t1, t2) SELECT /*+ TIDB_INLJ(t1, t2) */ * from t1,t2 where t1.id = t2.id 提示优化器使用 Index Nested Loop Join 算法,这个算法可能会在某些场景更快,消耗更少系统资源,有的场景会更慢,消耗更多系统资源。对于外表经过 WHERE 条件过滤后结果集较小(小于 1 万行)的场景,可以尝试使用。TIDB_INLJ() 中的参数是建立查询计划时,内表的候选表。即 TIDB_INLJ(t1) 只会考虑使用 t1 作为内表构建查询计划。TIDB_HJ(t1, t2) SELECT /*+ TIDB_HJ(t1, t2) */ * from t1,t2 where t1.id = t2.id 提示优化器使用 Hash Join 算法,这个算法多线程并发执行,执行速度较快,但会消耗较多内存。SHARD_ROW_ID_BITS 对于 PK 非整数或没有 PK 的表,TiDB 会使用一个隐式的自增 rowid,大量 INSERT 时会把数据集中写入单个 Region,造成写入热点。通过设置 SHARD_ROW_ID_BITS,可以把 rowid 打散写入多个不同的 Region,缓解写入热点问题。但是设置的过大会造成 RPC 请求数放大,增加 CPU 和网络开销。 SHARD_ROW_ID_BITS = 4 表示 16 个分片 SHARD_ROW_ID_BITS = 6 表示 64 个分片 SHARD_ROW_ID_BITS = 0 表示默认值 1 个分片 语句示例: CREATE TABLE:CREATE TABLE t (c int) SHARD_ROW_ID_BITS = 4; ALTER TABLE:ALTER TABLE t SHARD_ROW_ID_BITS = 4; tidb_slow_log_threshold 作用域:SESSION默认值:300输出慢日志的耗时阈值。当查询大于这个值,就会当做是一个慢查询,输出到慢查询日志。默认为 300ms。示例:set tidb_slow_log_threshold = 200 tidb_query_log_max_len 作用域:SESSION默认值:2048 (bytes)最长的 SQL 输出长度。当语句的长度大于 query-log-max-len,将会被截断输出。示例:set tidb_query_log_max_len = 20"}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/tidb-specific/", "title": "TiDB 专用系统变量和语法", "content": " TiDB 专用系统变量和语法 TiDB 在 MySQL 的基础上,定义了一些专用的系统变量和语法用来优化性能。System Variable 变量可以通过 SET 语句设置,例如set @@tidb_distsql_scan_concurrency = 10 如果需要设值全局变量,执行set @@global.tidb_distsql_scan_concurrency = 10 tidb_distsql_scan_concurrency 作用域: SESSION | GLOBAL默认值: 10这个变量用来设置 scan 操作的并发度,AP 类应用适合较大的值,TP 类应用适合较小的值。 对于 AP 类应用,最大值建议不要超过所有 TiKV 节点的 CPU 核数。tidb_index_lookup_size 作用域: SESSION | GLOBAL默认值: 20000这个变量用来设置 index lookup 操作的 batch 大小,AP 类应用适合较大的值,TP 类应用适合较小的值。tidb_index_lookup_concurrency 作用域: SESSION | GLOBAL默认值: 4这个变量用来设置 index lookup 操作的并发度,AP 类应用适合较大的值,TP 类应用适合较小的值。tidb_index_serial_scan_concurrency 作用域:SESSION | GLOBAL默认值:1这个变量用来设置顺序 scan 操作的并发度,AP 类应用适合较大的值,TP 类应用适合较小的值。tidb_index_join_batch_size 作用域:SESSION | GLOBAL默认值:25000这个变量用来设置 index lookup join 操作的 batch 大小,AP 类应用适合较大的值,TP 类应用适合较小的值。tidb_max_row_count_for_inlj 作用域:SESSION | GLOBAL默认值:128这个变量用来设置安全启用 Index Nested Loop Join 算法的外表大小。 如果外表行数大于这个值,只有使用 hint 语法才会启用 Index Nested Loop Join 算法。Optimizer Hint TiDB 在 MySQL 的 Optimizer Hint 语法上,增加了一些 TiDB 专有的 Hint 语法, 使用这些 Hint 的时候,TiDB 优化器会尽量使用指定的算法,在某些场景下会比默认算法更优。由于 hint 包含在类似 /*+ xxx */ 的 comment 里,MySQL 客户端在 5.7.7 之前,会默认把 comment 清除掉,如果需要在旧的客户端使用 hint,需要在启动客户端时加上 --comments 选项,例如 mysql -h 127.0.0.1 -P 4000 -uroot --commentsTIDB_SMJ(t1, t2) SELECT /*+ TIDB_SMJ(t1, t2) */ * from t1,t2 where t1.id = t2.id 提示优化器使用 Sort Merge Join 算法,这个算法通常会占用更少的内存,但执行时间会更久。 当数据量太大,或系统内存不足时,建议尝试使用。TIDB_INLJ(t1, t2) SELECT /*+ TIDB_INLJ(t1, t2) */ * from t1,t2 where t1.id = t2.id 提示优化器使用 Index Nested Loop Join 算法,这个算法可能会在某些场景更快,消耗更少系统资源,有的场景会更慢,消耗更多系统资源。对于外表经过 WHERE 条件过滤后结果集较小(小于 1 万行)的场景,可以尝试使用。TIDB_INLJ()中的参数是建立查询计划时,驱动表(外表)的候选表。即TIDB_INLJ(t1)只会考虑使用t1作为驱动表构建查询计划。"}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/tidb-specific/", "title": "TiDB 专用系统变量和语法", "content": " TiDB 专用系统变量和语法 TiDB 在 MySQL 的基础上,定义了一些专用的系统变量和语法用来优化性能。System Variable 变量可以通过 SET 语句设置,例如set @@tidb_distsql_scan_concurrency = 10 如果需要设值全局变量,执行set @@global.tidb_distsql_scan_concurrency = 10 tidb_distsql_scan_concurrency 作用域: SESSION | GLOBAL默认值: 10这个变量用来设置 scan 操作的并发度,AP 类应用适合较大的值,TP 类应用适合较小的值。 对于 AP 类应用,最大值建议不要超过所有 TiKV 节点的 CPU 核数。tidb_index_lookup_size 作用域: SESSION | GLOBAL默认值: 20000这个变量用来设置 index lookup 操作的 batch 大小,AP 类应用适合较大的值,TP 类应用适合较小的值。tidb_index_lookup_concurrency 作用域: SESSION | GLOBAL默认值: 4这个变量用来设置 index lookup 操作的并发度,AP 类应用适合较大的值,TP 类应用适合较小的值。tidb_index_serial_scan_concurrency 作用域:SESSION | GLOBAL默认值:1这个变量用来设置顺序 scan 操作的并发度,AP 类应用适合较大的值,TP 类应用适合较小的值。tidb_index_join_batch_size 作用域:SESSION | GLOBAL默认值:25000这个变量用来设置 index lookup join 操作的 batch 大小,AP 类应用适合较大的值,TP 类应用适合较小的值。tidb_max_row_count_for_inlj 作用域:SESSION | GLOBAL默认值:128这个变量用来设置安全启用 Index Nested Loop Join 算法的外表大小。 如果外表行数大于这个值,只有使用 hint 语法才会启用 Index Nested Loop Join 算法。Optimizer Hint TiDB 在 MySQL 的 Optimizer Hint 语法上,增加了一些 TiDB 专有的 Hint 语法, 使用这些 Hint 的时候,TiDB 优化器会尽量使用指定的算法,在某些场景下会比默认算法更优。由于 hint 包含在类似 /*+ xxx */ 的 comment 里,MySQL 客户端在 5.7.7 之前,会默认把 comment 清除掉,如果需要在旧的客户端使用 hint,需要在启动客户端时加上 --comments 选项,例如 mysql -h 127.0.0.1 -P 4000 -uroot --commentsTIDB_SMJ(t1, t2) SELECT /*+ TIDB_SMJ(t1, t2) */ * from t1,t2 where t1.id = t2.id 提示优化器使用 Sort Merge Join 算法,这个算法通常会占用更少的内存,但执行时间会更久。 当数据量太大,或系统内存不足时,建议尝试使用。TIDB_INLJ(t1, t2) SELECT /*+ TIDB_INLJ(t1, t2) */ * from t1,t2 where t1.id = t2.id 提示优化器使用 Index Nested Loop Join 算法,这个算法可能会在某些场景更快,消耗更少系统资源,有的场景会更慢,消耗更多系统资源。对于外表经过 WHERE 条件过滤后结果集较小(小于 1 万行)的场景,可以尝试使用。TIDB_INLJ()中的参数是建立查询计划时,驱动表(外表)的候选表。即TIDB_INLJ(t1)只会考虑使用t1作为驱动表构建查询计划。"}, {"url": "https://pingcap.com/docs-cn/sql/transaction/", "title": "TiDB 事务语句", "content": " TiDB 事务语句 TiDB 支持分布式事务。涉及到事务的语句包括 Autocommit 变量、 START TRANSACTION/BEGIN、 COMMIT 以及 ROLLBACK。自动提交 语法:SET autocommit = {0 | 1} 通过设置 autocommit 的值为 1,可以将当前 Session 设置为自动提交状态,0 则表示当前 Session 为非自动提交状态。默认情况下,autocommit 的值为 1。在自动提交状态,每条语句运行后,会将其修改自动提交到数据库中。否则,会等到运行 COMMIT 语句或者是 BEGIN 语句的时候,才会将之前的修改提交到数据库。另外 autocommit 也是一个 System Variable,所以可以通过变量赋值语句修改当前 Session 或者是 Global 的值。SET @@SESSION.autocommit = {0 | 1}; SET @@GLOBAL.autocommit = {0 | 1}; START TRANSACTION, Begin 语法:BEGIN; START TRANSACTION; START TRANSACTION WITH CONSISTENT SNAPSHOT; 上述三条语句都是事务开始语句,效果相同。通过事务开始语句可以显式地开始一个新的事务,如果这个时候当前 Session 正在一个事务中间过程中,会将当前事务提交后,开启一个新的事务。COMMIT 语法:COMMIT; 提交当前事务,包括从 BEGIN 到 COMMIT 之间的所有修改。ROLLBACK 语法:ROLLBACK; 回滚当前事务,撤销从 BEGIN 到 ROLLBACK 之间的所有修改。显式事务和隐式事务 TiDB 可以显式地使用事务(BEGIN/COMMIT)或者隐式的使用事务(SET autocommit = 1)。如果在 autocmmit = 1 的状态下,通过 BEGIN 语句开启一个新的事务,那么在 COMMIT/ROLLBACK 之前,会禁用 autocommit,也就是变成显式事务。对于 DDL 语句,会自动提交并且不能回滚。如果运行 DDL 的时候,正在一个事务的中间过程中,会先将当前的事务提交,再运行 DDL。事务隔离级别 TiDB 默认使用 SNAPSHOT ISOLATION,可以通过下面的语句将当前 Session 的隔离级别设置为 READ COMMITTED。SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;"}, {"url": "https://pingcap.com/docs-cn/sql/transaction-isolation/", "title": "TiDB 事务隔离级别", "content": " TiDB 事务隔离级别 事务隔离级别是数据库事务处理的基础,ACID 中 I,即 Isolation,指的就是事务的隔离性。sql 92标准定义了4种隔离级别,读未提交、读已提交、可重复读、串行化,见下表。 Isolation Level Dirty Read Nonrepeatable Read Phantom Read Serialization Anomaly Read uncommitted Possible Possible Possible Possible Read committed Not possible Possible Possible Possible Repeatable read Not possible Not possible Not possible in TiDB Possible Serializable Not possible Not possible Not possible Not possible TiDB 实现了其中的可重复读。TiDB 使用 Percolator 事务模型,当事务启动时会获取全局读时间戳,事务提交时也会获取全局提交时间戳,并以此确定事务的执行顺序,如果想了解 TiDB 事务模型的实现可以详细阅读以下两篇文章:TiKV 的 MVCC (Multi-Version Concurrency Control) 机制,Percolator 和 TiDB 事务算法。可重复读 当事务隔离级别为可重复读时,只能读到该事务启动时已经提交的其他事务修改的数据,未提交的数据或在事务启动后其他事务提交的数据是不可见的。对于本事务而言,事务语句可以看到之前的语句做出的修改。对于运行于不同节点的事务而言,不同事务启动和提交的顺序取决于从 PD 获取时间戳的顺序。处于可重复读隔离级别的事务不能并发的更新同一行,当时事务提交时发现该行在该事务启动后,已经被另一个已提交的事务更新过,那么该事务会回滚并启动自动重试。示例如下:create table t1(id int); insert into t1 values(0); start transaction; | start transaction; select * from t1; | select * from t1; update t1 set id=id+1; | update t1 set id=id+1; commit; | | commit; --回滚并自动重试 与 ANSI 可重复读隔离级别的区别 尽管名称是可重复读隔离级别,但是 TiDB 中可重复读隔离级别和 ANSI 可重复隔离级别是不同的,按照 A Critique of ANSI SQL Isolation Levels 论文中的标准,TiDB 实现的是论文中的 snapshot 隔离级别,该隔离级别不会出现幻读,但是会出现写偏斜,而 ANSI 可重复读隔离级别不会出现写偏斜,会出现幻读。与MySQL可重复读隔离级别的区别 MySQL 可重复读隔离级别在更新时并不检验当前版本是否可见,也就是说,即使该行在事务启动后被更新过,同样可以继续更新。这种情况在 TiDB 会导致事务回滚并后台重试,重试最终可能会失败,导致事务最终失败,而 MySQL 是可以更新成功的。 MySQL 的可重复读隔离级别并非 snapshot 隔离级别,MySQL 可重复读隔离级别的一致性要弱于 snapshot 隔离级别,也弱于 TiDB 的可重复读隔离级别。事务重试 对于 insert/delete/update 操作,如果事务执行失败,并且系统判断该错误为可重试,会在系统内部自动重试事务。通过配置参数 retry-limit 可控制自动重试的次数:[performance] ... # The maximum number of retries when commit a transaction. retry-limit = 10 乐观事务注意事项 因为 TiDB 使用乐观锁机制,通过显式的 BEGIN 语句创建的事务,在遇到冲突后自动重试可能会导致最终结果不符合预期。比如下面这两个例子: Session1 Session2 begin; begin; select balance from t where id = 1; update t set balance = balance -100 where id = 1; update t set balance = balance -100 where id = 2; // 使用 select 的结果决定后续的逻辑 commit; if balance > 100 { update t set balance = balance + 100 where id = 2; } commit; // 自动重试 Session1 Session2 begin; begin; update t set balance = balance - 100 where id = 1; delete t where id = 1; commit; // 使用 affected_rows 的结果决定后续的逻辑 if affected_rows > 100 { update t set balance = balance + 100 where id = 2; } commit; // 自动重试 因为 TiDB 自动重试机制会把事务第一次执行的所有语句重新执行一遍,当一个事务里的后续 语句是否执行取决于前面语句执行结果的时候,自动重试无法保证最终结果符合预期。 这种情况下,需要在应用层重试整个事务。通过配置全局变量 tidb_disable_txn_auto_retry 可以关掉显式事务的重试。set @@global.tidb_disable_txn_auto_retry = 1; 这个变量不会影响 auto_commit = 1 的单语句的隐式事务,仍然会自动重试。关掉显示事务重试后,如果出现事务冲突,commit 语句会返回错误,错误信息会包含 try again later 这个字符串,应用层可以用来判断遇到的错误是否是可以重试的。如果事务执行过程中包含了应用层的逻辑,建议在应用层添加显式事务的重试,并关闭自动重试。语句回滚 在事务内部执行一个语句,遇到错误时,该语句不会生效。begin; insert into test values (1); insert into tset values (2); // tset 拼写错了,这条语句出错。 insert into test values (3); commit; 上面的例子里面,第二个语句失败,其它插入 1 和 3 仍然能正常提交。begin; insert into test values (1); insert into tset values (2); // tset 拼写错了,这条语句出错。 insert into test values (3); rollback; 这个例子中,第二个语句失败,最后由于调用了 rollback,事务不会将任何数据写入数据库。"}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/transaction-isolation/", "title": "TiDB 事务隔离级别", "content": " TiDB 事务隔离级别 事务隔离级别是数据库事务处理的基础,ACID 中 I,即 Isolation,指的就是事务的隔离性。sql 92标准定义了4种隔离级别,读未提交、读已提交、可重复读、串行化,见下表。 Isolation Level Dirty Read Nonrepeatable Read Phantom Read Serialization Anomaly Read uncommitted Possible Possible Possible Possible Read committed Not possible Possible Possible Possible Repeatable read Not possible Not possible Not possible in TiDB Possible Serializable Not possible Not possible Not possible Not possible TiDB 实现了其中的两种:读已提交和可重复读。TiDB 使用percolator事务模型,当事务启动时会获取全局读时间戳,事务提交时也会获取全局提交时间戳,并以此确定事务的执行顺序,如果想了解 TiDB 事务模型的实现可以详细阅读以下两篇文章:TiKV 的 MVCC(Multi-Version Concurrency Control)机制,Percolator 和 TiDB 事务算法。可以通过以下命令设置事务的隔离级别:SET SESSION TRANSACTION ISOLATION LEVEL [read committed|repeatable read]可重复读 可重复读是 TiDB 的默认隔离级别,当事务隔离级别为可重复读时,只能读到该事务启动时已经提交的其他事务修改的数据,未提交的数据或在事务启动后其他事务提交的数据是不可见的。对于本事务而言,事务语句可以看到之前的语句做出的修改。对于运行于不同节点的事务而言,不同事务启动和提交的顺序取决于从 PD 获取时间戳的顺序。处于可重复读隔离级别的事务不能并发的更新同一行,当时事务提交时发现该行在该事务启动后,已经被另一个已提交的事务更新过,那么该事务会回滚并启动自动重试。示例如下:create table t1(id int); insert into t1 values(0); start transaction; | start transaction; select * from t1; | select * from t1; update t1 set id=id+1; | update t1 set id=id+1; commit; | | commit; --回滚并自动重试 与 ANSI 可重复读隔离级别的区别 尽管名称是可重复读隔离级别,但是 TiDB 中可重复读隔离级别和 ANSI 可重复隔离级别是不同的,按照A Critique of ANSI SQL Isolation Levels论文中的标准,TiDB 实现的是论文中的 snapshot 隔离级别,该隔离级别不会出现幻读,但是会出现写偏斜,而 ANSI 可重复读隔离级别不会出现写偏斜,会出现幻读。与MySQL可重复读隔离级别的区别 MySQL 可重复读隔离级别在更新时并不检验当前版本是否可见,也就是说,即使该行在事务启动后被更新过,同样可以继续更新。这种情况在 TiDB 会导致事务回滚并后台重试,重试最终可能会失败,导致事务最终失败,而 MySQL 是可以更新成功的。 MySQL 的可重复读隔离级别并非 snapshot 隔离级别,MySQL 可重复读隔离级别的一致性要弱于 snapshot 隔离级别,也弱于 TiDB 的可重复读隔离级别。读已提交 读已提交隔离级别和可重复读隔离级别不同,它仅仅保证不能读到未提交事务的数据,需要注意的是,事务提交是一个动态的过程,因此读已提交隔离级别可能读到某个事务部分提交的数据。不推荐在有严格一致要求的数据库中使用读已提交隔离级别。事务重试 对于 insert/delete/update 操作,如果事务执行失败,并且系统判断该错误为可重试,会在系统内部自动重试事务。通过配置参数 retry-limit 可控制自动重试的次数:[performance] ... # The maximum number of retries when commit a transaction. retry-limit = 10"}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/transaction-isolation/", "title": "TiDB 事务隔离级别", "content": " TiDB 事务隔离级别 事务隔离级别是数据库事务处理的基础,ACID 中 I,即 Isolation,指的就是事务的隔离性。sql 92标准定义了4种隔离级别,读未提交、读已提交、可重复读、串行化,见下表。 Isolation Level Dirty Read Nonrepeatable Read Phantom Read Serialization Anomaly Read uncommitted Possible Possible Possible Possible Read committed Not possible Possible Possible Possible Repeatable read Not possible Not possible Not possible in TiDB Possible Serializable Not possible Not possible Not possible Not possible TiDB 实现了其中的两种:读已提交和可重复读。TiDB 使用percolator事务模型,当事务启动时会获取全局读时间戳,事务提交时也会获取全局提交时间戳,并以此确定事务的执行顺序,如果想了解 TiDB 事务模型的实现可以详细阅读以下两篇文章:TiKV 的 MVCC(Multi-Version Concurrency Control)机制,Percolator 和 TiDB 事务算法。可以通过以下命令设置事务的隔离级别:SET SESSION TRANSACTION ISOLATION LEVEL [read committed|repeatable read]可重复读 可重复读是 TiDB 的默认隔离级别,当事务隔离级别为可重复读时,只能读到该事务启动时已经提交的其他事务修改的数据,未提交的数据或在事务启动后其他事务提交的数据是不可见的。对于本事务而言,事务语句可以看到之前的语句做出的修改。对于运行于不同节点的事务而言,不同事务启动和提交的顺序取决于从 PD 获取时间戳的顺序。处于可重复读隔离级别的事务不能并发的更新同一行,当时事务提交时发现该行在该事务启动后,已经被另一个已提交的事务更新过,那么该事务会回滚并启动自动重试。示例如下:create table t1(id int); insert into t1 values(0); start transaction; | start transaction; select * from t1; | select * from t1; update t1 set id=id+1; | update t1 set id=id+1; commit; | | commit; --回滚并自动重试 与 ANSI 可重复读隔离级别的区别 尽管名称是可重复读隔离级别,但是 TiDB 中可重复读隔离级别和 ANSI 可重复隔离级别是不同的,按照A Critique of ANSI SQL Isolation Levels论文中的标准,TiDB 实现的是论文中的 snapshot 隔离级别,该隔离级别不会出现幻读,但是会出现写偏斜,而 ANSI 可重复读隔离级别不会出现写偏斜,会出现幻读。与MySQL可重复读隔离级别的区别 MySQL 可重复读隔离级别在更新时并不检验当前版本是否可见,也就是说,即使该行在事务启动后被更新过,同样可以继续更新。这种情况在 TiDB 会导致事务回滚并后台重试,重试最终可能会失败,导致事务最终失败,而 MySQL 是可以更新成功的。 MySQL 的可重复读隔离级别并非 snapshot 隔离级别,MySQL 可重复读隔离级别的一致性要弱于 snapshot 隔离级别,也弱于 TiDB 的可重复读隔离级别。读已提交 读已提交隔离级别和可重复读隔离级别不同,它仅仅保证不能读到未提交事务的数据,需要注意的是,事务提交是一个动态的过程,因此读已提交隔离级别可能读到某个事务部分提交的数据。不推荐在有严格一致要求的数据库中使用读已提交隔离级别。事务重试 对于 insert/delete/update 操作,如果事务执行失败,并且系统判断该错误为可重试,会在系统内部自动重试事务。通过配置参数 retry-limit 可控制自动重试的次数:[performance] ... # The maximum number of retries when commit a transaction. retry-limit = 10"}, {"url": "https://pingcap.com/recruit-cn/engineering/product-manager/", "title": "TiDB 产品经理", "content": " TiDB 产品经理 岗位职责: 负责 TiDB、TiSpark、数据库管理平台等某个产品线的产品规划与设计,对产品交付负责; 负责跟踪业界动态,市场需求,竞品分析等,设计数据库产品功能,对产品竞争力负责; 负责产品生命周期管理,对产品的用户体验和质量负责; 负责协调后端资源并推进达成产品目标; 负责向销售、售前、售后团队提供产品方案、培训和咨询等支持,辅助销售、售前、售后团队完成商业目标。 任职要求: 善于沟通,做事认真、细致、逻辑性强,有责任心和团队合作精神,具备优秀的学习能力和创新能力; 熟悉 1 种以上关系型或 NoSQL 数据库,了解市场上主流的数据库产品; 有一定的项目管理经验,熟悉常见的项目管理工具、流程; 有较强的数据分析能力,较好的逻辑思维能力和理解能力,思维活跃,有创新精神; 有数据库产品或其他技术型产品经验优先,有数据库内核研发、运维、DBA 经验优先; 有分布式系统存储、分布式缓存、分布式系统研发经验优先; 有 Google Spanner/F1、Amazon Aurora 等业界 NewSQL 有较深刻的理解优先; 为 TiDB 相关的开源项目做出贡献者优先; 具备一定的开发能力优先,语言不限。 待遇:25K - 50K + 期权,13薪 + 奖金,优秀者可面议联系方式:hire@pingcap.com工作地点:北京,上海,广州,杭州,成都,深圳"}, {"url": "https://pingcap.com/docs-cn/sql/tidb-memory-control/", "title": "TiDB 内存控制文档", "content": " TiDB 内存控制文档 目前 TiDB 已经能够做到追踪单条 SQL 查询过程中的内存使用情况,当内存使用超过一定阈值后也能采取一些操作来预防 OOM 或者排查 OOM 原因。在 TiDB 的配置文件中,我们可以使用如下配置来控制内存使用超阈值时 TiDB 的行为:# Valid options: ["log", "cancel"] oom-action = "log" 如果上面的配置项使用的是 “log”,那么当一条 SQL 的内存使用超过一定阈值(由 session 变量 tidb_mem_quota_query 来控制)后,TiDB 会在 log 文件中打印一条 LOG,然后这条 SQL 继续执行,之后如果发生了 OOM 可以在 LOG 中找到对应的 SQL。 如果上面的配置项使用的是 “cancel”,那么当一条 SQL 的内存使用超过一定阈值后,TiDB 会立即中断这条 SQL 的执行并给客户端返回一个 error,error 信息中会详细写明这条 SQL 执行过程中各个占用内存比较多的物理执行算子的内存使用情况。 如何配置一条 SQL 执行过程中的内存使用阈值 可以在配置文件中设置每个 Query 默认的 Memory Quota,例如将其设置为 32GB:mem-quota-query = 34359738368 此外还可通过如下几个 session 变量来控制一条 Query 中的内存使用,大多数用户只需要设置 tidb_mem_quota_query 即可,其他变量是高级配置,大多数用户不需要关心: 变量名 作用 单位 默认值 tidb_mem_quota_query 配置整条 SQL 的内存使用阈值 Byte 32 << 30 tidb_mem_quota_hashjoin 配置 Hash Join 的内存使用阈值 Byte 32 << 30 tidb_mem_quota_mergejoin 配置 Merge Join 的内存使用阈值 Byte 32 << 30 tidb_mem_quota_sort 配置 Sort 的内存使用阈值 Byte 32 << 30 tidb_mem_quota_topn 配置 TopN 的内存使用阈值 Byte 32 << 30 tidb_mem_quota_indexlookupreader 配置 Index Lookup Reader 的内存使用阈值 Byte 32 << 30 tidb_mem_quota_indexlookupjoin 配置 Index Lookup Join 的内存使用阈值 Byte 32 << 30 tidb_mem_quota_nestedloopapply 配置 Nested Loop Apply 的内存使用阈值 Byte 32 << 30 几个使用例子:-- 配置整条 SQL 的内存使用阈值为 8GB: set @@tidb_mem_quota_query = 8 << 30; -- 配置整条 SQL 的内存使用阈值为 8MB: set @@tidb_mem_quota_query = 8 << 20; -- 配置整条 SQL 的内存使用阈值为 8KB: set @@tidb_mem_quota_query = 8 << 10;"}, {"url": "https://pingcap.com/docs-cn/op-guide/history-read/", "title": "TiDB 历史数据回溯", "content": " TiDB 历史数据回溯 本文档用于描述 TiDB 如何读取历史版本数据,包括具体的操作流程以及历史数据的保存策略。功能说明 TiDB 实现了通过标准 SQL 接口读取历史数据功能,无需特殊的 client 或者 driver。当数据被更新、删除后,依然可以通过 SQL 接口将更新/删除前的数据读取出来。另外即使在更新数据之后,表结构发生了变化,TiDB 依旧能用旧的表结构将数据读取出来。操作流程 为支持读取历史版本数据, 引入了一个新的 system variable: tidb_snapshot ,这个变量是 Session 范围有效,可以通过标准的 Set 语句修改其值。其值为文本,能够存储 TSO 和日期时间。TSO 即是全局授时的时间戳,是从 PD 端获取的; 日期时间的格式可以为: “2016-10-08 16:45:26.999”,一般来说可以只写到秒,比如”2016-10-08 16:45:26”。 当这个变量被设置时,TiDB 会用这个时间戳建立 Snapshot(没有开销,只是创建数据结构),随后所有的 Select 操作都会在这个 Snapshot 上读取数据。 注意:TiDB 的事务是通过 PD 进行全局授时,所以存储的数据版本也是以 PD 所授时间戳作为版本号。在生成 Snapshot 时,是以 tidb_snapshot 变量的值作为版本号,如果 TiDB Server 所在机器和 PD Server 所在机器的本地时间相差较大,需要以 PD 的时间为准。 当读取历史版本操作结束后,可以结束当前 Session 或者是通过 Set 语句将 tidb_snapshot 变量的值设为 ““,即可读取最新版本的数据。历史数据保留策略 TiDB 使用 MVCC 管理版本,当更新/删除数据时,不会做真正的数据删除,只会添加一个新版本数据,所以可以保留历史数据。历史数据不会全部保留,超过一定时间的历史数据会被彻底删除,以减小空间占用以及避免历史版本过多引入的性能开销。TiDB 使用周期性运行的 GC(Garbage Collection,垃圾回收)来进行清理,关于 GC 的详细介绍参见 TiDB 垃圾回收 (GC)。这里需要重点关注的是 tikv_gc_life_time 和 tikv_gc_safe_point 这条。tikv_gc_life_time 用于配置历史版本保留时间,可以手动修改;tikv_gc_safe_point 记录了当前的 safePoint,用户可以安全地使用大于 safePoint 的时间戳创建 snapshot 读取历史版本。safePoint 在每次 GC 开始运行时自动更新。示例 初始化阶段,创建一个表,并插入几行数据:mysql> create table t (c int); Query OK, 0 rows affected (0.01 sec) mysql> insert into t values (1), (2), (3); Query OK, 3 rows affected (0.00 sec) 查看表中的数据:mysql> select * from t; +------+ | c | +------+ | 1 | | 2 | | 3 | +------+ 3 rows in set (0.00 sec) 查看当前时间:mysql> select now(); +---------------------+ | now() | +---------------------+ | 2016-10-08 16:45:26 | +---------------------+ 1 row in set (0.00 sec) 更新某一行数据:mysql> update t set c=22 where c=2; Query OK, 1 row affected (0.00 sec) 确认数据已经被更新:mysql> select * from t; +------+ | c | +------+ | 1 | | 22 | | 3 | +------+ 3 rows in set (0.00 sec) 设置一个特殊的环境变量,这个是一个 session scope 的变量,其意义为读取这个时间之前的最新的一个版本。mysql> set @@tidb_snapshot="2016-10-08 16:45:26"; Query OK, 0 rows affected (0.00 sec) 注意: 这里的时间设置的是 update 语句之前的那个时间。 在 tidb_snapshot 前须使用 @@ 而非 @,因为 @@ 表示系统变量,@ 表示用户变量。 这里读取到的内容即为 update 之前的内容,也就是历史版本:mysql> select * from t; +------+ | c | +------+ | 1 | | 2 | | 3 | +------+ 3 rows in set (0.00 sec) 清空这个变量后,即可读取最新版本数据:mysql> set @@tidb_snapshot=""; Query OK, 0 rows affected (0.00 sec)mysql> select * from t; +------+ | c | +------+ | 1 | | 22 | | 3 | +------+ 3 rows in set (0.00 sec) 注意:在 tidb_snapshot 前须使用 @@ 而非 @,因为 @@ 表示系统变量,@ 表示用户变量。 "}, {"url": "https://pingcap.com/docs-cn/v1.0/op-guide/history-read/", "title": "TiDB 历史数据回溯", "content": " TiDB 历史数据回溯 本文档用于描述 TiDB 如何读取历史版本数据,包括具体的操作流程以及历史数据的保存策略。功能说明 TiDB 实现了通过标准 SQL 接口读取历史数据功能,无需特殊的 client 或者 driver。当数据被更新、删除后,依然可以通过 SQL 接口将更新/删除前的数据读取出来。另外即使在更新数据之后,表结构发生了变化,TiDB 依旧能用旧的表结构将数据读取出来。操作流程 为支持读取历史版本数据, 引入了一个新的 system variable: tidb_snapshot ,这个变量是 Session 范围有效,可以通过标准的 Set 语句修改其值。其值为文本,记录了时间,格式为: “2016-10-08 16:45:26.999”,一般来说可以只写到秒,比如”2016-10-08 16:45:26”。 当这个变量被设置时,TiDB 会用这个时间戳建立 Snapshot(没有开销,只是创建数据结构),随后所有的 Select 操作都会在这个 Snapshot 上读取数据。 注意 TiDB 的事务是通过 PD 进行全局授时,所以存储的数据版本也是以 PD 所授时间戳作为版本号。在生成 Snapshot ·时,是以 tidb_snapshot 变量的值作为版本号,如果 TiDB Server 所在机器和 PD Server 所在机器的本地时间相差较大,需要以 PD 的时间为准。 当读取历史版本操作结束后,可以结束当前 Session 或者是通过 Set 语句将 tidb_snapshot 变量的值设为 ”“,即可读取最新版本的数据。历史数据保留策略 TiDB 使用 MVCC 管理版本,当更新/删除数据时,不会做真正的数据删除,只会添加一个新版本数据,所以可以保留历史数据。历史数据不会全部保留,超过一定时间的历史数据会被彻底删除,以减小空间占用以及避免历史版本过多引入的性能开销。我们使用周期性运行的 GC (Garbage Collection, 垃圾回收)来进行清理,GC 的触发方式为:每个 TiDB 启动后会在后台运行一个 gc_worker,每个集群中有一个 gc_worker 会被自动选为 leader,leader 负责维护 GC 的状态并向所有的 TiKV region leader 发送 GC 命令。GC 的运行状态记录记录在 mysql.tidb 系统表中,可通过 SQL 语句进行监测与配置。mysql> select variable_name, variable_value from mysql.tidb; +-----------------------+----------------------------+ | variable_name | variable_value | +-----------------------+----------------------------+ | bootstrapped | True | | tikv_gc_leader_uuid | 55daa0dfc9c0006 | | tikv_gc_leader_desc | host:pingcap-pc5 pid:10549 | | tikv_gc_leader_lease | 20160927-13:18:28 +0800 CST| | tikv_gc_run_interval | 10m0s | | tikv_gc_life_time | 10m0s | | tikv_gc_last_run_time | 20160927-13:13:28 +0800 CST| | tikv_gc_safe_point | 20160927-13:03:28 +0800 CST| +-----------------------+----------------------------+ 7 rows in set (0.00 sec) 其中需要重点关注的是 tikv_gc_life_time 和 tikv_gc_safe_point 这两行。tikv_gc_life_time 用于配置历史版本保留时间(默认值为 10m),用户可以使用 SQL 进行配置。比如我们需要一天内的所有历史版本都可读,那么可以使用 SQL update mysql.tidb set variable_value='24h' where variable_name='tikv_gc_life_time' 将此行设置为 24 小时。时长字符串的形式是数字后接时间单位的序列,如 24h、2h30m、2.5h。可以使用的时间单位包括 “h”、”m”、”s”。tikv_gc_safe_point 记录了当前的 safePoint,用户可以安全地使用大于 safePoint 的时间戳创建 snapshot 读取历史版本。safePoint 在每次 GC 开始运行时自动更新。需要注意的是,在数据更新频繁的场景下如果将 tikv_gc_life_time 设置得比较大(如数天甚至数月),可能会有一些潜在的问题: 随着版本的不断增多,数据占用的磁盘空间会随之增加。 大量的历史版本会在一定程度上导致查询变慢,主要影响范围查询(select count(*) from t)。 如果在运行中突然将 tikv_gc_life_time 配置调小,可能会导致大量历史数据被删除,造成 I/O 负担。 示例 初始化阶段,创建一个表,并插入几行数据:mysql> create table t (c int); Query OK, 0 rows affected (0.01 sec) mysql> insert into t values (1), (2), (3); Query OK, 3 rows affected (0.00 sec) 查看表中的数据:mysql> select * from t; +------+ | c | +------+ | 1 | | 2 | | 3 | +------+ 3 rows in set (0.00 sec) 查看当前时间:mysql> select now(); +---------------------+ | now() | +---------------------+ | 2016-10-08 16:45:26 | +---------------------+ 1 row in set (0.00 sec) 更新某一行数据:mysql> update t set c=22 where c=2; Query OK, 1 row affected (0.00 sec) 确认数据已经被更新:mysql> select * from t; +------+ | c | +------+ | 1 | | 22 | | 3 | +------+ 3 rows in set (0.00 sec) 设置一个特殊的环境变量,这个是一个 session scope 的变量,其意义为读取这个时间之前的最新的一个版本。注意这里的时间设置的是 update 语句之前的那个时间:mysql> set @@tidb_snapshot="2016-10-08 16:45:26"; Query OK, 0 rows affected (0.00 sec) 这里读取到的内容即为 update 之前的内容,也就是历史版本:mysql> select * from t; +------+ | c | +------+ | 1 | | 2 | | 3 | +------+ 3 rows in set (0.00 sec) 清空这个变量后,即可读取最新版本数据:mysql> set @@tidb_snapshot=""; Query OK, 0 rows affected (0.00 sec)mysql> select * from t; +------+ | c | +------+ | 1 | | 22 | | 3 | +------+ 3 rows in set (0.00 sec)"}, {"url": "https://pingcap.com/docs-cn/v2.0/op-guide/history-read/", "title": "TiDB 历史数据回溯", "content": " TiDB 历史数据回溯 本文档用于描述 TiDB 如何读取历史版本数据,包括具体的操作流程以及历史数据的保存策略。功能说明 TiDB 实现了通过标准 SQL 接口读取历史数据功能,无需特殊的 client 或者 driver。当数据被更新、删除后,依然可以通过 SQL 接口将更新/删除前的数据读取出来。另外即使在更新数据之后,表结构发生了变化,TiDB 依旧能用旧的表结构将数据读取出来。操作流程 为支持读取历史版本数据, 引入了一个新的 system variable: tidb_snapshot ,这个变量是 Session 范围有效,可以通过标准的 Set 语句修改其值。其值为文本,记录了时间,格式为: “2016-10-08 16:45:26.999”,一般来说可以只写到秒,比如”2016-10-08 16:45:26”。 当这个变量被设置时,TiDB 会用这个时间戳建立 Snapshot(没有开销,只是创建数据结构),随后所有的 Select 操作都会在这个 Snapshot 上读取数据。 注意 TiDB 的事务是通过 PD 进行全局授时,所以存储的数据版本也是以 PD 所授时间戳作为版本号。在生成 Snapshot ·时,是以 tidb_snapshot 变量的值作为版本号,如果 TiDB Server 所在机器和 PD Server 所在机器的本地时间相差较大,需要以 PD 的时间为准。 当读取历史版本操作结束后,可以结束当前 Session 或者是通过 Set 语句将 tidb_snapshot 变量的值设为 ”“,即可读取最新版本的数据。历史数据保留策略 TiDB 使用 MVCC 管理版本,当更新/删除数据时,不会做真正的数据删除,只会添加一个新版本数据,所以可以保留历史数据。历史数据不会全部保留,超过一定时间的历史数据会被彻底删除,以减小空间占用以及避免历史版本过多引入的性能开销。我们使用周期性运行的 GC (Garbage Collection, 垃圾回收)来进行清理,GC 的触发方式为:每个 TiDB 启动后会在后台运行一个 gc_worker,每个集群中有一个 gc_worker 会被自动选为 leader,leader 负责维护 GC 的状态并向所有的 TiKV region leader 发送 GC 命令。GC 的运行状态记录记录在 mysql.tidb 系统表中,可通过 SQL 语句进行监测与配置。mysql> select variable_name, variable_value from mysql.tidb; +-----------------------+----------------------------+ | variable_name | variable_value | +-----------------------+----------------------------+ | bootstrapped | True | | tikv_gc_leader_uuid | 55daa0dfc9c0006 | | tikv_gc_leader_desc | host:pingcap-pc5 pid:10549 | | tikv_gc_leader_lease | 20160927-13:18:28 +0800 CST| | tikv_gc_run_interval | 10m0s | | tikv_gc_life_time | 10m0s | | tikv_gc_last_run_time | 20160927-13:13:28 +0800 CST| | tikv_gc_safe_point | 20160927-13:03:28 +0800 CST| +-----------------------+----------------------------+ 7 rows in set (0.00 sec) 其中需要重点关注的是 tikv_gc_life_time 和 tikv_gc_safe_point 这两行。tikv_gc_life_time 用于配置历史版本保留时间(默认值为 10m),用户可以使用 SQL 进行配置。比如我们需要一天内的所有历史版本都可读,那么可以使用 SQL update mysql.tidb set variable_value='24h' where variable_name='tikv_gc_life_time' 将此行设置为 24 小时。时长字符串的形式是数字后接时间单位的序列,如 24h、2h30m、2.5h。可以使用的时间单位包括 “h”、”m”、”s”。tikv_gc_safe_point 记录了当前的 safePoint,用户可以安全地使用大于 safePoint 的时间戳创建 snapshot 读取历史版本。safePoint 在每次 GC 开始运行时自动更新。需要注意的是,在数据更新频繁的场景下如果将 tikv_gc_life_time 设置得比较大(如数天甚至数月),可能会有一些潜在的问题: 随着版本的不断增多,数据占用的磁盘空间会随之增加。 大量的历史版本会在一定程度上导致查询变慢,主要影响范围查询(select count(*) from t)。 如果在运行中突然将 tikv_gc_life_time 配置调小,可能会导致大量历史数据被删除,造成 I/O 负担。 示例 初始化阶段,创建一个表,并插入几行数据:mysql> create table t (c int); Query OK, 0 rows affected (0.01 sec) mysql> insert into t values (1), (2), (3); Query OK, 3 rows affected (0.00 sec) 查看表中的数据:mysql> select * from t; +------+ | c | +------+ | 1 | | 2 | | 3 | +------+ 3 rows in set (0.00 sec) 查看当前时间:mysql> select now(); +---------------------+ | now() | +---------------------+ | 2016-10-08 16:45:26 | +---------------------+ 1 row in set (0.00 sec) 更新某一行数据:mysql> update t set c=22 where c=2; Query OK, 1 row affected (0.00 sec) 确认数据已经被更新:mysql> select * from t; +------+ | c | +------+ | 1 | | 22 | | 3 | +------+ 3 rows in set (0.00 sec) 设置一个特殊的环境变量,这个是一个 session scope 的变量,其意义为读取这个时间之前的最新的一个版本。注意这里的时间设置的是 update 语句之前的那个时间:mysql> set @@tidb_snapshot="2016-10-08 16:45:26"; Query OK, 0 rows affected (0.00 sec) 这里读取到的内容即为 update 之前的内容,也就是历史版本:mysql> select * from t; +------+ | c | +------+ | 1 | | 2 | | 3 | +------+ 3 rows in set (0.00 sec) 清空这个变量后,即可读取最新版本数据:mysql> set @@tidb_snapshot=""; Query OK, 0 rows affected (0.00 sec)mysql> select * from t; +------+ | c | +------+ | 1 | | 22 | | 3 | +------+ 3 rows in set (0.00 sec)"}, {"url": "https://pingcap.com/recruit-cn/engineering/bizdev-cloud-engineer/", "title": "TiDB 商业产品开发 - Cloud 研发工程师", "content": " TiDB 商业产品开发 - Cloud 研发工程师 岗位职责: 开发基于 Kubernetes 的 TiDB Cloud 版自动化部署和运维工具; 开发基于 Kubernetes 的企业版 TiDB 自动化部署工具; 负责搭建基于 Kubernetes 和 TiDB 的企业级数据库云 DBaaS。 任职要求: 优秀的发现和解决问题能力,良好的沟通能力和团队合作精神; 扎实的编程能力,熟悉 C/C++/Rust/Go/Python 中至少一种; 了解各种常见网络协议原理和虚拟化技术; 熟悉 Docker 容器原理; 熟练使用 Linux 和 Docker 容器; 了解 Ansible/SaltStack/Puppet/Terraform 等自动化运维工具; 对分布式系统有一定了解。 加分项: 为 Docker/Kubernetes 等容器相关知名开源项目贡献过代码; 自己手动部署过 Kubernetes 集群; 基于 Kubernetes 开发过 operator 管理有状态服务; 熟悉 gRPC 协议; 熟悉 AWS/GCP/Azure 命令行运维工具 awscli, gcloud, az, terraform 等。 待遇:25K - 50K + 期权,13薪 + 奖金,优秀者可面议工作地点:北京,上海,广州,杭州,成都,特别优秀可 Remote"}, {"url": "https://pingcap.com/recruit-cn/engineering/bizdev-tools-engineer/", "title": "TiDB 商业产品开发 - Tools 研发工程师", "content": " TiDB 商业产品开发 - Tools 研发工程师 岗位职责: TiDB 商业工具开发,完善 TiDB 的周边生态,提升用户使用体验; 建设高度智能的自动化测试系统,进行各种破坏性测试,验证 TiDB 的可靠性。 任职要求: 扎实的编程能力,熟悉 C/C++/Go/Rust 其中一种编程语言; 熟悉大型分布式系统,具备冷静分析复杂问题能力; 熟悉常用算法和数据结构; 深入了解过操作系统和网络; 良好的沟通能力和技巧,以及抗压能力; 了解 Automated Reasoning、Static Analysis 等测试方法及工具。 加分项: 爱折腾,强烈的 Hack 精神; TopCoder、Codeforces 黄色以上。 待遇:25K - 50K + 期权,13薪 + 奖金,优秀者可面议工作地点:北京,上海,广州,杭州,成都,特别优秀可 Remote"}, {"url": "https://pingcap.com/recruit-cn/engineering/bizdev-fe-engineer/", "title": "TiDB 商业产品开发 - 前端开发工程师", "content": " TiDB 商业产品开发 - 前端开发工程师 岗位职责: 负责 TiDB 商业产品前端研发,构建功能丰富且流畅易用的 UI 系统,持续提升产品的用户体验; 前端组件设计和开发,框架定制和保证快速迭代的效率和质量 探索前端开发新规范和模式。 任职要求: 三年以上相关领域开发经验,扎实的编程基础; 优秀的发现和解决问题能力,良好的沟通能力和团队合作精神; 熟悉 JavaScript、TypeScript 和新语言规范和语法特性,如 ES2015 等; 精通 Webpack 构建,Node 脚本开发和常用 Prettier、ESLint、Babel 等配置; 熟悉 React/Angular/Vue 等现代 Web 前端框架使用和实现原理 熟悉富应用 SPA 开发模式,如单向数据流 Flux/Redux,响应式编程 rxjs/cyclejs。 加分项: 拥抱开源,对前沿技术有浓厚的热情和探索欲望,有开源项目经历; 良好的适应和学习能力对自己不设限,挑战如:数据可视化、监控告警 DevOPS; 喜欢 SaaS 产品,乐于商业化和工具产品设计等方向; 其他例如,您熟悉 Electron、看过 Chromium 源代码、写过一些关于 JavaScript 技术的博客文章等。具体不限,我们愿闻其详。 待遇:25K - 50K + 期权,13薪 + 奖金,优秀者可面议工作地点:北京"}, {"url": "https://pingcap.com/recruit-cn/engineering/bizdev-engineering-efficiency-engineer/", "title": "TiDB 商业产品开发 - 工程效率研发工程师", "content": " TiDB 商业产品开发 - 工程效率研发工程师 岗位职责: 构建自动化流程及工具,解决研发、测试与产品运维中遇到的各种效率问题; 负责 “薛定谔” 分布式测试平台的开发与维护; 负责公司内部 DevOps 平台的开发和维护; 负责操作系统内核调试、诊断工具的探索和研发。 任职要求: 具有探索精神,有强烈的责任感及合作精神,具备优秀的学习能力和创新能力; 有 2 年以上运维开发或内部工程效率工具开发相关领域经验; 熟悉 go/python 一种编程语言,熟悉 shell 和 linux 常用操作; 对 linux 操作系统参数及调优有较深入的了解; 对容器编排系统有较深入的理解及相关开发或使用经验; 对并发编程有较深入的理解; 熟悉 docker 原理及 docker 的常规操作。 加分项: 有分布式系统的测试相关经验; 有云平台如 AWS/Azure 等的开发经验; 熟悉 k8s/docker 代码。 待遇:25K - 50K + 期权,13薪 + 奖金,优秀者可面议工作地点:北京,上海,广州,杭州,成都,特别优秀可 Remote"}, {"url": "https://pingcap.com/recruit-cn/engineering/bizdev-qa-engineer/", "title": "TiDB 商业产品开发 - 测试开发工程师", "content": " TiDB 商业产品开发 - 测试开发工程师 岗位职责: 对 TiDB 缺陷和测试 case 进行管理,并监督测试执行结果,保障产品质量; 结合应用场景,收集用户反馈,针对性地开发测试用例; 探索有效的质量管理和测试方法论。 任职要求: 具有 3 年以上软件测试或开发经验,参与开发或测试大型项目; 扎实的编程能力,熟悉 C/C++/Go/Java/Python 中的一种,熟悉 Shell; 对数据库、分布式系统、linux 有深入了解; 对软件测试有浓厚的兴趣善于发现、分析和总结问题; 有良好的沟通能力,具备团队合作精神。 待遇:25K - 50K + 期权,13薪 + 奖金,优秀者可面议工作地点:北京,上海,广州,杭州,成都,特别优秀可 Remote"}, {"url": "https://pingcap.com/docs-cn/op-guide/gc/", "title": "TiDB 垃圾回收 (GC)", "content": " TiDB 垃圾回收 (GC) TiDB 采用 MVCC 的方式来进行并发控制。当对数据进行更新或者删除时,原有的数据不会被立刻删除,而是会被保留一段时间,并且在这段时间内这些旧数据仍然可以被读取。这使得写入操作和读取操作不必互斥,并使读取历史数据成为可能。存在超过一定时间并且不再使用的版本会被清理,否则它们将始终占用硬盘空间,并对性能产生负面影响。TiDB 使用一个垃圾回收 (GC) 机制来清理这些旧数据。工作方式 TiDB 会周期性地进行 GC。每个 TiDB Server 启动后都会在后台运行一个 gc_worker,每个集群中会有其中一个 gc_worker 被选为 leader,leader 负责维护 GC 的状态并向所有的 TiKV Region leader 发送 GC 命令。配置与监测方法 GC 相关的配置和运行状态记录在 mysql.tidb 这张系统表中,可以通过 SQL 语句进行检测和配置:mysql> select VARIABLE_NAME, VARIABLE_VALUE from mysql.tidb; +-----------------------+------------------------------------------------------------------------------------------------+ | VARIABLE_NAME | VARIABLE_VALUE | +-----------------------+------------------------------------------------------------------------------------------------+ | bootstrapped | True | | tidb_server_version | 18 | | tikv_gc_leader_uuid | 58accebfa7c0004 | | tikv_gc_leader_desc | host:ip-172-16-30-5, pid:95472, start at 2018-04-11 13:43:30.73076656 +0800 CST m=+0.068873865 | | tikv_gc_leader_lease | 20180418-11:02:30 +0800 CST | | tikv_gc_run_interval | 10m0s | | tikv_gc_life_time | 10m0s | | tikv_gc_last_run_time | 20180418-10:59:30 +0800 CST | | tikv_gc_safe_point | 20180418-10:58:30 +0800 CST | | tikv_gc_concurrency | 1 | +-----------------------+------------------------------------------------------------------------------------------------+ 10 rows in set (0.02 sec) 其中,tikv_gc_run_interval,tikv_gc_life_time,tikv_gc_concurrency 这三条记录可以手动配置。其余带有 tikv_gc 前缀的记录为当前运行状态的记录, TiDB 会自动更新这些记录,请勿手动修改。tikv_gc_run_interval 是 GC 运行时间间隔。tikv_gc_life_time 是历史版本的保留时间,每次进行 GC 时,会清理超过该时间的历史数据。这两项配置不应低于 10 分钟,默认值均为 10 分钟。可以直接用 SQL 修改其数值来进行配置。比如,如果想保留一天以内的历史数据,就可以执行:update mysql.tidb set VARIABLE_VALUE = '24h' where VARIABLE_NAME = 'tikv_gc_life_time'; 时长字符串的形式是数字后接时间单位的序列,如 24h、2h30m、2.5h。可以使用的时间单位包括 “h”、”m”、”s”。需要注意的是,在数据更新频繁的场景下如果将 tikv_gc_life_time 设置得比较大(如数天甚至数月),可能会有一些潜在的问题: 随着版本的不断增多,数据占用的磁盘空间会随之增加。 大量的历史版本会在一定程度上导致查询变慢,主要影响范围查询(如 select count(*) from t)。 如果在运行中突然将 tikv_gc_life_time 配置调小,可能会导致短时间内大量历史数据被删除,造成 I/O 负担。 tikv_gc_concurrency 是运行 GC 的并发数。默认该选项为 1,即单线程运行,逐个向每个涉及的 Region 发起请求并等待响应。可以增加该数值以改善性能,最大不能超过 128。tikv_gc_leader_uuid,tikv_gc_leader_desc,tikv_gc_leader_lease 是当前的 GC leader 的信息。tikv_gc_last_run_time 是上一次执行 GC 的时间。tikv_gc_safe_point 的含义是,在该时间点以前的版本已经被 GC 清理,并保证该时间点以后的读取可以正确进行。实现细节 GC 的实施过程实际上比较复杂。我们要在保证一致性不被破坏的前提下,清除不再使用的数据。具体来说,每次执行 GC,要顺序执行三个步骤:1. Resolve Locks TiDB 的事务是基于 Google Percolator 模型实现的,事务的提交是一个两阶段提交的过程。第一阶段完成时,所有涉及的 key 会加上一个锁,其中一个锁会被设定为 Primary,其余的锁(Secondary)则会指向 Primary;第二阶段会将 Primary 锁所在的 key 加上一个 Write 记录,并去除锁。这里的 Write 记录就是历史上对该 key 进行写入或删除,或者该 key 上发生事务回滚的记录。Primary 锁被替换为何种 Write 记录标志着该事务提交成功与否。接下来,所有 Secondary 锁也会被依次替换。如果替换这些 Secondary 锁的线程死掉了,锁就残留了下来。在 GC 过程中如果遇到了时间戳在 safe point 之前的这样的锁,就会根据该事务提交与否,将该锁也替换成 Write 记录。这一步是必须的,因为如果其 Primary 的 Write 记录被 GC 清除掉了,就再也无法知道该事务是否成功,也就难以保证一致性。2. Delete Ranges DeleteRanges 通常在 drop table 这样的操作之后需要进行,用于删除可能很大的一个区间。如果 TiKV 的 use_delete_range 选项没有打开,那么 TiKV 会把范围中的 key 逐个删除。3. Do GC 这一步把每一个 key 的 safe point 之前的数据和 Write 记录清除掉。有一个特例是,如果在 safe point 之前的所有 Put 类型和 Delete 类型的 Write 记录中,最后一个记录是 Put(即写入),那么该记录(及其对应的数据)不能被直接删除。否则,时间戳在 safe point 之后、该 key 的下一个版本之前的读取操作将无法读取到该数据。"}, {"url": "https://pingcap.com/docs-cn/try-tidb/", "title": "TiDB 基本操作", "content": " TiDB 基本操作 成功部署 TiDB 集群之后,便可以在 TiDB 中执行 SQL 语句了。因为 TiDB 兼容 MySQL,你可以使用 MySQL 客户端连接 TiDB,并且大多数情况下可以直接执行 MySQL 语句。本文介绍 CRUD 操作等基本的 SQL 语句。完整的 SQL 语句列表,参见 TiDB SQL 语法详解。创建、查看和删除数据库 使用 CREATE DATABASE 语句创建数据库。语法如下:CREATE DATABASE db_name [options]; 例如,要创建一个名为 samp_db 的数据库,可使用以下语句:CREATE DATABASE IF NOT EXISTS samp_db; 使用 SHOW DATABASES 语句查看数据库:SHOW DATABASES; 使用 DROP DATABASE 语句删除数据库,例如:DROP DATABASE samp_db; 创建、查看和删除表 使用 CREATE TABLE 语句创建表。语法如下:CREATE TABLE table_name column_name data_type constraint; 例如:CREATE TABLE person ( number INT(11), name VARCHAR(255), birthday DATE ); 如果表已存在,添加 IF NOT EXISTS 可防止发生错误:CREATE TABLE IF NOT EXISTS person ( number INT(11), name VARCHAR(255), birthday DATE ); 使用 SHOW CREATE 语句查看建表语句。例如:SHOW CREATE table person; 使用 SHOW FULL COLUMNS 语句查看表的列。 例如:SHOW FULL COLUMNS FROM person; 使用 DROP TABLE 语句删除表。例如:DROP TABLE person; 或者DROP TABLE IF EXISTS person; 使用 SHOW TABLES 语句查看数据库中的所有表。例如:SHOW TABLES FROM samp_db; 创建、查看和删除索引 对于值不唯一的列,可使用 CREATE INDEX 或 ALTER TABLE 语句。例如:CREATE INDEX person_num ON person (number); 或者ALTER TABLE person ADD INDEX person_num (number); 对于值唯一的列,可以创建唯一索引。例如:CREATE UNIQUE INDEX person_num ON person (number); 或者ALTER TABLE person ADD UNIQUE person_num on (number); 使用 SHOW INDEX 语句查看表内所有索引:SHOW INDEX from person; 使用 ALTER TABLE 或 DROP INDEX 语句来删除索引。与 CREATE INDEX 语句类似,DROP INDEX 也可以嵌入 ALTER TABLE 语句。例如:DROP INDEX person_num ON person; ALTER TABLE person DROP INDEX person_num; 增删改查数据 使用 INSERT 语句向表内插入数据。例如:INSERT INTO person VALUES("1","tom","20170912"); 使用 SELECT 语句检索表内数据。例如:SELECT * FROM person; +--------+------+------------+ | number | name | birthday | +--------+------+------------+ | 1 | tom | 2017-09-12 | +--------+------+------------+ 使用 UPDATE 语句修改表内数据。例如:UPDATE person SET birthday='20171010' WHERE name='tom'; SELECT * FROM person; +--------+------+------------+ | number | name | birthday | +--------+------+------------+ | 1 | tom | 2017-10-10 | +--------+------+------------+ 使用 DELETE 语句删除表内数据:DELETE FROM person WHERE number=1; SELECT * FROM person; Empty set (0.00 sec) 创建、授权和删除用户 使用 CREATE USER 语句创建一个用户 tiuser,密码为 123456:CREATE USER 'tiuser'@'localhost' IDENTIFIED BY '123456'; 授权用户 tiuser 可检索数据库 samp_db 内的表:GRANT SELECT ON samp_db.* TO 'tiuser'@'localhost'; 查询用户 tiuser 的权限:SHOW GRANTS for tiuser@localhost; 删除用户 tiuser:DROP USER 'tiuser'@'localhost';"}, {"url": "https://pingcap.com/docs-cn/QUICKSTART/", "title": "TiDB 快速入门指南", "content": " TiDB 快速入门指南 作为开源分布式 HTAP (Hybrid Transactional and Analytical Processing) 数据库,TiDB 可以部署在本地和云平台上,支持公有云、私有云和混合云。TiDB 部署方式 你可以根据实际场景或需求,选择相应的方式来部署 TiDB 集群: 使用 Ansible 部署:如果用于生产环境,须使用 Ansible 部署 TiDB 集群。 使用 Ansible 离线部署:如果部署环境无法访问网络,可使用 Ansible 进行离线部署。 使用 Docker Compose 部署:如果你只是想测试 TiDB、体验 TiDB 的特性,或者用于开发环境,可以使用 Docker Compose 在本地快速部署 TiDB 集群。该部署方式不适用于生产环境。 使用 Docker 部署:你可以使用 Docker 部署 TiDB 集群,但该部署方式不适用于生产环境。 项目源码 TiDB 集群所有组件的源码均可从 GitHub 上直接访问: TiDB TiKV PD TiSpark TiDB Operator "}, {"url": "https://pingcap.com/docs-cn/sql/tidb-server/", "title": "TiDB 数据库管理", "content": " TiDB 数据库管理 TiDB 服务 TiDB 是指 TiDB 数据库系统,本篇文档涉及到 TiDB 集群的基本管理功能。TiDB 集群启动配置 可以通过命令行参数或者配置文件设置服务参数,或者是两者一起使用。注意命令行参数的优先级高于配置文件,如果同一个参数两种方式都设置,会以命令行参数中的值为准。具体信息参考这篇文档。TiDB 数据库系统变量 TiDB 兼容 MySQL 的系统变量,同时定义了一些特有的系统变量用于调整数据库行为,具体信息参考 TiDB 专用系统变量和语法 文档。TiDB 系统表 和 MySQL 类似,TiDB 中也有系统表,用于存放数据库运行时所需信息。具体信息参考 TiDB 系统数据库文档。TiDB 数据目录 TiDB 数据存放在存储引擎中,数据目录取决于使用的存储引擎,存储引擎的选择参见 TiDB 启动参数文档。 对于使用本地存储引擎的情况,数据存储在本机硬盘上,目录位置通过 path 参数控制。 对于使用 TiKV 引擎的情况,数据存储在 TiKV 节点上,目录位置通过 data-dir 参数控制。 TiDB 服务器日志文件 TiDB 集群的三个组件(tidb-server、tikv-server、pd-server)默认会将日志输出到标准错误中,并且三个组件都支持设置 --log-file 启动参数(或者是配置文件中的配置项)将日志输出到文件中。通过配置文件可以调整日志的行为,具体信息请参见各个组件的配置文件说明。例如: tidb-server 日志配置项。"}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/tidb-server/", "title": "TiDB 数据库管理", "content": " TiDB 数据库管理 TiDB 服务 TiDB 是指 TiDB 数据库系统,本篇文档涉及到 TiDB 集群的基本管理功能。TiDB 集群启动配置 可以通过命令行参数或者配置文件设置服务参数,或者是两者一起使用。注意命令行参数的优先级高于配置文件,如果同一个参数两种方式都设置,会以命令行参数中的值为准。具体信息参考这篇文档。TiDB 数据库系统变量 TiDB 兼容 MySQL 的系统变量,同时定义了一些特有的系统变量用于调整数据库行为,具体信息参考 TiDB 专用系统变量和语法 文档。TiDB 系统表 和 MySQL 类似,TiDB 中也有系统表,用于存放数据库运行时所需信息。具体信息参考 TiDB 系统数据库文档。TiDB 数据目录 TiDB 数据存放在存储引擎中,数据目录取决于使用的存储引擎,存储引擎的选择参见 TiDB 启动参数文档。对于使用本地存储引擎的情况,数据存储在本机硬盘上,目录位置通过 path 参数控制。对于使用 TiKV 引擎的情况,数据存储在 TiKV 节点上,目录位置通过 data-dir 参数控制。TiDB 服务器日志文件 TiDB 集群的三个组件(tidb-server、tikv-server、pd-server)默认会将日志输出到标准错误中,并且三个组件都支持设置 --log-file 启动参数 (或者是配置文件中的配置项)将日志输出到文件中。通过配置文件可以调整日志的行为,具体信息请参见各个组件的配置文件说明。例如: tidb-server 日志配置项。"}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/tidb-server/", "title": "TiDB 数据库管理", "content": " TiDB 数据库管理 TiDB 服务 TiDB 是指 TiDB 数据库系统,本篇文档涉及到 TiDB 集群的基本管理功能。TiDB 集群启动配置 可以通过命令行参数或者配置文件设置服务参数,或者是两者一起使用。注意命令行参数的优先级高于配置文件,如果同一个参数两种方式都设置,会以命令行参数中的值为准。具体信息参考这篇文档。TiDB 数据库系统变量 TiDB 兼容 MySQL 的系统变量,同时定义了一些特有的系统变量用于调整数据库行为,具体信息参考 TiDB 专用系统变量和语法 文档。TiDB 系统表 和 MySQL 类似,TiDB 中也有系统表,用于存放数据库运行时所需信息。具体信息参考 TiDB 系统数据库文档。TiDB 数据目录 TiDB 数据存放在存储引擎中,数据目录取决于使用的存储引擎,存储引擎的选择参见 TiDB 启动参数文档。对于使用本地存储引擎的情况,数据存储在本机硬盘上,目录位置通过 path 参数控制。对于使用 TiKV 引擎的情况,数据存储在 TiKV 节点上,目录位置通过 data-dir 参数控制。TiDB 服务器日志文件 TiDB 集群的三个组件(tidb-server、tikv-server、pd-server)默认会将日志输出到标准错误中,并且三个组件都支持设置 --log-file 启动参数 (或者是配置文件中的配置项)将日志输出到文件中。通过配置文件可以调整日志的行为,具体信息请参见各个组件的配置文件说明。例如: tidb-server 日志配置项。"}, {"url": "https://pingcap.com/docs-cn/sql/datatype/", "title": "TiDB 数据类型", "content": " TiDB 数据类型 概述 TiDB 支持 MySQL 除空间类型之外的所有数据类型,包括数值型类型、字符串类型、时间&日期类型、Json 类型。数据类型定义一般为 T(M[, D]),其中: T 表示具体的类型 M 对于整数类型表示最大显示长度;对于浮点数或者定点数表示精度;对于字符类型表示最大长度。M 的最大值取决于具体的类型。 D 表示浮点数/定点数的小数位长度 对于时间&日期类型中的 TIME、DATETIME 以及 TIMESTAMP,定义中可以包含 Fsp 表示秒的精度,其取值范围是0到6,默认的精度为0 数值类型 概述 TiDB 支持 MySQL 所有的数值类型,按照精度可以分为: 整数类型(精确值) 浮点类型(近似值) 定点类型(精确值) 整数类型 TiDB 支持 MySQL 所有的整数类型,包括 INTEGER/INT、TINYINT、SMALLINT、MEDIUMINT 以及 BIGINT,完整信息参考这篇文档。类型定义 语法:BIT[(M)] > 比特值类型。M 表示比特位的长度,取值范围从1到64,其默认值是1。 TINYINT[(M)] [UNSIGNED] [ZEROFILL] > TINYINT 类型。有符号数的范围是[-128, 127]。无符号数的范围是[0, 255]。 BOOL, BOOLEAN > 布尔类型,和 TINYINT(1) 等价。零值被认为是 False,非零值认为是 True。在 TiDB 内部,True 存储为1, False 存储为0。 SMALLINT[(M)] [UNSIGNED] [ZEROFILL] > SMALLINT 类型。有符号数的范围是[-32768, 32767]。无符号数的范围是[0, 65535]。 MEDIUMINT[(M)] [UNSIGNED] [ZEROFILL] > MEDIUMINT 类型。有符号数的范围是[-8388608, 8388607]。无符号数的范围是[0, 16777215]。 INT[(M)] [UNSIGNED] [ZEROFILL] > INT 类型。 有符号数的范围是[-2147483648, 2147483647]。无符号数的范围是[0, 4294967295]。 INTEGER[(M)] [UNSIGNED] [ZEROFILL] > 和 INT 相同。 BIGINT[(M)] [UNSIGNED] [ZEROFILL] > BIGINT 类型。 有符号数的范围是[-9223372036854775808, 9223372036854775807]。无符号数的范围是[0, 18446744073709551615]。 字段意义: 语法元素 说明 M 类型显示宽度,可选 UNSIGNED 无符号数,如果不加这个标识,则为有符号数 ZEROFILL 补零标识,如果有这个标识,TiDB 会自动给类型增加 UNSIGNED 标识,但是没有做补零的操作 存储空间以及取值范围 每种类型对存储空间的需求以及最大/最小值如下表所示: 类型 存储空间 最小值(有符号/无符号) 最大值(有符号/无符号) TINYINT 1 -128 / 0 127 / 255 SMALLINT 2 -32768 / 0 32767 / 65535 MEDIUMINT 3 -8388608 / 0 8388607 / 16777215 INT 4 -2147483648 / 0 2147483647 / 4294967295 BIGINT 8 -9223372036854775808 / 0 9223372036854775807 / 18446744073709551615 浮点类型 TiDB 支持 MySQL 所有的浮点类型,包括 FLOAT、DOUBLE,完整信息参考这篇文档。类型定义 语法:FLOAT[(M,D)] [UNSIGNED] [ZEROFILL] > 单精度浮点数。允许的值范围为 -2^128 ~ +2^128,也即 -3.402823466E+38 到 -1.175494351E-38、0 和 1.175494351E-38 到 3.402823466E+38。这些是理论限制,基于 IEEE 标准。实际的范围根据硬件或操作系统的不同可能稍微小些。 DOUBLE[(M,D)] [UNSIGNED] [ZEROFILL] > 双精度浮点数。允许的值范围为:-2^1024 ~ +2^1024,也即是 -1.7976931348623157E+308 到 -2.2250738585072014E-308、0 和 2.2250738585072014E-308 到 1.7976931348623157E+308。这些是理论限制,基于 IEEE 标准。实际的范围根据硬件或操作系统的不同可能稍微小些。 DOUBLE PRECISION [(M,D)] [UNSIGNED] [ZEROFILL], REAL[(M,D)] [UNSIGNED] [ZEROFILL] > 为 DOUBLE 的同义词。 FLOAT(p) [UNSIGNED] [ZEROFILL] > 浮点数。p 表示精度(以位数表示),只使用该值来确定是否结果列的数据类型为 FLOAT 或 DOUBLE。如果 p 为从 0 到 24,数据类型变为没有 M 或 D 值的 FLOAT。如果 p 为从 25 到 53,数据类型变为没有 M 或 D 值的 DOUBLE。结果列范围与本节前面描述的单精度 FLOAT 或双精度 DOUBLE 数据类型相同。 字段意义: 语法元素 说明 M 小数总位数 D 小数点后位数 UNSIGNED 无符号数,如果不加这个标识,则为有符号数 ZEROFILL 补零标识,如果有这个标识,TiDB 会自动给类型增加 UNSIGNED 标识 存储空间 每种类型对存储空间的需求如下表所示: 类型 存储空间 FLOAT 4 FLOAT(p) 如果 0 <= p <= 24 为 4 个字节, 如果 25 <= p <= 53 为 8 个字节 DOUBLE 8 定点类型 TiDB 支持 MySQL 所有的定点类型,包括 DECIMAL、NUMERIC,完整信息参考这篇文档。类型定义 语法:DECIMAL[(M[,D])] [UNSIGNED] [ZEROFILL] > 定点数。M 是小数位数(精度)的总数,D 是小数点(标度)后面的位数。小数点和‘-’(负数)符号不包括在M中。如果 D 是 0,则值没有小数点或分数部分。如果 D 被省略, 默认是 0。如果 M 被省略, 默认是 10。 NUMERIC[(M[,D])] [UNSIGNED] [ZEROFILL] > DECIMAL的同义词。 字段意义: 语法元素 说明 M 小数总位数 D 小数点后位数 UNSIGNED 无符号数,如果不加这个标识,则为有符号数 ZEROFILL 补零标识,如果有这个标识,TiDB 会自动给类型增加 UNSIGNED 标识 日期时间类型 概述 TiDB 支持 MySQL 所有的日期时间类型,包括 DATE、DATETIME、TIMESTAMP、TIME 以及 YEAR,完整信息参考这篇文档。类型定义 语法:DATE > 日期。支持的范围为`1000-01-01`到`9999-12-31`。以`YYYY-MM-DD`格式显示 DATE 值。 DATETIME[(fsp)] > 日期和时间的组合。支持的范围是`1000-01-01 00:00:00.000000`到`9999-12-31 23:59:59.000000`。 以`YYYY-MM-DD HH:MM:SS[.fraction]`格式显示 DATETIME 值。fsp 参数是表示秒精度,取值范围为 0-6,默认值取 0。 TIMESTAMP[(fsp)] > 时间戳。支持的范围是`1970-01-01 00:00:01.000000`到`2038-01-19 03:14:07.999999`。 fsp 参数是表示秒精度,取值范围为 0-6,默认值取 0。 TIME[(fsp)] > 时间。范围是`-838:59:59.000000`到`838:59:59.000000`。以`HH:MM:SS[.fraction]`格式显示 TIME 值。 fsp 参数是表示秒精度,取值范围为:0-6。默认值取 0。 YEAR[(4)] > 四位格式的年。允许的值是 1901 到 2155 和 0000。 字符串类型 概述 TiDB 支持 MySQL 所有的字符串类型,包括 CHAR、VARCHAR、BINARY、VARBINARY、BLOB、TEXT、ENUM 以及 SET, 完整信息参考这篇文档。类型定义 语法:[NATIONAL] CHAR[(M)] [CHARACTER SET charset_name] [COLLATE collation_name] > 定长字符串。CHAR 列的长度固定为创建表时声明的长度。长度可以为从 0 到 255 的任何值。当保存 CHAR 值时,在它们的右边填充空格以达到指定的长度。 [NATIONAL] VARCHAR(M) [CHARACTER SET charset_name] [COLLATE collation_name] > 变长字符串。M 表示最大列长度,范围是 0 到 65535。VARCHAR 的最大实际长度由最长的行的大小和使用的字符集确定。 BINARY(M) > 类似于 CHAR, 区别在于 BINARY 存储的是二进制字符串。 VARBINARY(M) > 类似于 VARCHAR, 区别在于 VARBINARY 存储的是二进制字符串。 BLOB[(M)] > 二进制大文件。M 表示最大列长度,范围是 0 到 65535。 TINYBLOB > 类似于 BLOB, 区别在于最大列长度为 255。 MEDIUMBLOB > 类似于 BLOB, 区别在于最大列长度为 16777215。 LONGBLOB > 类似于 BLOB, 区别在于最大列长度为 4294967295。 TEXT[(M)] [CHARACTER SET charset_name] [COLLATE collation_name] > 文本串。M 表示最大列长度,范围是 0 到 65535。TEXT 的最大实际长度由最长的行的大小和使用的字符集确定。 TINYTEXT[(M)] [CHARACTER SET charset_name] [COLLATE collation_name] > 类似于 TEXT, 区别在于最大列长度为 255。 MEDIUMTEXT [CHARACTER SET charset_name] [COLLATE collation_name] > 类似于 TEXT, 区别在于最大列长度为 16777215。 LONGTEXT [CHARACTER SET charset_name] [COLLATE collation_name] > 类似于 TEXT, 区别在于最大列长度为 4294967295。 ENUM('value1','value2',...) [CHARACTER SET charset_name] [COLLATE collation_name] > 枚举。只能有一个值的字符串对象,其值通常选自允许值列表中,在某些情况下也可以是空串或者 NULL。 SET('value1','value2',...) [CHARACTER SET charset_name] [COLLATE collation_name] > 集合。可以有零或者多个值的字符串对象,每一个值必须选自允许值列表中。 Json 类型 Json 类型可以存储 Json 这种半结构化的数据,相比于直接将 Json 存储为字符串,它的好处在于: 使用 Binary 格式进行序列化,对 Json 的内部字段的查询、解析加快; 多了 Json 合法性验证的步骤,只有合法的 Json 文档才可以放入这个字段中; Json 字段本身上,并不能创建索引。相反,可以对 Json 文档中的某个子字段创建索引。例如:CREATE TABLE city ( id INT PRIMARY KEY, detail JSON, population INT AS (JSON_EXTRACT(detail, '$.population') ); INSERT INTO city VALUES (1, '{"name": "Beijing", "population": 100}'); SELECT id FROM city WHERE population >= 100; 枚举类型 集合类型是一个字符串,其值必须是从一个固定集合中选取,这个固定集合在创建表的时候定义,语法是:ENUM('value1','value2',...) [CHARACTER SET charset_name] [COLLATE collation_name] # 例子 ENUM('apple', 'orange', 'pear') 枚举类型的值在 TiDB 内部使用数值来存储,每个值会按照定义的顺序转换为一个数字,比如上面的例子中,每个字符串值都会映射为一个数字: 值 数字 NULL NULL “ 0 ‘apple’ 1 ‘orange’ 2 ‘pear’ 3 更多信息参考 MySQL 枚举文档。集合类型 集合类型是一个包含零个或多个值的字符串,其中每个值必须是从一个固定集合中选取,这个固定集合在创建表的时候定义,语法是:SET('value1','value2',...) [CHARACTER SET charset_name] [COLLATE collation_name] # 例子 SET('1', '2') NOT NULL 上面的例子中,这列的有效值可以是:'' '1' '2' '1,2' 集合类型的值在 TiDB 内部会转换为一个 Int64 数值,每个元素是否存在用一个二进制位的 0/1 值来表示,比如这个例子 SET('a','b','c','d'),每一个元素都被映射为一个数字,且每个数字的二进制表示只会有一位是 1: 成员 十进制表示 二进制表示 ‘a’ 1 0001 ‘b’ 2 0010 ‘c’ 4 0100 ’d’ 8 1000 这样对于值为 ('a', 'c') 的元素,其二进制表示即为 0101。更多信息参考 MySQL 集合文档。数据类型的默认值 在一个数据类型描述中的 DEFAULT value 段描述了一个列的默认值。这个默认值必须是常量,不可以是一个函数或者是表达式。但是对于时间类型,可以例外的使用 NOW、CURRENT_TIMESTAMP、LOCALTIME、LOCALTIMESTAMP 等函数作为 DATETIME 或者 TIMESTAMP 的默认值。BLOB、TEXT 以及 JSON 不可以设置默认值。如果一个列的定义中没有 DEFAULT 的设置。TiDB 按照如下的规则决定: 如果该类型可以使用 NULL 作为值,那么这个列会在定义时添加隐式的默认值设置 DEFAULT NULL。 如果该类型无法使用 NULL 作为值,那么这个列在定义时不会添加隐式的默认值设置。 对于一个设置了 NOT NULL 但是没有显式设置 DEFAULT 的列,当 INSERT、REPLACE 没有涉及到该列的值时,TiDB 根据当时的 SQL_MODE 进行不同的行为: 如果此时是 strict sql mode,在事务中的语句会导致事务失败并回滚,非事务中的语句会直接报错。 如果此时不是 strict sql mode,TiDB 会为这列赋值为列数据类型的隐式默认值。 此时隐式默认值的设置按照如下规则: 对于数值类型,它们的默认值是 0。当有 AUTO_INCREMENT 参数时,默认值会按照增量情况赋予正确的值。 对于除了时间戳外的日期时间类型,默认值会是该类型的“零值”。时间戳类型的默认值会是当前的时间。 对于除枚举以外的字符串类型,默认值会是空字符串。对于枚举类型,默认值是枚举中的第一个值。 "}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/datatype/", "title": "TiDB 数据类型", "content": " TiDB 数据类型 概述 TiDB 支持 MySQL 除空间类型之外的所有数据类型,包括数值型类型、字符串类型、时间&日期类型、Json 类型。数据类型定义一般为 T(M[, D]),其中: T 表示具体的类型 M 对于整数类型表示最大显示长度;对于浮点数或者定点数表示精度;对于字符类型表示最大长度。M 的最大值取决于具体的类型。 D 表示浮点数/定点数的小数位长度 对于时间&日期类型中的 TIME、DATETIME 以及 TIMESTAMP,定义中可以包含 Fsp 表示秒的精度,其取值范围是0到6,默认的精度为0 数值类型 概述 TiDB 支持 MySQL 所有的数值类型,按照精度可以分为: 整数类型(精确值) 浮点类型(近似值) 定点类型(精确值) 整数类型 TiDB 支持 MySQL 所有的整数类型,包括 INTEGER/INT、TINYINT、SMALLINT、MEDIUMINT 以及 BIGINT,完整信息参考这篇文档。类型定义 语法:BIT[(M)] > 比特值类型。M 表示比特位的长度,取值范围从1到64,其默认值是1。 TINYINT[(M)] [UNSIGNED] [ZEROFILL] > TINYINT 类型。有符号数的范围是[-128, 127]。无符号数的范围是[0, 255]。 BOOL, BOOLEAN > 布尔类型,和 TINYINT(1) 等价。零值被认为是 False,非零值认为是 True。在 TiDB 内部,True 存储为1, False 存储为0。 SMALLINT[(M)] [UNSIGNED] [ZEROFILL] > SMALLINT 类型。有符号数的范围是[-32768, 32767]。无符号数的范围是[0, 65535]。 MEDIUMINT[(M)] [UNSIGNED] [ZEROFILL] > MEDIUMINT 类型。有符号数的范围是[-8388608, 8388607]。无符号数的范围是[0, 16777215]。 INT[(M)] [UNSIGNED] [ZEROFILL] > INT 类型。 有符号数的范围是[-2147483648, 2147483647]。无符号数的范围是[0, 4294967295]。 INTEGER[(M)] [UNSIGNED] [ZEROFILL] > 和 INT 相同。 BIGINT[(M)] [UNSIGNED] [ZEROFILL] > BIGINT 类型。 有符号数的范围是[-9223372036854775808, 9223372036854775807]。无符号数的范围是[0, 18446744073709551615]。 字段意义: 语法元素 说明 M 类型长度,可选的 UNSIGNED 无符号数,如果不加这个标识,则为有符号数 ZEROFILL 补零标识,如果有这个标识,TiDB 会自动给类型增加 UNSIGNED 标识,但是没有做补零的操作 存储空间以及取值范围 每种类型对存储空间的需求以及最大/最小值如下表所示: 类型 存储空间 最小值(有符号/无符号) 最大值(有符号/无符号) TINYINT 1 -128 / 0 127 / 255 SMALLINT 2 -32768 / 0 32767 / 65535 MEDIUMINT 3 -8388608 / 0 8388607 / 16777215 INT 4 -2147483648 / 0 2147483647 / 4294967295 BIGINT 8 -9223372036854775808 / 0 9223372036854775807 / 18446744073709551615 浮点类型 TiDB 支持 MySQL 所有的浮点类型,包括 FLOAT、DOUBLE,完整信息参考这篇文档。类型定义 语法:FLOAT[(M,D)] [UNSIGNED] [ZEROFILL] > 单精度浮点数。允许的值范围为 -2^128 ~ +2^128,也即 -3.402823466E+38 到 -1.175494351E-38、0 和 1.175494351E-38 到 3.402823466E+38。这些是理论限制,基于 IEEE 标准。实际的范围根据硬件或操作系统的不同可能稍微小些。 DOUBLE[(M,D)] [UNSIGNED] [ZEROFILL] > 双精度浮点数。允许的值范围为:-2^1024 ~ +2^1024,也即是 -1.7976931348623157E+308 到 -2.2250738585072014E-308、0 和 2.2250738585072014E-308 到 1.7976931348623157E+308。这些是理论限制,基于 IEEE 标准。实际的范围根据硬件或操作系统的不同可能稍微小些。 DOUBLE PRECISION [(M,D)] [UNSIGNED] [ZEROFILL], REAL[(M,D)] [UNSIGNED] [ZEROFILL] > 为 DOUBLE 的同义词。 FLOAT(p) [UNSIGNED] [ZEROFILL] > 浮点数。p 表示精度(以位数表示),只使用该值来确定是否结果列的数据类型为 FLOAT 或 DOUBLE。如果 p 为从 0 到 24,数据类型变为没有 M 或 D 值的 FLOAT。如果 p 为从 25 到 53,数据类型变为没有 M 或 D 值的 DOUBLE。结果列范围与本节前面描述的单精度 FLOAT 或双精度 DOUBLE 数据类型相同。 字段意义: 语法元素 说明 M 小数总位数 D 小数点后位数 UNSIGNED 无符号数,如果不加这个标识,则为有符号数 ZEROFILL 补零标识,如果有这个标识,TiDB 会自动给类型增加 UNSIGNED 标识 存储空间 每种类型对存储空间的需求如下表所示: 类型 存储空间 FLOAT 4 FLOAT(p) 如果 0 <= p <= 24 为 4 个字节, 如果 25 <= p <= 53 为 8 个字节 DOUBLE 8 定点类型 TiDB 支持 MySQL 所有的浮点类型,包括 DECIMAL、NUMERIC,完整信息参考这篇文档。类型定义 语法:DECIMAL[(M[,D])] [UNSIGNED] [ZEROFILL] > 定点数。M 是小数位数(精度)的总数,D 是小数点(标度)后面的位数。小数点和‘-’(负数)符号不包括在M中。如果 D 是 0,则值没有小数点或分数部分。如果 D 被省略, 默认是 0。如果 M 被省略, 默认是 10。 NUMERIC[(M[,D])] [UNSIGNED] [ZEROFILL] > DECIMAL的同义词。 字段意义: 语法元素 说明 M 小数总位数 D 小数点后位数 UNSIGNED 无符号数,如果不加这个标识,则为有符号数 ZEROFILL 补零标识,如果有这个标识,TiDB 会自动给类型增加 UNSIGNED 标识 日期时间类型 概述 TiDB 支持 MySQL 所有的日期时间类型,包括 DATE、DATETIME、TIMESTAMP、TIME 以及 YEAR,完整信息参考这篇文档。类型定义 语法:DATE > 日期。支持的范围为`1000-01-01`到`9999-12-31`。以`YYYY-MM-DD`格式显示 DATE 值。 DATETIME[(fsp)] > 日期和时间的组合。支持的范围是`1000-01-01 00:00:00.000000`到`9999-12-31 23:59:59.000000`。 以`YYYY-MM-DD HH:MM:SS[.fraction]`格式显示 DATETIME 值。fsp 参数是表示秒精度,取值范围为 0-6,默认值取 0。 TIMESTAMP[(fsp)] > 时间戳。支持的范围是`1970-01-01 00:00:01.000000`到`2038-01-19 03:14:07.999999`。 fsp 参数是表示秒精度,取值范围为 0-6,默认值取 0。 TIME[(fsp)] > 时间。范围是`-838:59:59.000000`到`838:59:59.000000`。以`HH:MM:SS[.fraction]`格式显示 TIME 值。 fsp 参数是表示秒精度,取值范围为:0-6。默认值取 0。 YEAR[(2|4)] > 两位或四位格式的年。默认是四位格式。在四位格式中,允许的值是 1901 到 2155 和 0000。在两位格式中,允许的值是 70 到 69,表示从 1970 年到 2069 年。 字符串类型 概述 TiDB 支持 MySQL 所有的字符串类型,包括 CHAR、VARCHAR、BINARY、VARBINARY、BLOB、TEXT、ENUM 以及 SET, 完整信息参考这篇文档。类型定义 语法:[NATIONAL] CHAR[(M)] [CHARACTER SET charset_name] [COLLATE collation_name] > 定长字符串。CHAR 列的长度固定为创建表时声明的长度。长度可以为从 0 到 255 的任何值。当保存 CHAR 值时,在它们的右边填充空格以达到指定的长度。 [NATIONAL] VARCHAR(M) [CHARACTER SET charset_name] [COLLATE collation_name] > 变长字符串。M 表示最大列长度,范围是 0 到 65535。VARCHAR 的最大实际长度由最长的行的大小和使用的字符集确定。 BINARY(M) > 类似于 CHAR, 区别在于 BINARY 存储的是二进制字符串。 VARBINARY(M) > 类似于 VARCHAR, 区别在于 VARBINARY 存储的是二进制字符串。 BLOB[(M)] > 二进制大文件。M 表示最大列长度,范围是 0 到 65535。 TINYBLOB > 类似于 BLOB, 区别在于最大列长度为 255。 MEDIUMBLOB > 类似于 BLOB, 区别在于最大列长度为 16777215。 LONGBLOB > 类似于 BLOB, 区别在于最大列长度为 4294967295。 TEXT[(M)] [CHARACTER SET charset_name] [COLLATE collation_name] > 文本串。M 表示最大列长度,范围是 0 到 65535。TEXT 的最大实际长度由最长的行的大小和使用的字符集确定。 TINYTEXT[(M)] [CHARACTER SET charset_name] [COLLATE collation_name] > 类似于 TEXT, 区别在于最大列长度为 255。 MEDIUMTEXT [CHARACTER SET charset_name] [COLLATE collation_name] > 类似于 TEXT, 区别在于最大列长度为 16777215。 LONGTEXT [CHARACTER SET charset_name] [COLLATE collation_name] > 类似于 TEXT, 区别在于最大列长度为 4294967295。 ENUM('value1','value2',...) [CHARACTER SET charset_name] [COLLATE collation_name] > 枚举。只能有一个值的字符串对象,其值通常选自允许值列表中,在某些情况下也可以是空串或者 NULL。 SET('value1','value2',...) [CHARACTER SET charset_name] [COLLATE collation_name] > 集合。可以有零或者多个值的字符串对象,每一个值必须选自允许值列表中。 Json 类型 Json 类型可以存储 Json 这种半结构化的数据,相比于直接将 Json 存储为字符串,它的好处在于: 使用 Binary 格式进行序列化,对 Json 的内部字段的查询、解析加快; 多了 Json 合法性验证的步骤,只有合法的 Json 文档才可以放入这个字段中; Json 字段本身上,并不能创建索引。相反,可以对 Json 文档中的某个子字段创建索引。例如:CREATE TABLE city ( id INT PRIMARY KEY, detail JSON, population INT AS (JSON_EXTRACT(detail, '$.population') ); INSERT INTO city VALUES (1, '{"name": "Beijing", "population": 100}'); SELECT id FROM city WHERE population >= 100; 枚举类型 集合类型是一个字符串,其值必须是从一个固定集合中选取,这个固定集合在创建表的时候定义,语法是:ENUM('value1','value2',...) [CHARACTER SET charset_name] [COLLATE collation_name] # 例子 ENUM('apple', 'orange', 'pear') 枚举类型的值在 TiDB 内部使用数值来存储,每个值会按照定义的顺序转换为一个数字,比如上面的例子中,每个字符串值都会映射为一个数字: 值 数字 NULL NULL “ 0 ‘apple’ 1 ‘orange’ 2 ‘pear’ 3 更多信息参考 MySQL 枚举文档。集合类型 集合类型是一个包含零个或多个值的字符串,其中每个值必须是从一个固定集合中选取,这个固定集合在创建表的时候定义,语法是:SET('value1','value2',...) [CHARACTER SET charset_name] [COLLATE collation_name] # 例子 SET('1', '2') NOT NULL 上面的例子中,这列的有效值可以是:'' '1' '2' '1,2' 集合类型的值在 TiDB 内部会转换为一个 Int64 数值,每个元素是否存在用一个二进制位的 0/1 值来表示,比如这个例子 SET('a','b','c','d'),每一个元素都被映射为一个数字,且每个数字的二进制表示只会有一位是 1: 成员 十进制表示 二进制表示 ‘a’ 1 0001 ‘b’ 2 0010 ‘c’ 4 0100 ’d’ 8 1000 这样对于值为 ('a', 'c') 的元素,其二进制表示即为 0101。更多信息参考 MySQL 集合文档。数据类型的默认值 在一个数据类型描述中的 DEFAULT value 段描述了一个列的默认值。这个默认值必须是常量,不可以是一个函数或者是表达式。但是对于时间类型,可以例外的使用 NOW、CURRENT_TIMESTAMP、LOCALTIME、LOCALTIMESTAMP 等函数作为 DATETIME 或者 TIMESTAMP 的默认值。BLOB、TEXT 以及 JSON 不可以设置默认值。如果一个列的定义中没有 DEFAULT 的设置。TiDB 按照如下的规则决定: 如果该类型可以使用 NULL 作为值,那么这个列会在定义时添加隐式的默认值设置 DEFAULT NULL。 如果该类型无法使用 NULL 作为值,那么这个列在定义时不会添加隐式的默认值设置。 对于一个设置了 NOT NULL 但是没有显式设置 DEFAULT 的列,当 INSERT、REPLACE 没有涉及到该列的值时,TiDB 根据当时的 SQL_MODE 进行不同的行为: 如果此时是 strict sql mode,在事务中的语句会导致事务失败并回滚,非事务中的语句会直接报错。 如果此时不是 strict sql mode,TiDB 会为这列赋值为列数据类型的隐式默认值。 此时隐式默认值的设置按照如下规则: 对于数值类型,它们的默认值是 0。当有 AUTO_INCREMENT 参数时,默认值会按照增量情况赋予正确的值。 对于除了时间戳外的日期时间类型,默认值会是该类型的“零值”。时间戳类型的默认值会是当前的时间。 对于除枚举以外的字符串类型,默认值会是空字符串。对于枚举类型,默认值是枚举中的第一个值。 "}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/datatype/", "title": "TiDB 数据类型", "content": " TiDB 数据类型 概述 TiDB 支持 MySQL 除空间类型之外的所有数据类型,包括数值型类型、字符串类型、时间&日期类型、Json 类型。数据类型定义一般为 T(M[, D]),其中: T 表示具体的类型 M 对于整数类型表示最大显示长度;对于浮点数或者定点数表示精度;对于字符类型表示最大长度。M 的最大值取决于具体的类型。 D 表示浮点数/定点数的小数位长度 对于时间&日期类型中的 TIME、DATETIME 以及 TIMESTAMP,定义中可以包含 Fsp 表示秒的精度,其取值范围是0到6,默认的精度为0 数值类型 概述 TiDB 支持 MySQL 所有的数值类型,按照精度可以分为: 整数类型(精确值) 浮点类型(近似值) 定点类型(精确值) 整数类型 TiDB 支持 MySQL 所有的整数类型,包括 INTEGER/INT、TINYINT、SMALLINT、MEDIUMINT 以及 BIGINT,完整信息参考这篇文档。类型定义 语法:BIT[(M)] > 比特值类型。M 表示比特位的长度,取值范围从1到64,其默认值是1。 TINYINT[(M)] [UNSIGNED] [ZEROFILL] > TINYINT 类型。有符号数的范围是[-128, 127]。无符号数的范围是[0, 255]。 BOOL, BOOLEAN > 布尔类型,和 TINYINT(1) 等价。零值被认为是 False,非零值认为是 True。在 TiDB 内部,True 存储为1, False 存储为0。 SMALLINT[(M)] [UNSIGNED] [ZEROFILL] > SMALLINT 类型。有符号数的范围是[-32768, 32767]。无符号数的范围是[0, 65535]。 MEDIUMINT[(M)] [UNSIGNED] [ZEROFILL] > MEDIUMINT 类型。有符号数的范围是[-8388608, 8388607]。无符号数的范围是[0, 16777215]。 INT[(M)] [UNSIGNED] [ZEROFILL] > INT 类型。 有符号数的范围是[-2147483648, 2147483647]。无符号数的范围是[0, 4294967295]。 INTEGER[(M)] [UNSIGNED] [ZEROFILL] > 和 INT 相同。 BIGINT[(M)] [UNSIGNED] [ZEROFILL] > BIGINT 类型。 有符号数的范围是[-9223372036854775808, 9223372036854775807]。无符号数的范围是[0, 18446744073709551615]。 字段意义: 语法元素 说明 M 类型长度,可选的 UNSIGNED 无符号数,如果不加这个标识,则为有符号数 ZEROFILL 补零标识,如果有这个标识,TiDB 会自动给类型增加 UNSIGNED 标识,但是没有做补零的操作 存储空间以及取值范围 每种类型对存储空间的需求以及最大/最小值如下表所示: 类型 存储空间 最小值(有符号/无符号) 最大值(有符号/无符号) TINYINT 1 -128 / 0 127 / 255 SMALLINT 2 -32768 / 0 32767 / 65535 MEDIUMINT 3 -8388608 / 0 8388607 / 16777215 INT 4 -2147483648 / 0 2147483647 / 4294967295 BIGINT 8 -9223372036854775808 / 0 9223372036854775807 / 18446744073709551615 浮点类型 TiDB 支持 MySQL 所有的浮点类型,包括 FLOAT、DOUBLE,完整信息参考这篇文档。类型定义 语法:FLOAT[(M,D)] [UNSIGNED] [ZEROFILL] > 单精度浮点数。允许的值范围为 -2^128 ~ +2^128,也即 -3.402823466E+38 到 -1.175494351E-38、0 和 1.175494351E-38 到 3.402823466E+38。这些是理论限制,基于 IEEE 标准。实际的范围根据硬件或操作系统的不同可能稍微小些。 DOUBLE[(M,D)] [UNSIGNED] [ZEROFILL] > 双精度浮点数。允许的值范围为:-2^1024 ~ +2^1024,也即是 -1.7976931348623157E+308 到 -2.2250738585072014E-308、0 和 2.2250738585072014E-308 到 1.7976931348623157E+308。这些是理论限制,基于 IEEE 标准。实际的范围根据硬件或操作系统的不同可能稍微小些。 DOUBLE PRECISION [(M,D)] [UNSIGNED] [ZEROFILL], REAL[(M,D)] [UNSIGNED] [ZEROFILL] > 为 DOUBLE 的同义词。 FLOAT(p) [UNSIGNED] [ZEROFILL] > 浮点数。p 表示精度(以位数表示),只使用该值来确定是否结果列的数据类型为 FLOAT 或 DOUBLE。如果 p 为从 0 到 24,数据类型变为没有 M 或 D 值的 FLOAT。如果 p 为从 25 到 53,数据类型变为没有 M 或 D 值的 DOUBLE。结果列范围与本节前面描述的单精度 FLOAT 或双精度 DOUBLE 数据类型相同。 字段意义: 语法元素 说明 M 小数总位数 D 小数点后位数 UNSIGNED 无符号数,如果不加这个标识,则为有符号数 ZEROFILL 补零标识,如果有这个标识,TiDB 会自动给类型增加 UNSIGNED 标识 存储空间 每种类型对存储空间的需求如下表所示: 类型 存储空间 FLOAT 4 FLOAT(p) 如果 0 <= p <= 24 为 4 个字节, 如果 25 <= p <= 53 为 8 个字节 DOUBLE 8 定点类型 TiDB 支持 MySQL 所有的浮点类型,包括 DECIMAL、NUMERIC,完整信息参考这篇文档。类型定义 语法:DECIMAL[(M[,D])] [UNSIGNED] [ZEROFILL] > 定点数。M 是小数位数(精度)的总数,D 是小数点(标度)后面的位数。小数点和‘-’(负数)符号不包括在M中。如果 D 是 0,则值没有小数点或分数部分。如果 D 被省略, 默认是 0。如果 M 被省略, 默认是 10。 NUMERIC[(M[,D])] [UNSIGNED] [ZEROFILL] > DECIMAL的同义词。 字段意义: 语法元素 说明 M 小数总位数 D 小数点后位数 UNSIGNED 无符号数,如果不加这个标识,则为有符号数 ZEROFILL 补零标识,如果有这个标识,TiDB 会自动给类型增加 UNSIGNED 标识 日期时间类型 概述 TiDB 支持 MySQL 所有的日期时间类型,包括 DATE、DATETIME、TIMESTAMP、TIME 以及 YEAR,完整信息参考这篇文档。类型定义 语法:DATE > 日期。支持的范围为`1000-01-01`到`9999-12-31`。以`YYYY-MM-DD`格式显示 DATE 值。 DATETIME[(fsp)] > 日期和时间的组合。支持的范围是`1000-01-01 00:00:00.000000`到`9999-12-31 23:59:59.000000`。 以`YYYY-MM-DD HH:MM:SS[.fraction]`格式显示 DATETIME 值。fsp 参数是表示秒精度,取值范围为 0-6,默认值取 0。 TIMESTAMP[(fsp)] > 时间戳。支持的范围是`1970-01-01 00:00:01.000000`到`2038-01-19 03:14:07.999999`。 fsp 参数是表示秒精度,取值范围为 0-6,默认值取 0。 TIME[(fsp)] > 时间。范围是`-838:59:59.000000`到`838:59:59.000000`。以`HH:MM:SS[.fraction]`格式显示 TIME 值。 fsp 参数是表示秒精度,取值范围为:0-6。默认值取 0。 YEAR[(2|4)] > 两位或四位格式的年。默认是四位格式。在四位格式中,允许的值是 1901 到 2155 和 0000。在两位格式中,允许的值是 70 到 69,表示从 1970 年到 2069 年。 字符串类型 概述 TiDB 支持 MySQL 所有的字符串类型,包括 CHAR、VARCHAR、BINARY、VARBINARY、BLOB、TEXT、ENUM 以及 SET, 完整信息参考这篇文档。类型定义 语法:[NATIONAL] CHAR[(M)] [CHARACTER SET charset_name] [COLLATE collation_name] > 定长字符串。CHAR 列的长度固定为创建表时声明的长度。长度可以为从 0 到 255 的任何值。当保存 CHAR 值时,在它们的右边填充空格以达到指定的长度。 [NATIONAL] VARCHAR(M) [CHARACTER SET charset_name] [COLLATE collation_name] > 变长字符串。M 表示最大列长度,范围是 0 到 65535。VARCHAR 的最大实际长度由最长的行的大小和使用的字符集确定。 BINARY(M) > 类似于 CHAR, 区别在于 BINARY 存储的是二进制字符串。 VARBINARY(M) > 类似于 VARCHAR, 区别在于 VARBINARY 存储的是二进制字符串。 BLOB[(M)] > 二进制大文件。M 表示最大列长度,范围是 0 到 65535。 TINYBLOB > 类似于 BLOB, 区别在于最大列长度为 255。 MEDIUMBLOB > 类似于 BLOB, 区别在于最大列长度为 16777215。 LONGBLOB > 类似于 BLOB, 区别在于最大列长度为 4294967295。 TEXT[(M)] [CHARACTER SET charset_name] [COLLATE collation_name] > 文本串。M 表示最大列长度,范围是 0 到 65535。TEXT 的最大实际长度由最长的行的大小和使用的字符集确定。 TINYTEXT[(M)] [CHARACTER SET charset_name] [COLLATE collation_name] > 类似于 TEXT, 区别在于最大列长度为 255。 MEDIUMTEXT [CHARACTER SET charset_name] [COLLATE collation_name] > 类似于 TEXT, 区别在于最大列长度为 16777215。 LONGTEXT [CHARACTER SET charset_name] [COLLATE collation_name] > 类似于 TEXT, 区别在于最大列长度为 4294967295。 ENUM('value1','value2',...) [CHARACTER SET charset_name] [COLLATE collation_name] > 枚举。只能有一个值的字符串对象,其值通常选自允许值列表中,在某些情况下也可以是空串或者 NULL。 SET('value1','value2',...) [CHARACTER SET charset_name] [COLLATE collation_name] > 集合。可以有零或者多个值的字符串对象,每一个值必须选自允许值列表中。 Json 类型 Json 类型可以存储 Json 这种半结构化的数据,相比于直接将 Json 存储为字符串,它的好处在于: 使用 Binary 格式进行序列化,对 Json 的内部字段的查询、解析加快; 多了 Json 合法性验证的步骤,只有合法的 Json 文档才可以放入这个字段中; Json 字段本身上,并不能创建索引。相反,可以对 Json 文档中的某个子字段创建索引。例如:CREATE TABLE city ( id INT PRIMARY KEY, detail JSON, population INT AS (JSON_EXTRACT(detail, '$.population') ); INSERT INTO city VALUES (1, '{"name": "Beijing", "population": 100}'); SELECT id FROM city WHERE population >= 100; 枚举类型 集合类型是一个字符串,其值必须是从一个固定集合中选取,这个固定集合在创建表的时候定义,语法是:ENUM('value1','value2',...) [CHARACTER SET charset_name] [COLLATE collation_name] # 例子 ENUM('apple', 'orange', 'pear') 枚举类型的值在 TiDB 内部使用数值来存储,每个值会按照定义的顺序转换为一个数字,比如上面的例子中,每个字符串值都会映射为一个数字: 值 数字 NULL NULL “ 0 ‘apple’ 1 ‘orange’ 2 ‘pear’ 3 更多信息参考 MySQL 枚举文档。集合类型 集合类型是一个包含零个或多个值的字符串,其中每个值必须是从一个固定集合中选取,这个固定集合在创建表的时候定义,语法是:SET('value1','value2',...) [CHARACTER SET charset_name] [COLLATE collation_name] # 例子 SET('1', '2') NOT NULL 上面的例子中,这列的有效值可以是:'' '1' '2' '1,2' 集合类型的值在 TiDB 内部会转换为一个 Int64 数值,每个元素是否存在用一个二进制位的 0/1 值来表示,比如这个例子 SET('a','b','c','d'),每一个元素都被映射为一个数字,且每个数字的二进制表示只会有一位是 1: 成员 十进制表示 二进制表示 ‘a’ 1 0001 ‘b’ 2 0010 ‘c’ 4 0100 ’d’ 8 1000 这样对于值为 ('a', 'c') 的元素,其二进制表示即为 0101。更多信息参考 MySQL 集合文档。数据类型的默认值 在一个数据类型描述中的 DEFAULT value 段描述了一个列的默认值。这个默认值必须是常量,不可以是一个函数或者是表达式。但是对于时间类型,可以例外的使用 NOW、CURRENT_TIMESTAMP、LOCALTIME、LOCALTIMESTAMP 等函数作为 DATETIME 或者 TIMESTAMP 的默认值。BLOB、TEXT 以及 JSON 不可以设置默认值。如果一个列的定义中没有 DEFAULT 的设置。TiDB 按照如下的规则决定: 如果该类型可以使用 NULL 作为值,那么这个列会在定义时添加隐式的默认值设置 DEFAULT NULL。 如果该类型无法使用 NULL 作为值,那么这个列在定义时不会添加隐式的默认值设置。 对于一个设置了 NOT NULL 但是没有显式设置 DEFAULT 的列,当 INSERT、REPLACE 没有涉及到该列的值时,TiDB 根据当时的 SQL_MODE 进行不同的行为: 如果此时是 strict sql mode,在事务中的语句会导致事务失败并回滚,非事务中的语句会直接报错。 如果此时不是 strict sql mode,TiDB 会为这列赋值为列数据类型的隐式默认值。 此时隐式默认值的设置按照如下规则: 对于数值类型,它们的默认值是 0。当有 AUTO_INCREMENT 参数时,默认值会按照增量情况赋予正确的值。 对于除了时间戳外的日期时间类型,默认值会是该类型的“零值”。时间戳类型的默认值会是当前的时间。 对于除枚举以外的字符串类型,默认值会是空字符串。对于枚举类型,默认值是枚举中的第一个值。 "}, {"url": "https://pingcap.com/docs-cn/architecture/", "title": "TiDB 整体架构", "content": " TiDB 整体架构 要深入了解 TiDB 的水平扩展和高可用特点,首先需要了解 TiDB 的整体架构。TiDB 集群主要包括三个核心组件:TiDB Server,PD Server 和 TiKV Server。此外,还有用于解决用户复杂 OLAP 需求的 TiSpark 组件。TiDB Server TiDB Server 负责接收 SQL 请求,处理 SQL 相关的逻辑,并通过 PD 找到存储计算所需数据的 TiKV 地址,与 TiKV 交互获取数据,最终返回结果。TiDB Server 是无状态的,其本身并不存储数据,只负责计算,可以无限水平扩展,可以通过负载均衡组件(如LVS、HAProxy 或 F5)对外提供统一的接入地址。PD Server Placement Driver (简称 PD) 是整个集群的管理模块,其主要工作有三个:一是存储集群的元信息(某个 Key 存储在哪个 TiKV 节点);二是对 TiKV 集群进行调度和负载均衡(如数据的迁移、Raft group leader 的迁移等);三是分配全局唯一且递增的事务 ID。PD 是一个集群,需要部署奇数个节点,一般线上推荐至少部署 3 个节点。TiKV Server TiKV Server 负责存储数据,从外部看 TiKV 是一个分布式的提供事务的 Key-Value 存储引擎。存储数据的基本单位是 Region,每个 Region 负责存储一个 Key Range(从 StartKey 到 EndKey 的左闭右开区间)的数据,每个 TiKV 节点会负责多个 Region。TiKV 使用 Raft 协议做复制,保持数据的一致性和容灾。副本以 Region 为单位进行管理,不同节点上的多个 Region 构成一个 Raft Group,互为副本。数据在多个 TiKV 之间的负载均衡由 PD 调度,这里也是以 Region 为单位进行调度。TiSpark TiSpark 作为 TiDB 中解决用户复杂 OLAP 需求的主要组件,将 Spark SQL 直接运行在 TiDB 存储层上,同时融合 TiKV 分布式集群的优势,并融入大数据社区生态。至此,TiDB 可以通过一套系统,同时支持 OLTP 与 OLAP,免除用户数据同步的烦恼。"}, {"url": "https://pingcap.com/docs-cn/features/", "title": "TiDB 核心特性", "content": " TiDB 核心特性 本文详细介绍 TiDB 的两大核心特性:水平扩展与高可用。水平扩展 无限水平扩展是 TiDB 的一大特点,这里说的水平扩展包括两方面:计算能力和存储能力。TiDB Server 负责处理 SQL 请求,随着业务的增长,可以简单的添加 TiDB Server 节点,提高整体的处理能力,提供更高的吞吐。TiKV 负责存储数据,随着数据量的增长,可以部署更多的 TiKV Server 节点解决数据 Scale 的问题。PD 会在 TiKV 节点之间以 Region 为单位做调度,将部分数据迁移到新加的节点上。所以在业务的早期,可以只部署少量的服务实例(推荐至少部署 3 个 TiKV, 3 个 PD,2 个 TiDB),随着业务量的增长,按照需求添加 TiKV 或者 TiDB 实例。高可用 高可用是 TiDB 的另一大特点,TiDB/TiKV/PD 这三个组件都能容忍部分实例失效,不影响整个集群的可用性。下面分别说明这三个组件的可用性、单个实例失效后的后果以及如何恢复。 TiDBTiDB 是无状态的,推荐至少部署两个实例,前端通过负载均衡组件对外提供服务。当单个实例失效时,会影响正在这个实例上进行的 Session,从应用的角度看,会出现单次请求失败的情况,重新连接后即可继续获得服务。单个实例失效后,可以重启这个实例或者部署一个新的实例。 PDPD 是一个集群,通过 Raft 协议保持数据的一致性,单个实例失效时,如果这个实例不是 Raft 的 leader,那么服务完全不受影响;如果这个实例是 Raft 的 leader,会重新选出新的 Raft leader,自动恢复服务。PD 在选举的过程中无法对外提供服务,这个时间大约是3秒钟。推荐至少部署三个 PD 实例,单个实例失效后,重启这个实例或者添加新的实例。 TiKVTiKV 是一个集群,通过 Raft 协议保持数据的一致性(副本数量可配置,默认保存三副本),并通过 PD 做负载均衡调度。单个节点失效时,会影响这个节点上存储的所有 Region。对于 Region 中的 Leader 结点,会中断服务,等待重新选举;对于 Region 中的 Follower 节点,不会影响服务。当某个 TiKV 节点失效,并且在一段时间内(默认 30 分钟)无法恢复,PD 会将其上的数据迁移到其他的 TiKV 节点上。 "}, {"url": "https://pingcap.com/docs-cn/releases/rn/", "title": "TiDB 版本发布历史", "content": " TiDB 版本发布历史 TiDB 历史版本发布声明如下: 2.0.11 2.1.2 2.0.10 2.1.1 2.1 GA 2.0.9 2.1 RC5 2.1 RC4 2.0.8 2.1 RC3 2.1 RC2 2.0.7 2.1 RC1 2.0.6 2.0.5 2.1 Beta 2.0.4 2.0.3 2.0.2 2.0.1 2.0 2.0 RC5 2.0 RC4 2.0 RC3 2.0 RC1 1.1 Beta 1.1 Alpha 1.0 Pre-GA RC4 RC3 RC2 RC1 "}, {"url": "https://pingcap.com/docs-cn/v1.0/releases/README/", "title": "TiDB 版本发布历史", "content": " TiDB 版本发布历史 TiDB 历史版本发布声明如下: 1.1 Beta 1.1 Alpha 1.0 Pre-GA RC4 RC3 RC2 RC1 "}, {"url": "https://pingcap.com/docs-cn/v2.0/releases/rn/", "title": "TiDB 版本发布历史", "content": " TiDB 版本发布历史 TiDB 历史版本发布声明如下: 2.0 RC4 2.0 RC3 2.0 RC1 1.1 Beta 1.1 Alpha 1.0 Pre-GA RC4 RC3 RC2 RC1 "}, {"url": "https://pingcap.com/docs-cn/sql/user-manual/", "title": "TiDB 用户文档", "content": " TiDB 用户文档 TiDB 支持 SQL92 标准并兼容 MySQL 语法,为了帮您更好地使用 TiDB, 该文档沿用了 MySQL 大部分的文档结构, 同时针对 TiDB 特有的功能作了详细的描述。TiDB 数据库管理 TiDB 服务 TiDB 进程启动参数 TiDB 数据目录 TiDB 系统数据库 TiDB 系统变量 TiDB 专用系统变量和语法 TiDB 服务器日志文件 TiDB 访问权限管理 TiDB 用户账户管理 使用加密连接 SQL 优化 理解 TiDB 执行计划 统计信息 语言结构 字面值 字符串字面值 数字字面值 NULL 值 十六进制字面值 date 和 time 字面值 布尔值 bit-val 字面值 数据库、表、索引、列和别名 关键字和保留字 用户变量 表达式语法 注释语法 字符集和时区 字符集支持 字符集配置 时区 数据类型 数值类型 日期和时间类型 字符串类型 JSON 数据类型 数据类型默认值 函数和操作符 函数和操作符概述 表达式求值的类型转换 操作符 控制流程函数 字符串函数 数值函数与操作符 日期和时间函数 位函数和操作符 Cast 函数和操作符 加密和压缩函数 信息函数 JSON 函数 信息函数 全局事务 ID 函数 [TBD] GROUP BY 聚合函数 其他函数 精度数学 SQL 语句语法 数据定义语句(DDL) 数据操作语句(DML) 事务语句 数据库管理语句 Prepared SQL 语句语法 实用工具语句 TiDB SQL 语法图 JSON 支持 JSON 支持 Connectors 和 API Connectors 和 API 错误码与故障诊断 错误码与故障诊断 与 MySQL 兼容性对比 与 MySQL 兼容性对比 "}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/bit-functions-and-operators/", "title": "TiDB 用户文档", "content": " 位函数和操作符 TiDB 中位函数和操作符的使用方法与 MySQL 基本一致,详情参见: Bit Functions and Operators。位函数和操作符表 函数和操作符名 功能描述 BIT_COUNT() 返回参数二进制表示中为 1 的个数 & 位与 ~ 按位取反 | 位或 0 位亦或 << 左移 >> 右移 "}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/cast-functions-and-operators/", "title": "TiDB 用户文档", "content": " Cast 函数和操作符 Cast 函数和操作符用于将某种数据类型的值转换为另一种数据类型。TiDB 中该函数和操作符的使用方法与 MySQL基本一致,详情参见: Cast Functions and Operators.Cast 函数和操作符表 函数和操作符名 功能描述 BINARY 将一个字符串转换成一个二进制字符串 CAST() 将一个值转换成一个确定类型 CONVERT() 将一个值转换成一个确定类型 "}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/date-and-time-functions/", "title": "TiDB 用户文档", "content": " 日期和时间函数 TiDB 中日期和时间函数的使用方法与 MySQL 基本一致,详情参见: Date and Time Functions.日期时间函数表 函数名 功能描述 ADDDATE() 将时间间隔添加到日期上 ADDTIME() 时间数值相加 CONVERT_TZ() 转换时区 CURDATE() 返回当前日期 CURRENT_DATE(), CURRENT_DATE 与 CURDATE() 同义 CURRENT_TIME(), CURRENT_TIME 与 CURTIME() 同义 CURRENT_TIMESTAMP(), CURRENT_TIMESTAMP 与 NOW() 同义 CURTIME() 返回当前时间 DATE() 从日期或日期/时间表达式中提取日期部分 DATE_ADD() 将时间间隔添加到日期上 DATE_FORMAT() 返回满足指定格式的日期/时间 DATE_SUB() 从日期减去指定的时间间隔 DATEDIFF() 返回两个日期间隔的天数 DAY() 与 DAYOFMONTH() 同义 DAYNAME() 返回星期名称 DAYOFMONTH() 返回参数对应的天数部分(1-31) DAYOFWEEK() 返回参数对应的星期下标 DAYOFYEAR() 返回参数代表一年的哪一天 (1-366) EXTRACT() 提取日期/时间中的单独部分 FROM_DAYS() 将天数转化为日期 FROM_UNIXTIME() 将 Unix 时间戳格式化为日期 GET_FORMAT() 返回满足日期格式的字符串 HOUR() 提取日期/时间表达式中的小时部分 LAST_DAY 返回参数中月份的最后一天 LOCALTIME(), LOCALTIME 与 NOW() 同义 LOCALTIMESTAMP, LOCALTIMESTAMP() 与 NOW() 同义 MAKEDATE() 根据给定的年份和一年中的天数生成一个日期 MAKETIME() 根据给定的时、分、秒生成一个时间 MICROSECOND() 返回参数的微秒部分 MINUTE() 返回参数的分钟部分 MONTH() 返回参数的月份部分 MONTHNAME() 返回参数的月份名称 NOW() 返回当前日期和时间 PERIOD_ADD() 在年-月表达式上添加一段时间(数个月) PERIOD_DIFF() 返回间隔的月数 QUARTER() 返回参数对应的季度(1-4) SEC_TO_TIME() 将秒数转化为 ‘HH:MM:SS’ 的格式 SECOND() 返回秒数(0-59) STR_TO_DATE() 将字符串转化为日期 SUBDATE() 当传入三个参数时作为 DATE_SUB() 的同义 SUBTIME() 从一个时间中减去一段时间 SYSDATE() 返回该方法执行时的时间 TIME() 返回参数的时间表达式部分 TIME_FORMAT() 格式化时间 TIME_TO_SEC() 返回参数对应的秒数 TIMEDIFF() 返回时间间隔 TIMESTAMP() 传入一个参数时候,该方法返回日期或日期/时间表达式, 传入两个参数时候, 返回参数的和 TIMESTAMPADD() 在日期/时间表达式上增加一段时间间隔 TIMESTAMPDIFF() 从日期/时间表达式中减去一段时间间隔 TO_DAYS() 将参数转化对应的天数(从第 0 年开始) TO_SECONDS() 将日期或日期/时间参数转化为秒数(从第 0 年开始) UNIX_TIMESTAMP() 返回一个 Unix 时间戳 UTC_DATE() 返回当前的 UTC 日期 UTC_TIME() 返回当前的 UTC 时间 UTC_TIMESTAMP() 返回当前的 UTC 日期和时间 WEEK() 返回参数所在的一年中的星期数 WEEKDAY() 返回星期下标 WEEKOFYEAR() 返回参数在日历中对应的一年中的星期数 YEAR() 返回参数对应的年数 YEARWEEK() 返回年数和星期数 "}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/functions-and-operators-reference/", "title": "TiDB 用户文档", "content": " 函数和操作符概述 TiDB 中函数和操作符使用方法与 MySQL 基本一致, 详情参见: Functions and Operators在 SQL 语句中, 表达式可用于诸如 SELECT 语句的 ORDER BY 或 HAVING 子句, SELECT/ DELETE/ UPDATE 语句的 WHERE 子句, 或 SET 语句之类的地方.可使用字面值, 列名, NULL, 内置函数, 操作符等来书写表达式."}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/information-functions/", "title": "TiDB 用户文档", "content": " 信息函数 TiDB 中信息函数的使用方法与 MySQL 基本一致,详情参见: Information Functions.信息函数表 函数名 功能描述 CONNECTION_ID() 返回当前连接的连接 ID (线程 ID) CURRENT_USER(), CURRENT_USER 返回当前用户的用户名和主机名 DATABASE() 返回默认(当前)的数据库名 FOUND_ROWS() 该函数返回对于一个包含 LIMIT 的 SELECT 查询语句,在不包含 LIMIT 的情况下回返回的记录数 LAST_INSERT_ID() 返回最后一条 INSERT 语句中自增列的值 SCHEMA() 与 DATABASE() 同义 SESSION_USER() 与 USER() 同义 SYSTEM_USER() 与 USER() 同义 USER() 返回客户端提供的用户名和主机名 VERSION() 返回当前 MySQL 服务器的版本信息 TIDB_VERSION 返回当前 TiDB 服务器的版本信息 "}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/operators/", "title": "TiDB 用户文档", "content": " 操作符 操作符名 功能描述 AND, && 逻辑与 = 赋值 (可用于 SET 语句中, 或用于 UPDATE 语句的 SET 中 ) := 赋值 BETWEEN ... AND ... 判断值满足范围 BINARY 将一个字符串转换为一个二进制字符串 & 位与 ~ 位非 | 位或 ^ 按位异或 CASE case 操作符 DIV 整数除 / 除法 = 相等比较 <=> 空值安全型相等比较 > 大于 >= 大于或等于 IS 判断一个值是否等于一个布尔值 IS NOT 判断一个值是否不等于一个布尔值 IS NOT NULL 非空判断 IS NULL 空值判断 << 左移 < 小于 <= 小于或等于 LIKE 简单模式匹配 - 减 %, MOD 求余 NOT, ! 取反 NOT BETWEEN ... AND ... 判断值是否不在范围内 !=, <> 不等于 NOT LIKE 不符合简单模式匹配 NOT REGEXP 不符合正则表达式模式匹配 ||, OR 逻辑或 + 加 REGEXP 使用正则表达式进行模式匹配 >> 右移 RLIKE REGEXP 同义词 * 乘 - 取反符号 XOR 逻辑亦或 操作符优先级 操作符优先级显示在以下列表中,从最高优先级到最低优先级。同一行显示的操作符具有相同的优先级。INTERVAL BINARY ! - (unary minus), ~ (unary bit inversion) ^ *, /, DIV, %, MOD -, + <<, >> & | = (comparison), <=>, >=, >, <=, <, <>, !=, IS, LIKE, REGEXP, IN BETWEEN, CASE, WHEN, THEN, ELSE NOT AND, && XOR OR, || = (assignment), := 详情参见 这里.比较方法和操作符 操作符名 功能描述 BETWEEN ... AND ... 判断值是否在范围内 COALESCE() 返回第一个非空值 = 相等比较 <=> 空值安全型相等比较 > 大于 >= 大于或等于 GREATEST() 返回最大值 IN() 判断值是否在一个值的集合内 INTERVAL() 返回一个小于第一个参数的参数的下标 IS 判断是否等于一个布尔值 IS NOT 判断是否不等于一个布尔值 IS NOT NULL 非空判断 IS NULL 空值判断 ISNULL() 判断参数是否为空 LEAST() 返回最小值 < 小于 <= 小于或等于 LIKE 简单模式匹配 NOT BETWEEN ... AND ... 判断值是否不在范围内 !=, <> 不等于 NOT IN() 判断值是否不在一个值的集合内 NOT LIKE 不满足简单模式匹配 STRCMP() 比较两个字符串 详情参见 这里.逻辑操作符 操作符名 功能描述 AND, && 逻辑与 NOT, ! 逻辑非 ||, OR 逻辑或 XOR 逻辑亦或 详情参见 这里.赋值操作符 操作符名 功能描述 = 赋值 (可用于 SET 语句中, 或用于 UPDATE 语句的 SET 中 ) := 赋值 详情参见 这里."}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/precision-math/", "title": "TiDB 用户文档", "content": " 精度数学 TiDB 中精度数学计算与 MySQL 中基本一致, 详情请参见: Precision Math. 数值类型 DECIMAL 数据类型的特性 数值类型 精确数值运算的范围包括精确值数据类型(整型和 DECIMAL 类型), 以及精确值数字字面量. 近似值数据类型和近似值数字字面量被作为浮点数来处理.精确值数字字面量包含整数部分或小数部分, 或二者都包含. 精确值数字字面量可以包含符号位. 例如: 1, .2, 3.4, -5, -6.78, +9.10.近似值数字字面量以一个包含尾数和指数的科学计数法表示(基数为 10). 其中尾数和指数可以分别或同时带有符号位. 例如: 1.2E3, 1.2E-3, -1.2E3, -1.2E-3.两个看起来相似的数字可能会被以不同的方式进行处理. 例如, 2.34 是精确值(定点数), 而 2.3E0 是近似值(浮点数).DECIMAL 数据类型是定点数类型, 其运算是精确计算. FLOAT 和 DOUBLE 数据类型是浮点类型, 其运算是近似计算.DECIMAL 数据类型的特性 本节讨论 DECIMAL 数据类型的特性, 主要涉及以下几点: 最大位数 存储格式 存储要求 DECIMAL 列的声明语法为 DECIMAL(M, D). 其中参数值意义及其范围如下: M 表示最大的数字位数 (精度). 1<= M <= 65. D 表示小数点右边数字的位数 (标度). 1 <= D <= 30 且 不大于 M. M 的最大值 65 表示 DECIMAL 值的计算精确到 65 位数字. 该精度同样适用于其精确值字面量.DECIMAL 列的值采用二进制进行存储, 其将每 9 位十进制数字包装成 4 个字节. 其中整数和小数部分分别确定所需的存储空间. 如果数字位数为 9 的倍数, 则每 9 位十进制数字各采用 4 个字节进行存储, 对于剩余不足 9 位的数字, 所需的存储空间如下表所示. 剩余数字位数 存储所需字节数 0 0 1–2 1 3–4 2 5–6 3 7–9 4 例如, 定义类型为 DECIMAL(18, 9) 的列, 其小数点两侧均各包含 9 位十进制数字, 因此, 分别需要 4 个字节的存储空间. 定义类型为 DECIMAL(20, 6) 的列, 其小数部分包含 6 位十进制数字, 整数部分包含 14 位十进制数字. 整数部分中 9 位数字需要 4 个字节进行存储, 其余 5 位数字需要 3 个字节进行存储. 小数部分 6 位数字需要 3 个字节进行存储.DECIMAL 列不存储前导的字符 + 或字符 - 或数字 0. 如果将 +0003.1 插入到 DECIMAL(5, 1) 列中, 则将其存储为3.1. 对于负数, 不存储字符 - 的字面值.DECIMAL 列不允许插入大于列定义的隐含范围的值. 例如, DECIMAL(3, 0) 列范围为 -999 到 999. DECIMAL(M, D) 列小数点左边部分最多支持 M-D 位数字.有关 DECIMAL 值的内部格式完整说明, 请参阅 TiDB 源码文件 types/mydecimal.go.表达式计算 在涉及精度数学计算的表达式中,TiDB 会尽可能不做任何修改的使用每个输入的数值。比如:在计算比较函数时,参与运算的数字将不做任何改变。在严格 SQL 模式下,向一个数据列插入一个值时,如果该值处于这一列的值域范围内,这个值将直接不做任何修改的直接插入进去,提取这个值的时候,取得的值和插入的值将会是同一个值。当处于非严格 SQL 模式时,TiDB 会允许数据插入过程中发生的数据截断。处理数值类型表达式取决于这个表达式参数的具体值: 当表达式参数中包含近似值时,这个表达式的结果也是近似值,TiDB 会使用浮点数对应的计算逻辑返回一个浮点数的结果 当表达式参数中不包含任何近似值时(也就是说表达式的参数全部是精确值),如果某个精确值包含小数部分,TIDB 会对这个表达式使用 DECIMAL 对应的计算逻辑,返回一个 DECIMAL 的结果,精确到 65 位数字 其他情况下,表达式只会包含整数参数,这个表达式的结果也是精确的,TiDB 会使用整数对应的计算逻辑返回一个整数结果,精度和 BIGINT 保持一致(64位) 如果数值类型表达式中包含字符串参数,这些字符串参数将被转换成双精度浮点数,这个表达式的计算结果将是个近似值。向一个数值类型列插入数据的具体行为会受到 SQL 模式的影响。接下来的讨论将围绕严格模式以及 ERROR_FOR_DIVISION_BY_ZERO 模式展开,如果要打开所有的限制,可以简单的使用 TRADITIONAL 模式,这个模式将同时使用严格模式以及 ERROR_FOR_DIVISION_BY_ZERO 模式:SET sql_mode = 'TRADITIONAL`; 向一个具有精确值类型(DECIMAL 或者整数类型)的列插入数据时,如果插入的数据位于该列的值域范围内将使用该数据的精确值。如果该数据的小数部分太长,将会发生数值修约,这时会有 warning 产生,具体内容可以看”数值修约”。如果该数据整数部分太长: 如果没有开启严格模式,这个值会被截断并产生一个 warning 如果开启了严格模式,将会产生一个数据溢出的 error 如果向一个数值类型列插入字符串,如果该字符串中包含非数值部分,TiDB 将这样做类型转换: 在严格模式下,没有以数字开头的字符串(即使是一个空字符串)不能被被用作数字值并会返回一个 error 或者是 warning; 以数字开头的字符串可以被转换,不过末尾的非数字部分会被截断。如果被截断的部分包含的不全是空格,在严格模式下这回产生一个 error 或者 warning 默认情况下,如果计算的过程中发生了除数是 0 的现象将会得到一个 NULL 结果,并且不会有 warning 产生。通过设置适当的 SQL 模式,除以 0 的操作可以被限制:当设置 ERROR_FOR_DIVISION_BY_ZERO SQL 模式时,TiDB 的行为是: 如果设置了严格 SQL 模式,INSERT 和 UPDATE 的过程中如果发生了除以 0 的操作,正在进行的 INSERT 或者 UPDATE 操作会被禁止,并且会返回一个 error 如果没有设置严格 SQL 模式,除以 0 的操作仅会返回一个 warning 假设我们有如下的 SQL 语句:INSERT INTO t SET i = 1/0; 不同的 SQL 模式将会导致不同的结果如下: sql_mode 的值 结果 “ 没有 warning,没有 error,i 被设为 NULL strict 没有 warning,没有 error,i 被设为 NULL ERROR_FOR_DIVISION_BY_ZERO 有 warning,没有 error,i 被设为 NULL strict, ERROR_FOR_DIVISION_BY_ZERO 有 error,插入失败 数值修约 round() 函数的结果取决于他的参数是否是精确值: 如果参数是精确值,round() 函数将使用四舍五入的规则 如果参数是一个近似值,round() 表达式的结果可能和 MySQL 不太一样 TiDB > SELECT ROUND(2.5), ROUND(25E-1); +------------+--------------+ | ROUND(2.5) | ROUND(25E-1) | +------------+--------------+ | 3 | 3 | +------------+--------------+ 1 row in set (0.00 sec) 向一个 DECIMAL 或者整数类型列插入数据时,round 的规则将采用 round half away from zero 的方式:TiDB > CREATE TABLE t (d DECIMAL(10,0)); Query OK, 0 rows affected (0.01 sec) TiDB > INSERT INTO t VALUES(2.5),(2.5E0); Query OK, 2 rows affected, 2 warnings (0.00 sec) TiDB > SELECT d FROM t; +------+ | d | +------+ | 3 | | 3 | +------+ 2 rows in set (0.00 sec)"}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/user-manual/", "title": "TiDB 用户文档", "content": " TiDB 用户文档 TiDB 支持 SQL92 标准并兼容 MySQL 语法,为了帮您更好地使用 TiDB, 该文档沿用了 MySQL 大部分的文档结构, 同时针对 TiDB 特有的功能作了详细的描述。TiDB 数据库管理 TiDB 服务 TiDB 进程启动参数 TiDB 数据目录 TiDB 系统数据库 TiDB 系统变量 TiDB 专用系统变量和语法 TiDB 服务器日志文件 TiDB 访问权限管理 TiDB 用户账户管理 使用加密连接 SQL 优化 理解 TiDB 执行计划 统计信息 语言结构 字面值 字符串字面值 数字字面值 NULL 值 十六进制字面值 date 和 time 字面值 布尔值 bit-val 字面值 数据库、表、索引、列和别名 关键字和保留字 用户变量 表达式语法 注释语法 字符集和时区 字符集支持 字符集配置 时区 数据类型 数值类型 日期和时间类型 字符串类型 JSON 数据类型 数据类型默认值 函数和操作符 函数和操作符概述 表达式求值的类型转换 操作符 控制流程函数 字符串函数 数值函数与操作符 日期和时间函数 位函数和操作符 Cast 函数和操作符 加密和压缩函数 信息函数 JSON 函数 信息函数 全局事务 ID 函数 [TBD] GROUP BY 聚合函数 其他函数 精度数学 SQL 语句语法 数据定义语句(DDL) 数据操作语句(DML) 事务语句 数据库管理语句 Prepared SQL 语句语法 实用工具语句 TiDB SQL 语法图 JSON 支持 JSON 支持 Connectors 和 API Connectors 和 API 错误码与故障诊断 错误码与故障诊断 与 MySQL 兼容性对比 与 MySQL 兼容性对比 "}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/bit-functions-and-operators/", "title": "TiDB 用户文档", "content": " 位函数和操作符 TiDB 中位函数和操作符的使用方法与 MySQL 基本一致,详情参见: Bit Functions and Operators。位函数和操作符表 函数和操作符名 功能描述 BIT_COUNT() 返回参数二进制表示中为 1 的个数 & 位与 ~ 按位取反 | 位或 0 位亦或 << 左移 >> 右移 "}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/cast-functions-and-operators/", "title": "TiDB 用户文档", "content": " Cast 函数和操作符 Cast 函数和操作符用于将某种数据类型的值转换为另一种数据类型。TiDB 中该函数和操作符的使用方法与 MySQL基本一致,详情参见: Cast Functions and Operators.Cast 函数和操作符表 函数和操作符名 功能描述 BINARY 将一个字符串转换成一个二进制字符串 CAST() 将一个值转换成一个确定类型 CONVERT() 将一个值转换成一个确定类型 "}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/date-and-time-functions/", "title": "TiDB 用户文档", "content": " 日期和时间函数 TiDB 中日期和时间函数的使用方法与 MySQL 基本一致,详情参见: Date and Time Functions.日期时间函数表 函数名 功能描述 ADDDATE() 将时间间隔添加到日期上 ADDTIME() 时间数值相加 CONVERT_TZ() 转换时区 CURDATE() 返回当前日期 CURRENT_DATE(), CURRENT_DATE 与 CURDATE() 同义 CURRENT_TIME(), CURRENT_TIME 与 CURTIME() 同义 CURRENT_TIMESTAMP(), CURRENT_TIMESTAMP 与 NOW() 同义 CURTIME() 返回当前时间 DATE() 从日期或日期/时间表达式中提取日期部分 DATE_ADD() 将时间间隔添加到日期上 DATE_FORMAT() 返回满足指定格式的日期/时间 DATE_SUB() 从日期减去指定的时间间隔 DATEDIFF() 返回两个日期间隔的天数 DAY() 与 DAYOFMONTH() 同义 DAYNAME() 返回星期名称 DAYOFMONTH() 返回参数对应的天数部分(1-31) DAYOFWEEK() 返回参数对应的星期下标 DAYOFYEAR() 返回参数代表一年的哪一天 (1-366) EXTRACT() 提取日期/时间中的单独部分 FROM_DAYS() 将天数转化为日期 FROM_UNIXTIME() 将 Unix 时间戳格式化为日期 GET_FORMAT() 返回满足日期格式的字符串 HOUR() 提取日期/时间表达式中的小时部分 LAST_DAY 返回参数中月份的最后一天 LOCALTIME(), LOCALTIME 与 NOW() 同义 LOCALTIMESTAMP, LOCALTIMESTAMP() 与 NOW() 同义 MAKEDATE() 根据给定的年份和一年中的天数生成一个日期 MAKETIME() 根据给定的时、分、秒生成一个时间 MICROSECOND() 返回参数的微秒部分 MINUTE() 返回参数的分钟部分 MONTH() 返回参数的月份部分 MONTHNAME() 返回参数的月份名称 NOW() 返回当前日期和时间 PERIOD_ADD() 在年-月表达式上添加一段时间(数个月) PERIOD_DIFF() 返回间隔的月数 QUARTER() 返回参数对应的季度(1-4) SEC_TO_TIME() 将秒数转化为 ‘HH:MM:SS’ 的格式 SECOND() 返回秒数(0-59) STR_TO_DATE() 将字符串转化为日期 SUBDATE() 当传入三个参数时作为 DATE_SUB() 的同义 SUBTIME() 从一个时间中减去一段时间 SYSDATE() 返回该方法执行时的时间 TIME() 返回参数的时间表达式部分 TIME_FORMAT() 格式化时间 TIME_TO_SEC() 返回参数对应的秒数 TIMEDIFF() 返回时间间隔 TIMESTAMP() 传入一个参数时候,该方法返回日期或日期/时间表达式, 传入两个参数时候, 返回参数的和 TIMESTAMPADD() 在日期/时间表达式上增加一段时间间隔 TIMESTAMPDIFF() 从日期/时间表达式中减去一段时间间隔 TO_DAYS() 将参数转化对应的天数(从第 0 年开始) TO_SECONDS() 将日期或日期/时间参数转化为秒数(从第 0 年开始) UNIX_TIMESTAMP() 返回一个 Unix 时间戳 UTC_DATE() 返回当前的 UTC 日期 UTC_TIME() 返回当前的 UTC 时间 UTC_TIMESTAMP() 返回当前的 UTC 日期和时间 WEEK() 返回参数所在的一年中的星期数 WEEKDAY() 返回星期下标 WEEKOFYEAR() 返回参数在日历中对应的一年中的星期数 YEAR() 返回参数对应的年数 YEARWEEK() 返回年数和星期数 "}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/functions-and-operators-reference/", "title": "TiDB 用户文档", "content": " 函数和操作符概述 TiDB 中函数和操作符使用方法与 MySQL 基本一致, 详情参见: Functions and Operators在 SQL 语句中, 表达式可用于诸如 SELECT 语句的 ORDER BY 或 HAVING 子句, SELECT/ DELETE/ UPDATE 语句的 WHERE 子句, 或 SET 语句之类的地方.可使用字面值, 列名, NULL, 内置函数, 操作符等来书写表达式."}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/information-functions/", "title": "TiDB 用户文档", "content": " 信息函数 TiDB 中信息函数的使用方法与 MySQL 基本一致,详情参见: Information Functions.信息函数表 函数名 功能描述 CONNECTION_ID() 返回当前连接的连接 ID (线程 ID) CURRENT_USER(), CURRENT_USER 返回当前用户的用户名和主机名 DATABASE() 返回默认(当前)的数据库名 FOUND_ROWS() 该函数返回对于一个包含 LIMIT 的 SELECT 查询语句,在不包含 LIMIT 的情况下回返回的记录数 LAST_INSERT_ID() 返回最后一条 INSERT 语句中自增列的值 SCHEMA() 与 DATABASE() 同义 SESSION_USER() 与 USER() 同义 SYSTEM_USER() 与 USER() 同义 USER() 返回客户端提供的用户名和主机名 VERSION() 返回当前 MySQL 服务器的版本信息 TIDB_VERSION 返回当前 TiDB 服务器的版本信息 "}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/operators/", "title": "TiDB 用户文档", "content": " 操作符 操作符名 功能描述 AND, && 逻辑与 = 赋值 (可用于 SET 语句中, 或用于 UPDATE 语句的 SET 中 ) := 赋值 BETWEEN ... AND ... 判断值满足范围 BINARY 将一个字符串转换为一个二进制字符串 & 位与 ~ 位非 | 位或 ^ 按位异或 CASE case 操作符 DIV 整数除 / 除法 = 相等比较 <=> 空值安全型相等比较 > 大于 >= 大于或等于 IS 判断一个值是否等于一个布尔值 IS NOT 判断一个值是否不等于一个布尔值 IS NOT NULL 非空判断 IS NULL 空值判断 << 左移 < 小于 <= 小于或等于 LIKE 简单模式匹配 - 减 %, MOD 求余 NOT, ! 取反 NOT BETWEEN ... AND ... 判断值是否不在范围内 !=, <> 不等于 NOT LIKE 不符合简单模式匹配 NOT REGEXP 不符合正则表达式模式匹配 ||, OR 逻辑或 + 加 REGEXP 使用正则表达式进行模式匹配 >> 右移 RLIKE REGEXP 同义词 * 乘 - 取反符号 XOR 逻辑亦或 操作符优先级 操作符优先级显示在以下列表中,从最高优先级到最低优先级。同一行显示的操作符具有相同的优先级。INTERVAL BINARY ! - (unary minus), ~ (unary bit inversion) ^ *, /, DIV, %, MOD -, + <<, >> & | = (comparison), <=>, >=, >, <=, <, <>, !=, IS, LIKE, REGEXP, IN BETWEEN, CASE, WHEN, THEN, ELSE NOT AND, && XOR OR, || = (assignment), := 详情参见 这里.比较方法和操作符 操作符名 功能描述 BETWEEN ... AND ... 判断值是否在范围内 COALESCE() 返回第一个非空值 = 相等比较 <=> 空值安全型相等比较 > 大于 >= 大于或等于 GREATEST() 返回最大值 IN() 判断值是否在一个值的集合内 INTERVAL() 返回一个小于第一个参数的参数的下标 IS 判断是否等于一个布尔值 IS NOT 判断是否不等于一个布尔值 IS NOT NULL 非空判断 IS NULL 空值判断 ISNULL() 判断参数是否为空 LEAST() 返回最小值 < 小于 <= 小于或等于 LIKE 简单模式匹配 NOT BETWEEN ... AND ... 判断值是否不在范围内 !=, <> 不等于 NOT IN() 判断值是否不在一个值的集合内 NOT LIKE 不满足简单模式匹配 STRCMP() 比较两个字符串 详情参见 这里.逻辑操作符 操作符名 功能描述 AND, && 逻辑与 NOT, ! 逻辑非 ||, OR 逻辑或 XOR 逻辑亦或 详情参见 这里.赋值操作符 操作符名 功能描述 = 赋值 (可用于 SET 语句中, 或用于 UPDATE 语句的 SET 中 ) := 赋值 详情参见 这里."}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/precision-math/", "title": "TiDB 用户文档", "content": " 精度数学 TiDB 中精度数学计算与 MySQL 中基本一致, 详情请参见: Precision Math. 数值类型 DECIMAL 数据类型的特性 数值类型 精确数值运算的范围包括精确值数据类型(整型和 DECIMAL 类型), 以及精确值数字字面量. 近似值数据类型和近似值数字字面量被作为浮点数来处理.精确值数字字面量包含整数部分或小数部分, 或二者都包含. 精确值数字字面量可以包含符号位. 例如: 1, .2, 3.4, -5, -6.78, +9.10.近似值数字字面量以一个包含尾数和指数的科学计数法表示(基数为 10). 其中尾数和指数可以分别或同时带有符号位. 例如: 1.2E3, 1.2E-3, -1.2E3, -1.2E-3.两个看起来相似的数字可能会被以不同的方式进行处理. 例如, 2.34 是精确值(定点数), 而 2.3E0 是近似值(浮点数).DECIMAL 数据类型是定点数类型, 其运算是精确计算. FLOAT 和 DOUBLE 数据类型是浮点类型, 其运算是近似计算.DECIMAL 数据类型的特性 本节讨论 DECIMAL 数据类型的特性, 主要涉及以下几点: 最大位数 存储格式 存储要求 DECIMAL 列的声明语法为 DECIMAL(M, D). 其中参数值意义及其范围如下: M 表示最大的数字位数 (精度). 1<= M <= 65. D 表示小数点右边数字的位数 (标度). 1 <= D <= 30 且 不大于 M. M 的最大值 65 表示 DECIMAL 值的计算精确到 65 位数字. 该精度同样适用于其精确值字面量.DECIMAL 列的值采用二进制进行存储, 其将每 9 位十进制数字包装成 4 个字节. 其中整数和小数部分分别确定所需的存储空间. 如果数字位数为 9 的倍数, 则每 9 位十进制数字各采用 4 个字节进行存储, 对于剩余不足 9 位的数字, 所需的存储空间如下表所示. 剩余数字位数 存储所需字节数 0 0 1–2 1 3–4 2 5–6 3 7–9 4 例如, 定义类型为 DECIMAL(18, 9) 的列, 其小数点两侧均各包含 9 位十进制数字, 因此, 分别需要 4 个字节的存储空间. 定义类型为 DECIMAL(20, 6) 的列, 其小数部分包含 6 位十进制数字, 整数部分包含 14 位十进制数字. 整数部分中 9 位数字需要 4 个字节进行存储, 其余 5 位数字需要 3 个字节进行存储. 小数部分 6 位数字需要 3 个字节进行存储.DECIMAL 列不存储前导的字符 + 或字符 - 或数字 0. 如果将 +0003.1 插入到 DECIMAL(5, 1) 列中, 则将其存储为3.1. 对于负数, 不存储字符 - 的字面值.DECIMAL 列不允许插入大于列定义的隐含范围的值. 例如, DECIMAL(3, 0) 列范围为 -999 到 999. DECIMAL(M, D) 列小数点左边部分最多支持 M-D 位数字.有关 DECIMAL 值的内部格式完整说明, 请参阅 TiDB 源码文件 types/mydecimal.go.表达式计算 在涉及精度数学计算的表达式中,TiDB 会尽可能不做任何修改的使用每个输入的数值。比如:在计算比较函数时,参与运算的数字将不做任何改变。在严格 SQL 模式下,向一个数据列插入一个值时,如果该值处于这一列的值域范围内,这个值将直接不做任何修改的直接插入进去,提取这个值的时候,取得的值和插入的值将会是同一个值。当处于非严格 SQL 模式时,TiDB 会允许数据插入过程中发生的数据截断。处理数值类型表达式取决于这个表达式参数的具体值: 当表达式参数中包含近似值时,这个表达式的结果也是近似值,TiDB 会使用浮点数对应的计算逻辑返回一个浮点数的结果 当表达式参数中不包含任何近似值时(也就是说表达式的参数全部是精确值),如果某个精确值包含小数部分,TIDB 会对这个表达式使用 DECIMAL 对应的计算逻辑,返回一个 DECIMAL 的结果,精确到 65 位数字 其他情况下,表达式只会包含整数参数,这个表达式的结果也是精确的,TiDB 会使用整数对应的计算逻辑返回一个整数结果,精度和 BIGINT 保持一致(64位) 如果数值类型表达式中包含字符串参数,这些字符串参数将被转换成双精度浮点数,这个表达式的计算结果将是个近似值。向一个数值类型列插入数据的具体行为会受到 SQL 模式的影响。接下来的讨论将围绕严格模式以及 ERROR_FOR_DIVISION_BY_ZERO 模式展开,如果要打开所有的限制,可以简单的使用 TRADITIONAL 模式,这个模式将同时使用严格模式以及 ERROR_FOR_DIVISION_BY_ZERO 模式:SET sql_mode = 'TRADITIONAL`; 向一个具有精确值类型(DECIMAL 或者整数类型)的列插入数据时,如果插入的数据位于该列的值域范围内将使用该数据的精确值。如果该数据的小数部分太长,将会发生数值修约,这时会有 warning 产生,具体内容可以看”数值修约”。如果该数据整数部分太长: 如果没有开启严格模式,这个值会被截断并产生一个 warning 如果开启了严格模式,将会产生一个数据溢出的 error 如果向一个数值类型列插入字符串,如果该字符串中包含非数值部分,TiDB 将这样做类型转换: 在严格模式下,没有以数字开头的字符串(即使是一个空字符串)不能被被用作数字值并会返回一个 error 或者是 warning; 以数字开头的字符串可以被转换,不过末尾的非数字部分会被截断。如果被截断的部分包含的不全是空格,在严格模式下这回产生一个 error 或者 warning 默认情况下,如果计算的过程中发生了除数是 0 的现象将会得到一个 NULL 结果,并且不会有 warning 产生。通过设置适当的 SQL 模式,除以 0 的操作可以被限制:当设置 ERROR_FOR_DIVISION_BY_ZERO SQL 模式时,TiDB 的行为是: 如果设置了严格 SQL 模式,INSERT 和 UPDATE 的过程中如果发生了除以 0 的操作,正在进行的 INSERT 或者 UPDATE 操作会被禁止,并且会返回一个 error 如果没有设置严格 SQL 模式,除以 0 的操作仅会返回一个 warning 假设我们有如下的 SQL 语句:INSERT INTO t SET i = 1/0; 不同的 SQL 模式将会导致不同的结果如下: sql_mode 的值 结果 “ 没有 warning,没有 error,i 被设为 NULL strict 没有 warning,没有 error,i 被设为 NULL ERROR_FOR_DIVISION_BY_ZERO 有 warning,没有 error,i 被设为 NULL strict, ERROR_FOR_DIVISION_BY_ZERO 有 error,插入失败 数值修约 round() 函数的结果取决于他的参数是否是精确值: 如果参数是精确值,round() 函数将使用四舍五入的规则 如果参数是一个近似值,round() 表达式的结果可能和 MySQL 不太一样 TiDB > SELECT ROUND(2.5), ROUND(25E-1); +------------+--------------+ | ROUND(2.5) | ROUND(25E-1) | +------------+--------------+ | 3 | 3 | +------------+--------------+ 1 row in set (0.00 sec) 向一个 DECIMAL 或者整数类型列插入数据时,round 的规则将采用 round half away from zero 的方式:TiDB > CREATE TABLE t (d DECIMAL(10,0)); Query OK, 0 rows affected (0.01 sec) TiDB > INSERT INTO t VALUES(2.5),(2.5E0); Query OK, 2 rows affected, 2 warnings (0.00 sec) TiDB > SELECT d FROM t; +------+ | d | +------+ | 3 | | 3 | +------+ 2 rows in set (0.00 sec)"}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/user-manual/", "title": "TiDB 用户文档", "content": " TiDB 用户文档 TiDB 支持 SQL92 标准并兼容 MySQL 语法,为了帮您更好地使用 TiDB, 该文档沿用了 MySQL 大部分的文档结构, 同时针对 TiDB 特有的功能作了详细的描述。TiDB 数据库管理 TiDB 服务 TiDB 进程启动参数 TiDB 数据目录 TiDB 系统数据库 TiDB 系统变量 TiDB 专用系统变量和语法 TiDB 服务器日志文件 TiDB 访问权限管理 TiDB 用户账户管理 使用加密连接 SQL 优化 理解 TiDB 执行计划 统计信息 语言结构 字面值 字符串字面值 数字字面值 NULL 值 十六进制字面值 date 和 time 字面值 布尔值 bit-val 字面值 数据库、表、索引、列和别名 关键字和保留字 用户变量 表达式语法 注释语法 字符集和时区 字符集支持 字符集配置 时区 数据类型 数值类型 日期和时间类型 字符串类型 JSON 数据类型 数据类型默认值 函数和操作符 函数和操作符概述 表达式求值的类型转换 操作符 控制流程函数 字符串函数 数值函数与操作符 日期和时间函数 位函数和操作符 Cast 函数和操作符 加密和压缩函数 信息函数 JSON 函数 信息函数 全局事务 ID 函数 [TBD] GROUP BY 聚合函数 其他函数 精度数学 SQL 语句语法 数据定义语句(DDL) 数据操作语句(DML) 事务语句 数据库管理语句 Prepared SQL 语句语法 实用工具语句 TiDB SQL 语法图 JSON 支持 JSON 支持 Connectors 和 API Connectors 和 API 错误码与故障诊断 错误码与故障诊断 与 MySQL 兼容性对比 与 MySQL 兼容性对比 "}, {"url": "https://pingcap.com/docs-cn/sql/user-account-management/", "title": "TiDB 用户账户管理", "content": " TiDB 用户账户管理 用户名和密码 TiDB 将用户账户存储在 mysql.user 系统表里面。每个账户由用户名和 host 作为标识。每个账户可以设置一个密码。通过 MySQL 客户端连接到 TiDB 服务器,通过指定的账户和密码登陆:shell> mysql --port 4000 --user xxx --password 使用缩写的命令行参数则是:shell> mysql -P 4000 -u xxx -p 添加用户 添加用户有两种方式: 通过标准的用户管理的 SQL 语句创建用户以及授予权限,比如 CREATE USER 和 GRANT 。 直接通过 INSERT , UPDATE 和 DELETE 操作授权表。 推荐的方式是使用第一种。第二种方式修改容易导致一些不完整的修改,因此不推荐。还有另一种可选方式是使用第三方工具的图形化界面工具。下面的例子用 CREATE USER 和 GRANT 语句创建了四个账户:mysql> CREATE USER 'finley'@'localhost' IDENTIFIED BY 'some_pass'; mysql> GRANT ALL PRIVILEGES ON *.* TO 'finley'@'localhost' WITH GRANT OPTION; mysql> CREATE USER 'finley'@'%' IDENTIFIED BY 'some_pass'; mysql> GRANT ALL PRIVILEGES ON *.* TO 'finley'@'%' WITH GRANT OPTION; mysql> CREATE USER 'admin'@'localhost' IDENTIFIED BY 'admin_pass'; mysql> GRANT RELOAD,PROCESS ON *.* TO 'admin'@'localhost'; mysql> CREATE USER 'dummy'@'localhost'; 使用 SHOW GRANTS 可以看到为一个用户授予的权限:mysql> SHOW GRANTS FOR 'admin'@'localhost'; +-----------------------------------------------------+ | Grants for admin@localhost | +-----------------------------------------------------+ | GRANT RELOAD, PROCESS ON *.* TO 'admin'@'localhost' | +-----------------------------------------------------+ 删除用户 使用 DROP USER 语句可以删除用户,例如:mysql> DROP USER 'jeffrey'@'localhost'; 保留用户账户 TiDB 在数据库初始化时会生成一个 'root'@'%' 的默认账户。设置资源限制 暂不支持。设置密码 TiDB 将密码存在 mysql.user 系统数据库里面。只有拥有 CREATE USER 权限,或者拥有 mysql 数据库权限( INSERT 权限用于创建, UPDATE 权限用于更新)的用户才能够设置或修改密码。在 CREATE USER 创建用户时可以通过 IDENTIFIED BY 指定密码:CREATE USER 'jeffrey'@'localhost' IDENTIFIED BY 'mypass'; 为一个已存在的账户修改密码,可以通过 SET PASSWORD FOR 或者 ALTER USER 语句完成:SET PASSWORD FOR 'root'@'%' = 'xxx'; 或者ALTER USER 'jeffrey'@'localhost' IDENTIFIED BY 'mypass';"}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/user-account-management/", "title": "TiDB 用户账户管理", "content": " TiDB 用户账户管理 用户名和密码 TiDB 将用户账户存储在 mysql.user 系统表里面。每个账户由用户名和 host 作为标识。每个账户可以设置一个密码。通过 MySQL 客户端连接到 TiDB 服务器,通过指定的账户和密码登陆:shell> mysql --port 4000 --user xxx --password 使用缩写的命令行参数则是:shell> mysql -P 4000 -u xxx -p 添加用户 添加用户有两种方式: 通过标准的用户管理的 SQL 语句创建用户以及授予权限,比如 CREATE USER 和 GRANT 。 直接通过 INSERT , UPDATE 和 DELETE 操作授权表。 推荐的方式是使用第一种。第二种方式修改容易导致一些不完整的修改,因此不推荐。还有另一种可选方式是使用第三方工具的图形化界面工具。下面的例子用 CREATE USER 和 GRANT 语句创建了四个账户:mysql> CREATE USER 'finley'@'localhost' IDENTIFIED BY 'some_pass'; mysql> GRANT ALL PRIVILEGES ON *.* TO 'finley'@'localhost' WITH GRANT OPTION; mysql> CREATE USER 'finley'@'%' IDENTIFIED BY 'some_pass'; mysql> GRANT ALL PRIVILEGES ON *.* TO 'finley'@'%' WITH GRANT OPTION; mysql> CREATE USER 'admin'@'localhost' IDENTIFIED BY 'admin_pass'; mysql> GRANT RELOAD,PROCESS ON *.* TO 'admin'@'localhost'; mysql> CREATE USER 'dummy'@'localhost'; 使用 SHOW GRANTS 可以看到为一个用户授予的权限:mysql> SHOW GRANTS FOR 'admin'@'localhost'; +-----------------------------------------------------+ | Grants for admin@localhost | +-----------------------------------------------------+ | GRANT RELOAD, PROCESS ON *.* TO 'admin'@'localhost' | +-----------------------------------------------------+ 删除用户 使用 DROP USER 语句可以删除用户,例如:mysql> DROP USER 'jeffrey'@'localhost'; 保留用户账户 TiDB 在数据库初始化时会生成一个 'root'@'%' 的默认账户。设置资源限制 暂不支持。设置密码 TiDB 将密码存在 mysql.user 系统数据库里面。只有拥有 CREATE USER 权限,或者拥有 mysql 数据库权限( INSERT 权限用于创建, UPDATE 权限用于更新)的用户才能够设置或修改密码。在 CREATE USER 创建用户时可以通过 IDENTIFIED BY 指定密码:CREATE USER 'jeffrey'@'localhost' IDENTIFIED BY 'mypass'; 为一个已存在的账户修改密码,可以通过 SET PASSWORD FOR 或者 ALTER USER 语句完成:SET PASSWORD FOR 'root'@'%' = 'xxx'; 或者ALTER USER 'jeffrey'@'localhost' IDENTIFIED BY 'mypass';"}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/user-account-management/", "title": "TiDB 用户账户管理", "content": " TiDB 用户账户管理 用户名和密码 TiDB 将用户账户存储在 mysql.user 系统表里面。每个账户由用户名和 host 作为标识。每个账户可以设置一个密码。通过 MySQL 客户端连接到 TiDB 服务器,通过指定的账户和密码登陆:shell> mysql --port 4000 --user xxx --password 使用缩写的命令行参数则是:shell> mysql -P 4000 -u xxx -p 添加用户 添加用户有两种方式: 通过标准的用户管理的 SQL 语句创建用户以及授予权限,比如 CREATE USER 和 GRANT 。 直接通过 INSERT , UPDATE 和 DELETE 操作授权表。 推荐的方式是使用第一种。第二种方式修改容易导致一些不完整的修改,因此不推荐。还有另一种可选方式是使用第三方工具的图形化界面工具。下面的例子用 CREATE USER 和 GRANT 语句创建了四个账户:mysql> CREATE USER 'finley'@'localhost' IDENTIFIED BY 'some_pass'; mysql> GRANT ALL PRIVILEGES ON *.* TO 'finley'@'localhost' WITH GRANT OPTION; mysql> CREATE USER 'finley'@'%' IDENTIFIED BY 'some_pass'; mysql> GRANT ALL PRIVILEGES ON *.* TO 'finley'@'%' WITH GRANT OPTION; mysql> CREATE USER 'admin'@'localhost' IDENTIFIED BY 'admin_pass'; mysql> GRANT RELOAD,PROCESS ON *.* TO 'admin'@'localhost'; mysql> CREATE USER 'dummy'@'localhost'; 使用 SHOW GRANTS 可以看到为一个用户授予的权限:mysql> SHOW GRANTS FOR 'admin'@'localhost'; +-----------------------------------------------------+ | Grants for admin@localhost | +-----------------------------------------------------+ | GRANT RELOAD, PROCESS ON *.* TO 'admin'@'localhost' | +-----------------------------------------------------+ 删除用户 使用 DROP USER 语句可以删除用户,例如:mysql> DROP USER 'jeffrey'@'localhost'; 保留用户账户 TiDB 在数据库初始化时会生成一个 'root'@'%' 的默认账户。设置资源限制 暂不支持。设置密码 TiDB 将密码存在 mysql.user 系统数据库里面。只有拥有 CREATE USER 权限,或者拥有 mysql 数据库权限( INSERT 权限用于创建, UPDATE 权限用于更新)的用户才能够设置或修改密码。在 CREATE USER 创建用户时可以通过 IDENTIFIED BY 指定密码:CREATE USER 'jeffrey'@'localhost' IDENTIFIED BY 'mypass'; 为一个已存在的账户修改密码,可以通过 SET PASSWORD FOR 或者 ALTER USER 语句完成:SET PASSWORD FOR 'root'@'%' = 'xxx'; 或者ALTER USER 'jeffrey'@'localhost' IDENTIFIED BY 'mypass';"}, {"url": "https://pingcap.com/docs-cn/op-guide/monitor-overview/", "title": "TiDB 监控框架概述", "content": " TiDB 监控框架概述 TiDB 使用开源时序数据库 Prometheus 作为监控和性能指标信息存储方案,使用 Grafana 作为可视化组件进行展示。Prometheus 是一个拥有多维度数据模型,灵活的查询语句的时序数据库。Prometheus 作为热门的开源项目,拥有活跃的社区及众多的成功案例。Prometheus 提供了多个组件供用户使用。目前,我们使用 Prometheus Server,来收集和存储时间序列数据。Client 代码库,在程序中定制需要的 Metric 。Push GateWay 来接收 Client Push 上来的数据,统一供 Prometheus 主服务器抓取。以及 AlertManager 来实现报警机制。其结构如下图:Grafana 是一个开源的 metric 分析及可视化系统。我们使用 Grafana 来展示 TiDB 的各项性能指标 。如下图所示:"}, {"url": "https://pingcap.com/docs-cn/v1.0/op-guide/monitor-overview/", "title": "TiDB 监控框架概述", "content": " TiDB 监控框架概述 TiDB 使用开源时序数据库 Prometheus 作为监控和性能指标信息存储方案,使用 Grafana 作为可视化组件进行展示。Prometheus 是一个拥有多维度数据模型,灵活的查询语句的时序数据库。Prometheus 作为热门的开源项目,拥有活跃的社区及众多的成功案例。Prometheus 提供了多个组件供用户使用。目前,我们使用 Prometheus Server,来收集和存储时间序列数据。Client 代码库,在程序中定制需要的 Metric 。Push GateWay 来接收 Client Push 上来的数据,统一供 Prometheus 主服务器抓取。以及 AlertManager 来实现报警机制。其结构如下图:Grafana 是一个开源的 metric 分析及可视化系统。我们使用 Grafana 来展示 TiDB 的各项性能指标 。如下图所示:"}, {"url": "https://pingcap.com/docs-cn/v2.0/op-guide/monitor-overview/", "title": "TiDB 监控框架概述", "content": " TiDB 监控框架概述 TiDB 使用开源时序数据库 Prometheus 作为监控和性能指标信息存储方案,使用 Grafana 作为可视化组件进行展示。Prometheus 是一个拥有多维度数据模型,灵活的查询语句的时序数据库。Prometheus 作为热门的开源项目,拥有活跃的社区及众多的成功案例。Prometheus 提供了多个组件供用户使用。目前,我们使用 Prometheus Server,来收集和存储时间序列数据。Client 代码库,在程序中定制需要的 Metric 。Push GateWay 来接收 Client Push 上来的数据,统一供 Prometheus 主服务器抓取。以及 AlertManager 来实现报警机制。其结构如下图:Grafana 是一个开源的 metric 分析及可视化系统。我们使用 Grafana 来展示 TiDB 的各项性能指标 。如下图所示:"}, {"url": "https://pingcap.com/recruit-cn/engineering/tidb-engineer/", "title": "TiDB 研发工程师", "content": " TiDB 研发工程师 岗位职责: 负责分布式数据库查询优化器相关的设计,开发,文档撰写和新人指导; 负责分布式数据库 SQL 层的设计,开发和性能优化; 参与分布式数据库底层系统存储系统的设计。 职位要求: 三年以上相关领域开发经验,扎实的编程能力,熟悉 C/C++/Go/Java/Python 中的一种; 对分布式系统的架构和原理有比较深入的了解; 熟悉 MapReduce/Spark/Hive 等分布式计算框架中的一种或多种; 熟悉 MySQL/PostgreSQL/Greenplum 等数据库系统实现原理; 优秀的发现和解决问题能力,良好的沟通能力,具备团队合作精神。 加分项: 拥抱开源,对前沿技术有浓厚的热情和探索欲望,有开源项目经历; 熟悉 Spark 内核,并阅读过其中的源码; 熟悉 MySQL/PostgreSQL/Greenplum 的查询引擎,并阅读过其中的源码。 待遇:25K - 50K + 期权,13薪 + 奖金,优秀者可面议工作地点:北京,上海,广州,杭州,成都,特别优秀可 Remote"}, {"url": "https://pingcap.com/docs-cn/overview/", "title": "TiDB 简介", "content": " TiDB 简介 TiDB 是 PingCAP 公司设计的开源分布式 HTAP (Hybrid Transactional and Analytical Processing) 数据库,结合了传统的 RDBMS 和 NoSQL 的最佳特性。TiDB 兼容 MySQL,支持无限的水平扩展,具备强一致性和高可用性。TiDB 的目标是为 OLTP (Online Transactional Processing) 和 OLAP (Online Analytical Processing) 场景提供一站式的解决方案。TiDB 具备如下特性: 高度兼容 MySQL大多数情况下,无需修改代码即可从 MySQL 轻松迁移至 TiDB,分库分表后的 MySQL 集群亦可通过 TiDB 工具进行实时迁移。 水平弹性扩展通过简单地增加新节点即可实现 TiDB 的水平扩展,按需扩展吞吐或存储,轻松应对高并发、海量数据场景。 分布式事务TiDB 100% 支持标准的 ACID 事务。 真正金融级高可用相比于传统主从 (M-S) 复制方案,基于 Raft 的多数派选举协议可以提供金融级的 100% 数据强一致性保证,且在不丢失大多数副本的前提下,可以实现故障的自动恢复 (auto-failover),无需人工介入。 一站式 HTAP 解决方案TiDB 作为典型的 OLTP 行存数据库,同时兼具强大的 OLAP 性能,配合 TiSpark,可提供一站式 HTAP 解决方案,一份存储同时处理 OLTP & OLAP,无需传统繁琐的 ETL 过程。 云原生 SQL 数据库TiDB 是为云而设计的数据库,支持公有云、私有云和混合云,使部署、配置和维护变得十分简单。 TiDB 的设计目标是 100% 的 OLTP 场景和 80% 的 OLAP 场景,更复杂的 OLAP 分析可以通过 TiSpark 项目来完成。TiDB 对业务没有任何侵入性,能优雅的替换传统的数据库中间件、数据库分库分表等 Sharding 方案。同时它也让开发运维人员不用关注数据库 Scale 的细节问题,专注于业务开发,极大的提升研发的生产力。三篇文章了解 TiDB 技术内幕: 说存储 说计算 谈调度 "}, {"url": "https://pingcap.com/docs-cn/v1.0/overview/", "title": "TiDB 简介与整体架构", "content": " TiDB 简介与整体架构 TiDB 简介 TiDB 是 PingCAP 公司受 Google Spanner / F1 论文启发而设计的开源分布式 NewSQL 数据库。TiDB 具备如下 NewSQL 核心特性: SQL支持(TiDB 是 MySQL 兼容的) 水平弹性扩展(吞吐可线性扩展) 分布式事务 跨数据中心数据强一致性保证 故障自恢复的高可用 海量数据高并发实时写入与实时查询(HTAP 混合负载) TiDB 的设计目标是 100% 的 OLTP 场景和 80% 的 OLAP 场景,更复杂的 OLAP 分析可以通过 TiSpark 项目来完成。TiDB 对业务没有任何侵入性,能优雅的替换传统的数据库中间件、数据库分库分表等 Sharding 方案。同时它也让开发运维人员不用关注数据库 Scale 的细节问题,专注于业务开发,极大的提升研发的生产力。三篇文章了解 TiDB 技术内幕: 说存储 说计算 谈调度 TiDB 整体架构 要深入了解 TiDB 的水平扩展和高可用特点,首先需要了解 TiDB 的整体架构。TiDB 集群主要分为三个组件:TiDB Server TiDB Server 负责接收 SQL 请求,处理 SQL 相关的逻辑,并通过 PD 找到存储计算所需数据的 TiKV 地址,与 TiKV 交互获取数据,最终返回结果。 TiDB Server 是无状态的,其本身并不存储数据,只负责计算,可以无限水平扩展,可以通过负载均衡组件(如LVS、HAProxy 或 F5)对外提供统一的接入地址。PD Server Placement Driver (简称 PD) 是整个集群的管理模块,其主要工作有三个: 一是存储集群的元信息(某个 Key 存储在哪个 TiKV 节点);二是对 TiKV 集群进行调度和负载均衡(如数据的迁移、Raft group leader 的迁移等);三是分配全局唯一且递增的事务 ID。PD 是一个集群,需要部署奇数个节点,一般线上推荐至少部署 3 个节点。TiKV Server TiKV Server 负责存储数据,从外部看 TiKV 是一个分布式的提供事务的 Key-Value 存储引擎。存储数据的基本单位是 Region,每个 Region 负责存储一个 Key Range (从 StartKey 到 EndKey 的左闭右开区间)的数据,每个 TiKV 节点会负责多个 Region 。TiKV 使用 Raft 协议做复制,保持数据的一致性和容灾。副本以 Region 为单位进行管理,不同节点上的多个 Region 构成一个 Raft Group,互为副本。数据在多个 TiKV 之间的负载均衡由 PD 调度,这里也是以 Region 为单位进行调度。核心特性 水平扩展 无限水平扩展是 TiDB 的一大特点,这里说的水平扩展包括两方面:计算能力和存储能力。TiDB Server 负责处理 SQL 请求,随着业务的增长,可以简单的添加 TiDB Server 节点,提高整体的处理能力,提供更高的吞吐。TiKV 负责存储数据,随着数据量的增长,可以部署更多的 TiKV Server 节点解决数据 Scale 的问题。PD 会在 TiKV 节点之间以 Region 为单位做调度,将部分数据迁移到新加的节点上。所以在业务的早期,可以只部署少量的服务实例(推荐至少部署 3 个 TiKV, 3 个 PD,2 个 TiDB),随着业务量的增长,按照需求添加 TiKV 或者 TiDB 实例。高可用 高可用是 TiDB 的另一大特点,TiDB/TiKV/PD 这三个组件都能容忍部分实例失效,不影响整个集群的可用性。下面分别说明这三个组件的可用性、单个实例失效后的后果以及如何恢复。 TiDBTiDB 是无状态的,推荐至少部署两个实例,前端通过负载均衡组件对外提供服务。当单个实例失效时,会影响正在这个实例上进行的 Session,从应用的角度看,会出现单次请求失败的情况,重新连接后即可继续获得服务。单个实例失效后,可以重启这个实例或者部署一个新的实例。 PDPD 是一个集群,通过 Raft 协议保持数据的一致性,单个实例失效时,如果这个实例不是 Raft 的 leader,那么服务完全不受影响;如果这个实例是 Raft 的 leader,会重新选出新的 Raft leader,自动恢复服务。PD 在选举的过程中无法对外提供服务,这个时间大约是3秒钟。推荐至少部署三个 PD 实例,单个实例失效后,重启这个实例或者添加新的实例。 TiKVTiKV 是一个集群,通过 Raft 协议保持数据的一致性(副本数量可配置,默认保存三副本),并通过 PD 做负载均衡调度。单个节点失效时,会影响这个节点上存储的所有 Region。对于 Region 中的 Leader 结点,会中断服务,等待重新选举;对于 Region 中的 Follower 节点,不会影响服务。当某个 TiKV 节点失效,并且在一段时间内(默认 10 分钟)无法恢复,PD 会将其上的数据迁移到其他的 TiKV 节点上。 "}, {"url": "https://pingcap.com/docs-cn/v2.0/overview/", "title": "TiDB 简介与整体架构", "content": " TiDB 简介与整体架构 TiDB 简介 TiDB 是 PingCAP 公司受 Google Spanner / F1 论文启发而设计的开源分布式 NewSQL 数据库。TiDB 具备如下 NewSQL 核心特性: SQL支持(TiDB 是 MySQL 兼容的) 水平弹性扩展(吞吐可线性扩展) 分布式事务 跨数据中心数据强一致性保证 故障自恢复的高可用 海量数据高并发实时写入与实时查询(HTAP 混合负载) TiDB 的设计目标是 100% 的 OLTP 场景和 80% 的 OLAP 场景,更复杂的 OLAP 分析可以通过 TiSpark 项目来完成。TiDB 对业务没有任何侵入性,能优雅的替换传统的数据库中间件、数据库分库分表等 Sharding 方案。同时它也让开发运维人员不用关注数据库 Scale 的细节问题,专注于业务开发,极大的提升研发的生产力。三篇文章了解 TiDB 技术内幕: 说存储 说计算 谈调度 TiDB 整体架构 要深入了解 TiDB 的水平扩展和高可用特点,首先需要了解 TiDB 的整体架构。TiDB 集群主要分为三个组件:TiDB Server TiDB Server 负责接收 SQL 请求,处理 SQL 相关的逻辑,并通过 PD 找到存储计算所需数据的 TiKV 地址,与 TiKV 交互获取数据,最终返回结果。 TiDB Server 是无状态的,其本身并不存储数据,只负责计算,可以无限水平扩展,可以通过负载均衡组件(如LVS、HAProxy 或 F5)对外提供统一的接入地址。PD Server Placement Driver (简称 PD) 是整个集群的管理模块,其主要工作有三个: 一是存储集群的元信息(某个 Key 存储在哪个 TiKV 节点);二是对 TiKV 集群进行调度和负载均衡(如数据的迁移、Raft group leader 的迁移等);三是分配全局唯一且递增的事务 ID。PD 是一个集群,需要部署奇数个节点,一般线上推荐至少部署 3 个节点。TiKV Server TiKV Server 负责存储数据,从外部看 TiKV 是一个分布式的提供事务的 Key-Value 存储引擎。存储数据的基本单位是 Region,每个 Region 负责存储一个 Key Range (从 StartKey 到 EndKey 的左闭右开区间)的数据,每个 TiKV 节点会负责多个 Region 。TiKV 使用 Raft 协议做复制,保持数据的一致性和容灾。副本以 Region 为单位进行管理,不同节点上的多个 Region 构成一个 Raft Group,互为副本。数据在多个 TiKV 之间的负载均衡由 PD 调度,这里也是以 Region 为单位进行调度。核心特性 水平扩展 无限水平扩展是 TiDB 的一大特点,这里说的水平扩展包括两方面:计算能力和存储能力。TiDB Server 负责处理 SQL 请求,随着业务的增长,可以简单的添加 TiDB Server 节点,提高整体的处理能力,提供更高的吞吐。TiKV 负责存储数据,随着数据量的增长,可以部署更多的 TiKV Server 节点解决数据 Scale 的问题。PD 会在 TiKV 节点之间以 Region 为单位做调度,将部分数据迁移到新加的节点上。所以在业务的早期,可以只部署少量的服务实例(推荐至少部署 3 个 TiKV, 3 个 PD,2 个 TiDB),随着业务量的增长,按照需求添加 TiKV 或者 TiDB 实例。高可用 高可用是 TiDB 的另一大特点,TiDB/TiKV/PD 这三个组件都能容忍部分实例失效,不影响整个集群的可用性。下面分别说明这三个组件的可用性、单个实例失效后的后果以及如何恢复。 TiDBTiDB 是无状态的,推荐至少部署两个实例,前端通过负载均衡组件对外提供服务。当单个实例失效时,会影响正在这个实例上进行的 Session,从应用的角度看,会出现单次请求失败的情况,重新连接后即可继续获得服务。单个实例失效后,可以重启这个实例或者部署一个新的实例。 PDPD 是一个集群,通过 Raft 协议保持数据的一致性,单个实例失效时,如果这个实例不是 Raft 的 leader,那么服务完全不受影响;如果这个实例是 Raft 的 leader,会重新选出新的 Raft leader,自动恢复服务。PD 在选举的过程中无法对外提供服务,这个时间大约是3秒钟。推荐至少部署三个 PD 实例,单个实例失效后,重启这个实例或者添加新的实例。 TiKVTiKV 是一个集群,通过 Raft 协议保持数据的一致性(副本数量可配置,默认保存三副本),并通过 PD 做负载均衡调度。单个节点失效时,会影响这个节点上存储的所有 Region。对于 Region 中的 Leader 结点,会中断服务,等待重新选举;对于 Region 中的 Follower 节点,不会影响服务。当某个 TiKV 节点失效,并且在一段时间内(默认 10 分钟)无法恢复,PD 会将其上的数据迁移到其他的 TiKV 节点上。 "}, {"url": "https://pingcap.com/docs-cn/sql/system-database/", "title": "TiDB 系统数据库", "content": " TiDB 系统数据库 TiDB 的系统数据库跟 MySQL 类似,里面包含一些服务器运行时需要的信息。权限系统表 这些系统表里面包含了用户账户以及相应的授权信息: user 用户账户,全局权限,以及其它一些非权限的列 db 数据库级别的权限 tables_priv 表级的权限 columns_priv 列级的权限 服务端帮助信息系统表 help_topic 目前为空 统计信息相关系统表 stats_buckets 统计信息的桶 stats_histograms 统计信息的直方图 stats_meta 表的元信息,比如总行数和修改数 GC Worker 相关系统表 gc_delete_range 其它系统表 GLOBAL_VARIABLES 全局系统变量表 tidb 用于 TiDB 在 bootstrap 的时候记录相关版本信息 INFORMATION_SCHEMA 里面的表 INFORMATION_SCHEMA 库里面的表主要是为了兼容 MySQL 而存在,有些第三方软件会查询里面的信息。在目前 TiDB 的实现中,里面大部分只是一些空表。CHARACTER_SETS Table 提供字符集相关的信息,其实数据是假的。TiDB 默认支持并且只支持 utf8mb4 。mysql> select * from CHARACTER_SETS; +--------------------|----------------------|-----------------------|--------+ | CHARACTER_SET_NAME | DEFAULT_COLLATE_NAME | DESCRIPTION | MAXLEN | +--------------------|----------------------|-----------------------|--------+ | ascii | ascii_general_ci | US ASCII | 1 | | binary | binary | Binary pseudo charset | 1 | | latin1 | latin1_swedish_ci | cp1252 West European | 1 | | utf8 | utf8_general_ci | UTF-8 Unicode | 3 | | utf8mb4 | utf8mb4_general_ci | UTF-8 Unicode | 4 | +--------------------|----------------------|-----------------------|--------+ 5 rows in set (0.00 sec) COLLATIONS Table 同上。COLLATION_CHARACTER_SET_APPLICABILITY Table 空表。COLUMNS Table COLUMNS 表提供了关于所有表的列的信息。这张表里面的信息不准确,推荐使用 SHOW 语句查询:SHOW COLUMNS FROM table_name [FROM db_name] [LIKE 'wild'] COLUMN_PRIVILEGES Table 空表。ENGINES Table ENGINES 表提供了关于存储引擎的信息。从和 MySQL 兼容性上考虑,TiDB show engines 的结果展示成了 InnoDB。EVENTS Table 空表。FILES Table 空表。GLOBAL_STATUS Table 空表。GLOBAL_VARIABLES Table 空表。KEY_COLUMN_USAGE Table KEY_COLUMN_USAGE 这张表描述了关于列的 key 的约束,比如是否是主键列。OPTIMIZER_TRACE Table 空表。PARAMETERS Table 空表。PARTITIONS Table 空表。PLUGINS Table 空表。PROFILING Table 空表。REFERENTIAL_CONSTRAINTS Table 空表。ROUTINES Table 空表。SCHEMATA Table SCHEMATA 表提供了关于数据库的信息。表中的内容和 SHOW DATABASES 基本等价。mysql> select * from SCHEMATA; +--------------|--------------------|----------------------------|------------------------|----------+ | CATALOG_NAME | SCHEMA_NAME | DEFAULT_CHARACTER_SET_NAME | DEFAULT_COLLATION_NAME | SQL_PATH | +--------------|--------------------|----------------------------|------------------------|----------+ | def | INFORMATION_SCHEMA | utf8 | utf8_bin | NULL | | def | mysql | utf8 | utf8_bin | NULL | | def | PERFORMANCE_SCHEMA | utf8 | utf8_bin | NULL | | def | test | utf8 | utf8_bin | NULL | +--------------|--------------------|----------------------------|------------------------|----------+ 4 rows in set (0.00 sec) SCHEMA_PRIVILEGES Table 空表。SESSION_STATUS Table 空表。SESSION_VARIABLES Table SESSION_VARIABLES 表提供了关于 session 变量的信息。表中的数据跟 SHOW SESSION VARIABLES 类似。STATISTICS Table 统计信息的表。mysql> desc statistics; +---------------|---------------------|------|------|---------|-------+ | Field | Type | Null | Key | Default | Extra | +---------------|---------------------|------|------|---------|-------+ | TABLE_CATALOG | varchar(512) | YES | | NULL | | | TABLE_SCHEMA | varchar(64) | YES | | NULL | | | TABLE_NAME | varchar(64) | YES | | NULL | | | NON_UNIQUE | varchar(1) | YES | | NULL | | | INDEX_SCHEMA | varchar(64) | YES | | NULL | | | INDEX_NAME | varchar(64) | YES | | NULL | | | SEQ_IN_INDEX | bigint(2) UNSIGNED | YES | | NULL | | | COLUMN_NAME | varchar(21) | YES | | NULL | | | COLLATION | varchar(1) | YES | | NULL | | | CARDINALITY | bigint(21) UNSIGNED | YES | | NULL | | | SUB_PART | bigint(3) UNSIGNED | YES | | NULL | | | PACKED | varchar(10) | YES | | NULL | | | NULLABLE | varchar(3) | YES | | NULL | | | INDEX_TYPE | varchar(16) | YES | | NULL | | | COMMENT | varchar(16) | YES | | NULL | | | INDEX_COMMENT | varchar(1024) | YES | | NULL | | +---------------|---------------------|------|------|---------|-------+ 下列操作是等价的。SELECT * FROM INFORMATION_SCHEMA.STATISTICS WHERE table_name = 'tbl_name' AND table_schema = 'db_name' SHOW INDEX FROM tbl_name FROM db_name TABLES Table TABLES 表提供了数据库里面关于表的信息。以下操作是等价的:SELECT table_name FROM INFORMATION_SCHEMA.TABLES WHERE table_schema = 'db_name' [AND table_name LIKE 'wild'] SHOW TABLES FROM db_name [LIKE 'wild'] TABLESPACES Table 空表。TABLE_CONSTRAINTS Table TABLE_CONSTRAINTS 记录了表的约束信息。其中: CONSTRAINT_TYPE 的取值可以是 UNIQUE, PRIMARY KEY, 或者 FOREIGN KEY。 UNIQUE 和 PRIMARY KEY 信息跟 SHOW INDEX 看到的是一样的。 TABLE_PRIVILEGES Table 空表。TRIGGERS Table 空表。USER_PRIVILEGES Table USER_PRIVILEGES 表提供了关于全局权限的信息。这张表的内容是根据 mysql.user 表生成的。mysql> desc USER_PRIVILEGES; +----------------|--------------|------|------|---------|-------+ | Field | Type | Null | Key | Default | Extra | +----------------|--------------|------|------|---------|-------+ | GRANTEE | varchar(81) | YES | | NULL | | | TABLE_CATALOG | varchar(512) | YES | | NULL | | | PRIVILEGE_TYPE | varchar(64) | YES | | NULL | | | IS_GRANTABLE | varchar(3) | YES | | NULL | | +----------------|--------------|------|------|---------|-------+ 4 rows in set (0.00 sec) VIEWS Table 空表。TiDB 暂不支持视图。"}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/system-database/", "title": "TiDB 系统数据库", "content": " TiDB 系统数据库 TiDB 的系统数据库跟 MySQL 类似,里面包含一些服务器运行时需要的信息。权限系统表 这些系统表里面包含了用户账户以及相应的授权信息: user 用户账户,全局权限,以及其它一些非权限的列 db 数据库级别的权限 tables_priv 表级的权限 columns_priv 列级的权限 服务端帮助信息系统表 help_topic 目前为空 统计信息相关系统表 stats_buckets 统计信息的桶 stats_histograms 统计信息的直方图 stats_meta 表的元信息,比如总行数和修改数 GC Worker 相关系统表 gc_delete_range 其它系统表 GLOBAL_VARIABLES 全局系统变量表 tidb 用于 TiDB 在 bootstrap 的时候记录相关版本信息 INFORMATION_SCHEMA 里面的表 INFORMATION_SCHEMA 库里面的表主要是为了兼容 MySQL 而存在,有些第三方软件会查询里面的信息。在目前 TiDB 的实现中,里面大部分只是一些空表。CHARACTER_SETS Table 提供字符集相关的信息,其实数据是假的。TiDB 默认支持并且只支持 utf8mb4 。mysql> select * from CHARACTER_SETS; +--------------------|----------------------|-----------------------|--------+ | CHARACTER_SET_NAME | DEFAULT_COLLATE_NAME | DESCRIPTION | MAXLEN | +--------------------|----------------------|-----------------------|--------+ | ascii | ascii_general_ci | US ASCII | 1 | | binary | binary | Binary pseudo charset | 1 | | latin1 | latin1_swedish_ci | cp1252 West European | 1 | | utf8 | utf8_general_ci | UTF-8 Unicode | 3 | | utf8mb4 | utf8mb4_general_ci | UTF-8 Unicode | 4 | +--------------------|----------------------|-----------------------|--------+ 5 rows in set (0.00 sec) COLLATIONS Table 同上。COLLATION_CHARACTER_SET_APPLICABILITY Table 空表。COLUMNS Table COLUMNS 表提供了关于所有表的列的信息。这张表里面的信息不准确,推荐使用 SHOW 语句查询:SHOW COLUMNS FROM table_name [FROM db_name] [LIKE 'wild'] COLUMNS_PRIVILEGE Table 空表。ENGINES Table ENGINES 表提供了关于存储引擎的信息。目前这张表里面的数据是假的。生产环境中,TiDB 只推荐使用 TiKV 引擎。EVENTS Table 空表。FILES Table 空表。GLOBAL_STATUS Table 空表。GLOBAL_VARIABLES Table 空表。KEY_COLUMN_USAGE Table KEY_COLUMN_USAGE 这张表描述了关于列的 key 的约束,比如是否是主键列。OPTIMIZER_TRACE Table 空表。PARAMETERS Table 空表。PARTITIONS Table 空表。PLUGINS Table 空表。PROFILING Table 空表。REFERENTIAL_CONSTRAINTS Table 空表。ROUTINES Table 空表。SCHEMATA Table SCHEMATA 表提供了关于数据库的信息。表中的内容和 SHOW DATABASES 基本等价。mysql> select * from SCHEMATA; +--------------|--------------------|----------------------------|------------------------|----------+ | CATALOG_NAME | SCHEMA_NAME | DEFAULT_CHARACTER_SET_NAME | DEFAULT_COLLATION_NAME | SQL_PATH | +--------------|--------------------|----------------------------|------------------------|----------+ | def | INFORMATION_SCHEMA | utf8 | utf8_bin | NULL | | def | mysql | utf8 | utf8_bin | NULL | | def | PERFORMANCE_SCHEMA | utf8 | utf8_bin | NULL | | def | test | utf8 | utf8_bin | NULL | +--------------|--------------------|----------------------------|------------------------|----------+ 4 rows in set (0.00 sec) SCHEMA_PRIVILEGES Table 空表。SESSION_STATUS Table 空表。SESSION_VARIABLES Table SESSION_VARIABLES 表提供了关于 session 变量的信息。表中的数据跟 SHOW SESSION VARIABLES 类似。STATISTICS Table 统计信息的表。mysql> desc statistics; +---------------|---------------------|------|------|---------|-------+ | Field | Type | Null | Key | Default | Extra | +---------------|---------------------|------|------|---------|-------+ | TABLE_CATALOG | varchar(512) | YES | | NULL | | | TABLE_SCHEMA | varchar(64) | YES | | NULL | | | TABLE_NAME | varchar(64) | YES | | NULL | | | NON_UNIQUE | varchar(1) | YES | | NULL | | | INDEX_SCHEMA | varchar(64) | YES | | NULL | | | INDEX_NAME | varchar(64) | YES | | NULL | | | SEQ_IN_INDEX | bigint(2) UNSIGNED | YES | | NULL | | | COLUMN_NAME | varchar(21) | YES | | NULL | | | COLLATION | varchar(1) | YES | | NULL | | | CARDINALITY | bigint(21) UNSIGNED | YES | | NULL | | | SUB_PART | bigint(3) UNSIGNED | YES | | NULL | | | PACKED | varchar(10) | YES | | NULL | | | NULLABLE | varchar(3) | YES | | NULL | | | INDEX_TYPE | varchar(16) | YES | | NULL | | | COMMENT | varchar(16) | YES | | NULL | | | INDEX_COMMENT | varchar(1024) | YES | | NULL | | +---------------|---------------------|------|------|---------|-------+ 下列操作是等价的。SELECT * FROM INFORMATION_SCHEMA.STATISTICS WHERE table_name = 'tbl_name' AND table_schema = 'db_name' SHOW INDEX FROM tbl_name FROM db_name TABLES Table TABLES 表提供了数据库里面关于表的信息。以下操作是等价的:SELECT table_name FROM INFORMATION_SCHEMA.TABLES WHERE table_schema = 'db_name' [AND table_name LIKE 'wild'] SHOW TABLES FROM db_name [LIKE 'wild'] TABLESPACES Table 空表。TABLE_CONSTRAINTS Table TABLE_CONSTRAINTS 记录了表的约束信息。其中: CONSTRAINT_TYPE 的取值可以是 UNIQUE, PRIMARY KEY, 或者 FOREIGN KEY。 UNIQUE 和 PRIMARY KEY 信息跟 SHOW INDEX 看到的是一样的。 TABLE_PRIVILEGES Table 空表。TRIGGERS Table 空表。USER_PRIVILEGES Table USER_PRIVILEGES 表提供了关于全局权限的信息。这张表的内容是根据 mysql.user 表生成的。mysql> desc USER_PRIVILEGES; +----------------|--------------|------|------|---------|-------+ | Field | Type | Null | Key | Default | Extra | +----------------|--------------|------|------|---------|-------+ | GRANTEE | varchar(81) | YES | | NULL | | | TABLE_CATALOG | varchar(512) | YES | | NULL | | | PRIVILEGE_TYPE | varchar(64) | YES | | NULL | | | IS_GRANTABLE | varchar(3) | YES | | NULL | | +----------------|--------------|------|------|---------|-------+ 4 rows in set (0.00 sec) VIEWS Table 空表。TiDB 暂不支持视图。"}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/system-database/", "title": "TiDB 系统数据库", "content": " TiDB 系统数据库 TiDB 的系统数据库跟 MySQL 类似,里面包含一些服务器运行时需要的信息。权限系统表 这些系统表里面包含了用户账户以及相应的授权信息: user 用户账户,全局权限,以及其它一些非权限的列 db 数据库级别的权限 tables_priv 表级的权限 columns_priv 列级的权限 服务端帮助信息系统表 help_topic 目前为空 统计信息相关系统表 stats_buckets 统计信息的桶 stats_histograms 统计信息的直方图 stats_meta 表的元信息,比如总行数和修改数 GC Worker 相关系统表 gc_delete_range 其它系统表 GLOBAL_VARIABLES 全局系统变量表 tidb 用于 TiDB 在 bootstrap 的时候记录相关版本信息 INFORMATION_SCHEMA 里面的表 INFORMATION_SCHEMA 库里面的表主要是为了兼容 MySQL 而存在,有些第三方软件会查询里面的信息。在目前 TiDB 的实现中,里面大部分只是一些空表。CHARACTER_SETS Table 提供字符集相关的信息,其实数据是假的。TiDB 默认支持并且只支持 utf8mb4 。mysql> select * from CHARACTER_SETS; +--------------------|----------------------|-----------------------|--------+ | CHARACTER_SET_NAME | DEFAULT_COLLATE_NAME | DESCRIPTION | MAXLEN | +--------------------|----------------------|-----------------------|--------+ | ascii | ascii_general_ci | US ASCII | 1 | | binary | binary | Binary pseudo charset | 1 | | latin1 | latin1_swedish_ci | cp1252 West European | 1 | | utf8 | utf8_general_ci | UTF-8 Unicode | 3 | | utf8mb4 | utf8mb4_general_ci | UTF-8 Unicode | 4 | +--------------------|----------------------|-----------------------|--------+ 5 rows in set (0.00 sec) COLLATIONS Table 同上。COLLATION_CHARACTER_SET_APPLICABILITY Table 空表。COLUMNS Table COLUMNS 表提供了关于所有表的列的信息。这张表里面的信息不准确,推荐使用 SHOW 语句查询:SHOW COLUMNS FROM table_name [FROM db_name] [LIKE 'wild'] COLUMNS_PRIVILEGE Table 空表。ENGINES Table ENGINES 表提供了关于存储引擎的信息。目前这张表里面的数据是假的。生产环境中,TiDB 只推荐使用 TiKV 引擎。EVENTS Table 空表。FILES Table 空表。GLOBAL_STATUS Table 空表。GLOBAL_VARIABLES Table 空表。KEY_COLUMN_USAGE Table KEY_COLUMN_USAGE 这张表描述了关于列的 key 的约束,比如是否是主键列。OPTIMIZER_TRACE Table 空表。PARAMETERS Table 空表。PARTITIONS Table 空表。PLUGINS Table 空表。PROFILING Table 空表。REFERENTIAL_CONSTRAINTS Table 空表。ROUTINES Table 空表。SCHEMATA Table SCHEMATA 表提供了关于数据库的信息。表中的内容和 SHOW DATABASES 基本等价。mysql> select * from SCHEMATA; +--------------|--------------------|----------------------------|------------------------|----------+ | CATALOG_NAME | SCHEMA_NAME | DEFAULT_CHARACTER_SET_NAME | DEFAULT_COLLATION_NAME | SQL_PATH | +--------------|--------------------|----------------------------|------------------------|----------+ | def | INFORMATION_SCHEMA | utf8 | utf8_bin | NULL | | def | mysql | utf8 | utf8_bin | NULL | | def | PERFORMANCE_SCHEMA | utf8 | utf8_bin | NULL | | def | test | utf8 | utf8_bin | NULL | +--------------|--------------------|----------------------------|------------------------|----------+ 4 rows in set (0.00 sec) SCHEMA_PRIVILEGES Table 空表。SESSION_STATUS Table 空表。SESSION_VARIABLES Table SESSION_VARIABLES 表提供了关于 session 变量的信息。表中的数据跟 SHOW SESSION VARIABLES 类似。STATISTICS Table 统计信息的表。mysql> desc statistics; +---------------|---------------------|------|------|---------|-------+ | Field | Type | Null | Key | Default | Extra | +---------------|---------------------|------|------|---------|-------+ | TABLE_CATALOG | varchar(512) | YES | | NULL | | | TABLE_SCHEMA | varchar(64) | YES | | NULL | | | TABLE_NAME | varchar(64) | YES | | NULL | | | NON_UNIQUE | varchar(1) | YES | | NULL | | | INDEX_SCHEMA | varchar(64) | YES | | NULL | | | INDEX_NAME | varchar(64) | YES | | NULL | | | SEQ_IN_INDEX | bigint(2) UNSIGNED | YES | | NULL | | | COLUMN_NAME | varchar(21) | YES | | NULL | | | COLLATION | varchar(1) | YES | | NULL | | | CARDINALITY | bigint(21) UNSIGNED | YES | | NULL | | | SUB_PART | bigint(3) UNSIGNED | YES | | NULL | | | PACKED | varchar(10) | YES | | NULL | | | NULLABLE | varchar(3) | YES | | NULL | | | INDEX_TYPE | varchar(16) | YES | | NULL | | | COMMENT | varchar(16) | YES | | NULL | | | INDEX_COMMENT | varchar(1024) | YES | | NULL | | +---------------|---------------------|------|------|---------|-------+ 下列操作是等价的。SELECT * FROM INFORMATION_SCHEMA.STATISTICS WHERE table_name = 'tbl_name' AND table_schema = 'db_name' SHOW INDEX FROM tbl_name FROM db_name TABLES Table TABLES 表提供了数据库里面关于表的信息。以下操作是等价的:SELECT table_name FROM INFORMATION_SCHEMA.TABLES WHERE table_schema = 'db_name' [AND table_name LIKE 'wild'] SHOW TABLES FROM db_name [LIKE 'wild'] TABLESPACES Table 空表。TABLE_CONSTRAINTS Table TABLE_CONSTRAINTS 记录了表的约束信息。其中: CONSTRAINT_TYPE 的取值可以是 UNIQUE, PRIMARY KEY, 或者 FOREIGN KEY。 UNIQUE 和 PRIMARY KEY 信息跟 SHOW INDEX 看到的是一样的。 TABLE_PRIVILEGES Table 空表。TRIGGERS Table 空表。USER_PRIVILEGES Table USER_PRIVILEGES 表提供了关于全局权限的信息。这张表的内容是根据 mysql.user 表生成的。mysql> desc USER_PRIVILEGES; +----------------|--------------|------|------|---------|-------+ | Field | Type | Null | Key | Default | Extra | +----------------|--------------|------|------|---------|-------+ | GRANTEE | varchar(81) | YES | | NULL | | | TABLE_CATALOG | varchar(512) | YES | | NULL | | | PRIVILEGE_TYPE | varchar(64) | YES | | NULL | | | IS_GRANTABLE | varchar(3) | YES | | NULL | | +----------------|--------------|------|------|---------|-------+ 4 rows in set (0.00 sec) VIEWS Table 空表。TiDB 暂不支持视图。"}, {"url": "https://pingcap.com/docs-cn/ROADMAP/", "title": "TiDB 路线图", "content": " TiDB 路线图 TiDB: 优化器 重构 Ranger 代价模型优化 Cascades model planner Join Reorder 统计信息 基于 Query Feedback 动态更新统计信息 自动 Analyze 提升 Row Count 估算精度 执行引擎 下推 Projection 到 Coprocessor 优化 HashJoin 算子执行速度 算子并行化 并行 Projection 并行聚合 并行 Sort Compact Row Format,节省内存占用 File Sort View 窗口函数 Common Table Expression 分区表 Range 分区 Hash 分区 聚簇索引 新的 storage row format Query Tracing DDL 改进 Add Index 加速 并行 DDL 支持锁表 支持改变 column 类型 支持修改主键 支持一条语句中多个 DDL 操作 支持 utf8_general_ci collation TiKV: Raft Region Merge - 合并小的 Region 以减少开销 Local Read Thread - 把读请求放在一个单独的线程处理 批量 Region Split - 加速大的 Region 的分裂 Raft Learner - 支持 Raft learner 使得成员变更过程更加平滑 Raft Pre-voter - 支持 Raft Pre-vote 避免网络隔离带来不必要的选举 Joint Consensus - 安全地进行多个成员变更 多线程 Raftstore - 在多个线程处理不同 Region 的 Raft 逻辑 多线程 Apply Pool - 在多个线程执行不同 Region 已经提交了的命令 Engine Titan - 把大的 key-values 从 LSM-Tree 中分离出来 可拔插的 Engine 接口 - 简化接口逻辑并且提供可扩展性 Storage 在 scheduler 里做流控提前避免 write stall Transaction 优化事务冲突 分布式 GC - 把 MVCC 垃圾回收的逻辑分布到 TiKV 控制 Coprocessor Streaming - 把大的数据集切成小块返回以减少内存消耗 Chunk Execution - 按 chunk 的方式来处理数据以提高性能 请求跟踪 - 提供单个请求执行的详细信息 Tools TiKV Importer - 通过直接导入 SST 文件的方式加速数据导入 Client 提供 Rust 版本的 TiKV client gRPC 消息批量化 - 减少消息交互的开销 PD: Namespace 完善 不同 Namespace 或者 Table 配置不同的副本策略 Table Region 分散调度 调度支持优先级,更加可控 使用机器学习优化调度 优化 Region 元信息存储 - 把元信息存储在一个独立的存储引擎里 TiSpark: Limit/Order 下推 DAG 接口接入(废除 Select 接口) Index Join 和并行 merge join Data Federation(桥接其他数据源,最好能和社区同步,这个接进来可以比较好扩展 Usecase,如果再做一个 InputFormat 适配就可以接 Hive 和 Presto 这些 Hadoop 上的数仓) Tools: 集群部署工具 高性能数据导入工具(lightning) 集群备份和恢复工具(包括全量+增量备份,mydumper + drainer/reparo) 改进 TiDB-Binlog 架构 数据在线迁移工具(Syncer 升级版) 集群诊断和分析工具 "}, {"url": "https://pingcap.com/docs-cn/op-guide/recommendation/", "title": "TiDB 软件和硬件环境要求", "content": " TiDB 软件和硬件环境要求 概述 TiDB 作为一款开源分布式 NewSQL 数据库,可以很好的部署和运行在 Intel 架构服务器环境及主流虚拟化环境,并支持绝大多数的主流硬件网络。作为一款高性能数据库系统,TiDB 支持主流的 Linux 操作系统环境。Linux 操作系统版本要求 Linux 操作系统平台 版本 Red Hat Enterprise Linux 7.3 及以上 CentOS 7.3 及以上 Oracle Enterprise Linux 7.3 及以上 Ubuntu LTS 16.04 及以上 注: TiDB 只支持 Red Hat 兼容内核 (RHCK) 的 Oracle Enterprise Linux,不支持 Oracle Enterprise Linux 提供的 Unbreakable Enterprise Kernel。 TiDB 在 CentOS 7.3 的环境下进行过大量的测试,同时社区也有很多该操作系统部署的最佳实践,因此,建议使用 CentOS 7.3 以上的 Linux 操作系统来部署 TiDB。 以上 Linux 操作系统可运行在物理服务器以及 VMware、KVM、XEN 主流虚拟化环境上。 服务器要求 TiDB 支持部署和运行在 Intel x86-64 架构的 64 位通用硬件服务器平台。对于开发,测试,及生产环境的服务器硬件配置有以下要求和建议:开发及测试环境 组件 CPU 内存 本地存储 网络 实例数量(最低要求) TiDB 8核+ 16 GB+ SAS, 200 GB+ 千兆网卡 1(可与 PD 同机器) PD 4核+ 8 GB+ SAS, 200 GB+ 千兆网卡 1(可与 TiDB 同机器) TiKV 8核+ 32 GB+ SSD, 200 GB+ 千兆网卡 3 注: 验证测试环境中的 TiDB 和 PD 可以部署在同一台服务器上。 如进行性能相关的测试,避免采用低性能存储和网络硬件配置,防止对测试结果的正确性产生干扰。 如果仅验证功能,建议使用 Docker Compose 部署方案单机进行测试。 生产环境 组件 CPU 内存 硬盘类型 网络 实例数量(最低要求) TiDB 16核+ 32 GB+ SAS 万兆网卡(2块最佳) 2 PD 4核+ 8 GB+ SSD 万兆网卡(2块最佳) 3 TiKV 16核+ 32 GB+ SSD 万兆网卡(2块最佳) 3 监控 8核+ 16 GB+ SAS 千兆网卡 1 注: 生产环境中的 TiDB 和 PD 可以部署和运行在同服务器上,如对性能和可靠性有更高的要求,应尽可能分开部署。 生产环境强烈推荐使用更高的配置。 TiKV 硬盘大小配置建议 PCI-E SSD 不超过 2 TB,普通 SSD 不超过 1.5 TB。 网络要求 TiDB 作为开源分布式 NewSQL 数据库,其正常运行需要网络环境提供如下的网络端口配置要求,管理员可根据实际环境中 TiDB 组件部署的方案,在网络侧和主机侧开放相关端口: 组件 默认端口 说明 TiDB 4000 应用及 DBA 工具访问通信端口 TiDB 10080 TiDB 状态信息上报通信端口 TiKV 20160 TiKV 通信端口 PD 2379 提供 TiDB 和 PD 通信端口 PD 2380 PD 集群节点间通信端口 Pump 8250 Pump 通信端口 Drainer 8249 Drainer 通信端口 Prometheus 9090 Prometheus 服务通信端口 Pushgateway 9091 TiDB,TiKV,PD 监控聚合和上报端口 Node_exporter 9100 TiDB 集群每个节点的系统信息上报通信端口 Blackbox_exporter 9115 Blackbox_exporter 通信端口,用于 TiDB 集群端口监控 Grafana 3000 Web 监控服务对外服务和客户端(浏览器)访问端口 Grafana 8686 grafana_collector 通信端口,用于将 Dashboard 导出为 PDF 格式 Kafka_exporter 9308 Kafka_exporter 通信端口,用于监控 binlog kafka 集群 客户端 Web 浏览器要求 TiDB 提供了基于 Prometheus 和 Grafana 技术平台作为 TiDB 分布式数据库集群的可视化监控数据展现方案。建议用户采用高版本的微软 IE,Google Chrome,Mozilla Firefox 访问 Grafana 监控入口。"}, {"url": "https://pingcap.com/docs-cn/op-guide/op-guide/", "title": "TiDB 运维文档", "content": " TiDB 运维文档 软硬件环境需求 软硬件环境需求 部署集群 Ansible 部署方案 (强烈推荐) 离线 Ansible 部署方案 Docker 部署方案 跨数据中心部署方案 配置集群 配置参数 使用 Ansible 变更组件配置 监控集群 整体监控框架概述 重要监控指标详解 组件状态 API & 监控 扩容缩容 集群扩容缩容方案 使用 Ansible 扩容缩容 升级 使用 Anisble 升级组件版本 TiDB 2.0 升级操作指南 TiDB 2.1 升级操作指南 性能调优 TiKV 性能参数调优 备份与迁移 备份与恢复 数据迁移 全量导入 增量导入 "}, {"url": "https://pingcap.com/docs-cn/v1.0/op-guide/op-guide/", "title": "TiDB 运维文档", "content": " TiDB 运维文档 软硬件环境需求 软硬件环境需求 部署集群 Ansible 部署方案 (强烈推荐) 离线 Ansible 部署方案 (强烈推荐) Docker 部署方案 跨机房部署方案 配置集群 配置参数 监控集群 整体监控框架概述 重要监控指标详解 组件状态 API & 监控 扩容缩容 使用 Ansible 扩容缩容 集群扩容缩容方案 升级 使用 Ansible 升级 性能调优 TiKV 性能参数调优 备份与迁移 备份与恢复 数据迁移 全量导入 增量导入 Binary 部署方案 Binary 部署方案 "}, {"url": "https://pingcap.com/docs-cn/v2.0/op-guide/op-guide/", "title": "TiDB 运维文档", "content": " TiDB 运维文档 软硬件环境需求 软硬件环境需求 部署集群 Ansible 部署方案 (强烈推荐) 离线 Ansible 部署方案 (强烈推荐) Docker 部署方案 跨机房部署方案 配置集群 配置参数 监控集群 整体监控框架概述 重要监控指标详解 组件状态 API & 监控 扩容缩容 使用 Ansible 扩容缩容 集群扩容缩容方案 升级 使用 Ansible 升级 性能调优 TiKV 性能参数调优 备份与迁移 备份与恢复 数据迁移 全量导入 增量导入 Binary 部署方案 Binary 部署方案 "}, {"url": "https://pingcap.com/docs-cn/sql/server-command-option/", "title": "TiDB 进程启动参数", "content": " TiDB 进程启动参数 启动 TiDB 进程时,可以指定一些程序启动参数。TiDB 接受许多的启动参数,执行这个命令可以得到一个简要的说明:./tidb-server --help 获取版本信息可以使用下面命令:./tidb-server -V 以下是启动参数的完整描述。-L Log 级别 默认: “info” 可选值包括 debug, info, warn, error 或者 fatal -P TiDB 服务监听端口 默认: “4000” TiDB 服务将会使用这个端口接受 MySQL 客户端发过来的请求 --binlog-socket TiDB 服务使用 unix socket file 方式接受内部连接,如 PUMP 服务 默认: “” 譬如使用 “/tmp/pump.sock” 来接受 PUMP unix socket file 通信 --config TiDB 配置文件 默认: “” 配置文件的路径 --lease Schema 的租约时间,单位:秒 默认: “10” Schema 的 lease 主要用在 online schema changes 上面。这个值会影响到实际的 DDL 语句的执行时间。大多数情况下,用户不需要修改这个值,除非您清晰的了解 TiDB DDL 的内部实现机制 --host TiDB 服务监听 host 默认: “0.0.0.0” TiDB 服务会监听这个 host 0.0.0.0 默认会监听所有的网卡 address。如果有多块网卡,可以指定对外提供服务的网卡,譬如 192.168.100.113 --log-file Log 文件 默认: “” 如果没设置这个参数,log 会默认输出到 “stderr”,如果设置了, log 就会输出到对应的文件里面,在每天凌晨,log 会自动轮转使用一个新的文件,并且将以前的文件改名备份 --metrics-addr Prometheus Push Gateway 地址 默认: “” 如果为空,TiDB 不会将统计信息推送给 Push Gateway ,参数格式 如 --metrics-addr=192.168.100.115:9091 --metrics-intervel 推送统计信息到 Prometheus Push Gateway 的时间间隔 默认: 15s 设置为 0 表明不推送统计信息给 Push Gateway ,如: --metrics-interval=2 是每两秒推送到 Pushgateway --path 对于本地存储引擎 “goleveldb”, “BoltDB” 来说,path 指定的是实际的数据存放路径 对于 “memory” 存储引擎来说,path 不用设置 对于 “TiKV” 存储引擎来说,path 指定的是实际的 PD 地址。例如 PD 部署在 192.168.100.113:2379, 192.168.100.114:2379 和 192.168.100.115:2379 上面,那么 path 为 “192.168.100.113:2379, 192.168.100.114:2379, 192.168.100.115:2379” 默认: “/tmp/tidb” --report-status 打开 (true) 或者关闭 (false) 服务状态监听端口 默认: true 值可以为 (true) 或者 (false). (true) 表明开启状态监听端口。 (false) 表明关闭。状态监听端口用于通过 HTTP 方式对外报告一些服务内部信息 --run-ddl tidb-server 是否运行 DDL 语句,集群内大于两台以上 tidb-server 时设置 默认: true 值可以为 (true) 或者 (false). (true) 表明自身会运行 DDL. (false) 表明自身不会运行 DDL --socket string TiDB 服务使用 unix socket file 方式接受外部连接 默认: “” 譬如可以使用 “/tmp/tidb.sock” 来打开 unix socket file --status TiDB 服务状态监听端口 默认: “10080” 这个端口是为了展示 TiDB 内部数据用的。包括 prometheus 统计 以及 pprof Prometheus 统计可以通过 “http://host:status_port/metrics" 访问 Pprof 数据可以通过 “http://host:status_port/debug/pprof" 访问 --store 用来指定 TiDB 底层使用的存储引擎 默认: “mocktikv” 可选值包括 “memory”, “goleveldb”, “boltdb”, “mocktikv” 或者 “tikv”。(前面都是本地存储引擎,而 TiKV 是一个分布式存储引擎) 例如,通过 tidb-server --store=memory 来启动一个纯内存引擎的 TiDB TiDB 服务器配置文件 启动 TiDB 服务器时,通过 --config path 可以指定服务器的配置文件。对于配置中重叠的选项,命令行启动参数的优先级高于配置文件。一份配置文件的示例参见 https://github.com/pingcap/tidb/blob/master/config/config.toml.example以下是启动参数的完整描述。host 同启动参数 hostport 同启动参数 Ppath 同启动参数 pathsocket 同启动参数 socketbinlog-socket 同启动参数 binlog-socketrun-ddl 同启动参数 run-ddlcross-join 默认: true 在做 join 的时候,两边表没有任何条件(where 字段),默认可以执行这样的语句。但是设置为 false,则如有这样的 join 语句出现,server 会拒绝执行 force-priority 语句的默认优先级 默认: NO_PRIORITY TiDB 支持的语句优先级包括:NO_PRIORITY、LOW_PRIORITY、DELAYED 以及 HIGH_PRIORITY。例如,如果你需要为 OLAP 查询指定专属服务器池,可将该值设置为 LOW_PRIORITY,以保证 TiKV 服务器优先处理其他 TiDB 服务器池收到的 OLTP 请求。这样可以使 OLTP 性能更稳定,但 OLAP 性能可能会稍有下降 TiDB 自动将 table scan 设置为 LOW_PRIORITY,通过将 DML modifier 设置为 HIGH PRIORITY 或 LOW PRIORITY,可重写一条语句的优先级 join-concurrency join-concurrency 并发执行 join 的 goroutine 数量 默认: 5 看数据量和数据分布情况,一般情况下是越多越好,数值越大对 CPU 开销越大 query-log-max-len 日志中记录最大 sql 语句长度 默认: 2048 过长的请求输出到 log 时会被截断 slow-threshold int 大于这个值得 sql 语句将被记录 默认: 300 值只能是一个整数 (int) ,单位是毫秒 slow-query-file 慢查询日志文件 默认: “” 值是文件名,若指定了一个非空字符串,则慢查询日志会被重定向到相应的文件 retry-limit 事务遇见冲突时,提交事物最大重试次数 默认: 10 设置较大的重试次数会影响 TiDB 集群性能 skip-grant-table 允许任何人不带密码连接,并且所有的操作不检查权限 默认: false 值可以是(true) or (false)。启用此选项需要本机的 root 权限,一般用于忘记密码时重置 stats-lease 增量扫描全表并分析表的数据量 索引等一些信息 默认: “3s” 使用此参数需要先手动执行 analyze table name; 自动更新统计信息,持久化存储到 TiKV,会耗费一些内存开销, tcp-keep-alive TiDB 在 tcp 层开启 keepalive 默认: false ssl-cert PEM 格式的 SSL 证书文件路径 默认: “” 当同时设置了该选项和 --ssl-key 选项时,TiDB 将接受(但不强制)客户端使用 TLS 安全地连接到 TiDB。 若指定的证书或私钥无效,则 TiDB 会照常启动,但无法接受安全连接。 ssl-key PEM 格式的 SSL 证书密钥文件路径,即 --ssl-cert 所指定的证书的私钥 默认: “” 目前 TiDB 不支持加载由密码保护的私钥。 ssl-ca PEM 格式的受信任 CA 的证书文件路径 默认: “” 当同时设置了该选项和 --ssl-cert、--ssl-key 选项时,TiDB 将在客户端出示证书的情况下根据该选项指定的受信任的 CA 列表验证客户端证书。若验证失败,则连接会被终止。 即使设置了该选项,若客户端没有出示证书,则安全连接仍然继续,不会进行客户端证书验证。 "}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/server-command-option/", "title": "TiDB 进程启动参数和配置", "content": " TiDB 进程启动参数 启动 TiDB 进程时,可以指定一些程序启动参数。TiDB 接受许多的启动参数,执行这个命令可以得到一个简要的说明:./tidb-server --help 获取版本信息可以使用下面命令:./tidb-server -V 以下是启动参数的完整描述。-L Log 级别 默认: “info” 可选值包括 debug, info, warn, error 或者 fatal -P TiDB 服务监听端口 默认: “4000” TiDB 服务将会使用这个端口接受 MySQL 客户端发过来的请求 --binlog-socket TiDB 服务使用 unix socket file 方式接受内部连接,如 PUMP 服务 默认: “” 譬如使用 “/tmp/pump.sock” 来接受 PUMP unix socket file 通信 --config TiDB 配置文件 默认: “” 配置文件的路径 --lease Schema 的租约时间,单位:秒 默认: “10” Schema 的 lease 主要用在 online schema changes 上面。这个值会影响到实际的 DDL 语句的执行时间。大多数情况下,用户不需要修改这个值,除非您清晰的了解 TiDB DDL 的内部实现机制 --host TiDB 服务监听 host 默认: “0.0.0.0” TiDB 服务会监听这个 host 0.0.0.0 默认会监听所有的网卡 address。如果有多块网卡,可以指定对外提供服务的网卡,譬如 192.168.100.113 --log-file Log 文件 默认: “” 如果没设置这个参数,log 会默认输出到 “stderr”,如果设置了, log 就会输出到对应的文件里面,在每天凌晨,log 会自动轮转使用一个新的文件,并且将以前的文件改名备份 --metrics-addr Prometheus Push Gateway 地址 默认: “” 如果为空,TiDB 不会将统计信息推送给 Push Gateway ,参数格式 如 --metrics-addr=192.168.100.115:9091 --metrics-intervel 推送统计信息到 Prometheus Push Gateway 的时间间隔 默认: 15s 设置为 0 表明不推送统计信息给 Push Gateway ,如: --metrics-interval=2 是每两秒推送到 Push Gataway --path 对于本地存储引擎 “goleveldb”, “BoltDB” 来说,path 指定的是实际的数据存放路径 对于 “memory” 存储引擎来说,path 不用设置 对于 “TiKV” 存储引擎来说,path 指定的是实际的 PD 地址。例如 PD 部署在 192.168.100.113:2379, 192.168.100.114:2379 和 192.168.100.115:2379 上面,那么 path 为 “192.168.100.113:2379, 192.168.100.114:2379, 192.168.100.115:2379” 默认: “/tmp/tidb” --report-status 打开 (true) 或者关闭 (false) 服务状态监听端口 默认: true 值可以为 (true) 或者 (false). (true) 表明开启状态监听端口。 (false) 表明关闭。状态监听端口用于通过 HTTP 方式对外报告一些服务内部信息 --run-ddl tidb-server 是否运行 DDL 语句,集群内大于两台以上 tidb-server 时设置 默认: true 值可以为 (true) 或者 (false). (true) 表明自身会运行 DDL. (false) 表明自身不会运行 DDL --socket string TiDB 服务使用 unix socket file 方式接受外部连接 默认: “” 譬如可以使用 “/tmp/tidb.sock” 来打开 unix socket file --status TiDB 服务状态监听端口 默认: “10080” 这个端口是为了展示 TiDB 内部数据用的。包括 prometheus 统计 以及 pprof Prometheus 统计可以通过 “http://host:status_port/metrics" 访问 Pprof 数据可以通过 “http://host:status_port/debug/pprof" 访问 --store 用来指定 TiDB 底层使用的存储引擎 默认: “mocktikv” 可选值包括 “memory”, “goleveldb”, “boltdb”, “mocktikv” 或者 “tikv”。(前面都是本地存储引擎,而 TiKV 是一个分布式存储引擎) 例如,通过 tidb-server --store=memory 来启动一个纯内存引擎的 TiDB TiDB 服务器配置文件 启动 TiDB 服务器时,通过 --config path 可以指定服务器的配置文件。对于配置中重叠的选项,命令行启动参数的优先级高于配置文件。一份配置文件的示例参见 https://github.com/pingcap/tidb/blob/master/config/config.toml.example以下是启动参数的完整描述。host 同启动参数 hostport 同启动参数 Ppath 同启动参数 pathsocket 同启动参数 socketbinlog-socket 同启动参数 binlog-socketrun-ddl 同启动参数 run-ddlcross-join 默认: true 在做 join 的时候,两边表没有任何条件(where 字段),默认可以执行这样的语句。但是设置为 false,则如有这样的 join 语句出现,server 会拒绝执行 join-concurrency join-concurrency 并发执行 join 的 goroutine 数量 默认: 5 看数据量和数据分布情况,一般情况下是越多越好,数值越大对 CPU 开销越大 query-log-max-len 日志中记录最大 sql 语句长度 默认: 2048 过长的请求输出到 log 时会被截断 slow-threshold int 大于这个值得 sql 语句将被记录 默认: 300 值只能是一个整数 (int) ,单位是毫秒 slow-query-file 慢查询日志文件 默认: “” 值是文件名,若指定了一个非空字符串,则慢查询日志会被重定向到相应的文件 retry-limit 事务遇见冲突时,提交事物最大重试次数 默认: 10 设置较大的重试次数会影响 TiDB 集群性能 skip-grant-table 允许任何人不带密码连接,并且所有的操作不检查权限 默认: false 值可以是(true) or (false)。启用此选项需要本机的 root 权限,一般用于忘记密码时重置 stats-lease 增量扫描全表并分析表的数据量 索引等一些信息 默认: “3s” 使用此参数需要先手动执行 analyze table name; 自动更新统计信息,持久化存储到 TiKV,会耗费一些内存开销, tcp-keep-alive TiDB 在 tcp 层开启 keepalive 默认: false ssl-cert PEM 格式的 SSL 证书文件路径 默认: “” 当同时设置了该选项和 --ssl-key 选项时,TiDB 将接受(但不强制)客户端使用 TLS 安全地连接到 TiDB。 若指定的证书或私钥无效,则 TiDB 会照常启动,但无法接受安全连接。 ssl-key PEM 格式的 SSL 证书密钥文件路径,即 --ssl-cert 所指定的证书的私钥 默认: “” 目前 TiDB 不支持加载由密码保护的私钥。 ssl-ca PEM 格式的受信任 CA 的证书文件路径 默认: “” 当同时设置了该选项和 --ssl-cert、--ssl-key 选项时,TiDB 将在客户端出示证书的情况下根据该选项指定的受信任的 CA 列表验证客户端证书。若验证失败,则连接会被终止。 即使设置了该选项,若客户端没有出示证书,则安全连接仍然继续,不会进行客户端证书验证。 "}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/server-command-option/", "title": "TiDB 进程启动参数和配置", "content": " TiDB 进程启动参数 启动 TiDB 进程时,可以指定一些程序启动参数。TiDB 接受许多的启动参数,执行这个命令可以得到一个简要的说明:./tidb-server --help 获取版本信息可以使用下面命令:./tidb-server -V 以下是启动参数的完整描述。-L Log 级别 默认: “info” 可选值包括 debug, info, warn, error 或者 fatal -P TiDB 服务监听端口 默认: “4000” TiDB 服务将会使用这个端口接受 MySQL 客户端发过来的请求 --binlog-socket TiDB 服务使用 unix socket file 方式接受内部连接,如 PUMP 服务 默认: “” 譬如使用 “/tmp/pump.sock” 来接受 PUMP unix socket file 通信 --config TiDB 配置文件 默认: “” 配置文件的路径 --lease Schema 的租约时间,单位:秒 默认: “10” Schema 的 lease 主要用在 online schema changes 上面。这个值会影响到实际的 DDL 语句的执行时间。大多数情况下,用户不需要修改这个值,除非您清晰的了解 TiDB DDL 的内部实现机制 --host TiDB 服务监听 host 默认: “0.0.0.0” TiDB 服务会监听这个 host 0.0.0.0 默认会监听所有的网卡 address。如果有多块网卡,可以指定对外提供服务的网卡,譬如 192.168.100.113 --log-file Log 文件 默认: “” 如果没设置这个参数,log 会默认输出到 “stderr”,如果设置了, log 就会输出到对应的文件里面,在每天凌晨,log 会自动轮转使用一个新的文件,并且将以前的文件改名备份 --metrics-addr Prometheus Push Gateway 地址 默认: “” 如果为空,TiDB 不会将统计信息推送给 Push Gateway ,参数格式 如 --metrics-addr=192.168.100.115:9091 --metrics-intervel 推送统计信息到 Prometheus Push Gateway 的时间间隔 默认: 15s 设置为 0 表明不推送统计信息给 Push Gateway ,如: --metrics-interval=2 是每两秒推送到 Push Gataway --path 对于本地存储引擎 “goleveldb”, “BoltDB” 来说,path 指定的是实际的数据存放路径 对于 “memory” 存储引擎来说,path 不用设置 对于 “TiKV” 存储引擎来说,path 指定的是实际的 PD 地址。例如 PD 部署在 192.168.100.113:2379, 192.168.100.114:2379 和 192.168.100.115:2379 上面,那么 path 为 “192.168.100.113:2379, 192.168.100.114:2379, 192.168.100.115:2379” 默认: “/tmp/tidb” --report-status 打开 (true) 或者关闭 (false) 服务状态监听端口 默认: true 值可以为 (true) 或者 (false). (true) 表明开启状态监听端口。 (false) 表明关闭。状态监听端口用于通过 HTTP 方式对外报告一些服务内部信息 --run-ddl tidb-server 是否运行 DDL 语句,集群内大于两台以上 tidb-server 时设置 默认: true 值可以为 (true) 或者 (false). (true) 表明自身会运行 DDL. (false) 表明自身不会运行 DDL --socket string TiDB 服务使用 unix socket file 方式接受外部连接 默认: “” 譬如可以使用 “/tmp/tidb.sock” 来打开 unix socket file --status TiDB 服务状态监听端口 默认: “10080” 这个端口是为了展示 TiDB 内部数据用的。包括 prometheus 统计 以及 pprof Prometheus 统计可以通过 “http://host:status_port/metrics" 访问 Pprof 数据可以通过 “http://host:status_port/debug/pprof" 访问 --store 用来指定 TiDB 底层使用的存储引擎 默认: “mocktikv” 可选值包括 “memory”, “goleveldb”, “boltdb”, “mocktikv” 或者 “tikv”。(前面都是本地存储引擎,而 TiKV 是一个分布式存储引擎) 例如,通过 tidb-server --store=memory 来启动一个纯内存引擎的 TiDB TiDB 服务器配置文件 启动 TiDB 服务器时,通过 --config path 可以指定服务器的配置文件。对于配置中重叠的选项,命令行启动参数的优先级高于配置文件。一份配置文件的示例参见 https://github.com/pingcap/tidb/blob/master/config/config.toml.example以下是启动参数的完整描述。host 同启动参数 hostport 同启动参数 Ppath 同启动参数 pathsocket 同启动参数 socketbinlog-socket 同启动参数 binlog-socketrun-ddl 同启动参数 run-ddlcross-join 默认: true 在做 join 的时候,两边表没有任何条件(where 字段),默认可以执行这样的语句。但是设置为 false,则如有这样的 join 语句出现,server 会拒绝执行 join-concurrency join-concurrency 并发执行 join 的 goroutine 数量 默认: 5 看数据量和数据分布情况,一般情况下是越多越好,数值越大对 CPU 开销越大 query-log-max-len 日志中记录最大 sql 语句长度 默认: 2048 过长的请求输出到 log 时会被截断 slow-threshold int 大于这个值得 sql 语句将被记录 默认: 300 值只能是一个整数 (int) ,单位是毫秒 slow-query-file 慢查询日志文件 默认: “” 值是文件名,若指定了一个非空字符串,则慢查询日志会被重定向到相应的文件 retry-limit 事务遇见冲突时,提交事物最大重试次数 默认: 10 设置较大的重试次数会影响 TiDB 集群性能 skip-grant-table 允许任何人不带密码连接,并且所有的操作不检查权限 默认: false 值可以是(true) or (false)。启用此选项需要本机的 root 权限,一般用于忘记密码时重置 stats-lease 增量扫描全表并分析表的数据量 索引等一些信息 默认: “3s” 使用此参数需要先手动执行 analyze table name; 自动更新统计信息,持久化存储到 TiKV,会耗费一些内存开销, tcp-keep-alive TiDB 在 tcp 层开启 keepalive 默认: false ssl-cert PEM 格式的 SSL 证书文件路径 默认: “” 当同时设置了该选项和 --ssl-key 选项时,TiDB 将接受(但不强制)客户端使用 TLS 安全地连接到 TiDB。 若指定的证书或私钥无效,则 TiDB 会照常启动,但无法接受安全连接。 ssl-key PEM 格式的 SSL 证书密钥文件路径,即 --ssl-cert 所指定的证书的私钥 默认: “” 目前 TiDB 不支持加载由密码保护的私钥。 ssl-ca PEM 格式的受信任 CA 的证书文件路径 默认: “” 当同时设置了该选项和 --ssl-cert、--ssl-key 选项时,TiDB 将在客户端出示证书的情况下根据该选项指定的受信任的 CA 列表验证客户端证书。若验证失败,则连接会被终止。 即使设置了该选项,若客户端没有出示证书,则安全连接仍然继续,不会进行客户端证书验证。 "}, {"url": "https://pingcap.com/docs-cn/op-guide/tidb-config-file/", "title": "TiDB 配置项解释", "content": " TiDB 配置项解释 TiDB 配置文件比命令行参数支持更多的选项。你可以在 config/config.toml.example 找到默认的配置文件,重命名为 config.toml 即可。本文档只阐述未包含在命令行参数中的参数,命令行参数参见这里。split-table 为每个 table 建立单独的 Region。 默认: true 如果需要创建大量的表,我们建议把这个参数设置为 false。 oom-action 指定 TiDB 发生 out-of-memory 错误时的操作。 默认: “log” 现在合法的选项是 [“log”, “cancel”],如果为 “log”,仅仅是打印日志,不作实质处理。如果为 “cancel”,我们会取消执行这个操作,并且输出日志。 enable-streaming 开启 coprocessor 的 streaming 获取数据模式。 默认: false lower-case-table-names 这个选项可以设置 TiDB 的系统变量 lower_case_table_names 的值。 默认: 2 具体可以查看 MySQL 关于这个变量的描述 注意:目前 TiDB 只支持将该选项的值设为 2,即按照大小写来保存表名,按照小写来比较(不区分大小写)。 compatible-kill-query 设置 “kill” 语句的兼容性。 默认: false 在 TiDB 里面 “kill xxx” 语句和 MySQL 行为不一致。只有执行 “kill tidb xxx” 的时候,才会真正的杀死一条查询。当 compatible-kill-query 设置为 true 的时候,则兼容 MySQL 的行为,不需要 “tidb” 关键字。 log 日志相关的配置项。format 指定日志输出的格式,可选项为 [json, text, console]。 默认: “text” disable-timestamp 是否禁止在日志中输出时间戳。 默认: false 如果设置为 true,那么日志里面将不会输出时间戳。 slow-query-file 慢查询日志的文件名。 默认: “” 设置后,慢查询日志会单独输出到该文件。 slow-threshold 输出慢日志的耗时阈值。 默认: 300ms 当查询大于这个值,就会当做是一个慢查询,输出到慢查询日志。 expensive-threshold 输出 expensive 操作的行数阈值。 默认: 10000 当查询的行数(包括中间结果,基于统计信息)大于这个值,我们就会当成是一个 expensive 的操作,输出一个前缀带有 [EXPENSIVE_QUERY] 的日志。 query-log-max-len 最长的 SQL 输出长度。 默认: 2048 当语句的长度大于 query-log-max-len,将会被截断输出。 log.file filename 一般日志文件名字。 默认: “” 如果设置,会输出一般日志到这个文件。 max-size 日志文件的大小限制。 默认: 300MB 最大设置上限为 4GB。 max-days 日志最大保留的天数。 默认: 0 默认是不清理的,如果设置了,在 max-days 之后 TiDB 会清理过期的日志文件。 max-backups 保留的日志的最大数量。 默认: 0 默认全部保存,如果设置为 7,会最多保留 7 个老的日志文件。 log-rotate 是否每日创建一个新的日志文件。 默认: true 如果设置为 true,每天会新建新的日志文件,如果设置为 false,那么只会输出到一个日志文件。 security 安全相关配置。ssl-ca PEM 格式的受信任 CA 的证书文件路径 默认: “” 当同时设置了该选项和 --ssl-cert、--ssl-key 选项时,TiDB 将在客户端出示证书的情况下根据该选项指定的受信任的 CA 列表验证客户端证书。若验证失败,则连接会被终止。 即使设置了该选项,若客户端没有出示证书,则安全连接仍然继续,不会进行客户端证书验证。 ssl-cert PEM 格式的 SSL 证书文件路径 默认: “” 当同时设置了该选项和 --ssl-key 选项时,TiDB 将接受(但不强制)客户端使用 TLS 安全地连接到 TiDB。 若指定的证书或私钥无效,则 TiDB 会照常启动,但无法接受安全连接。 ssl-key PEM 格式的 SSL 证书密钥文件路径,即 --ssl-cert 所指定的证书的私钥 默认: “” 目前 TiDB 不支持加载由密码保护的私钥。 performance 性能相关配置。max-procs TiDB 的 CPU 使用数量。 默认: 0 默认为 0 表示使用机器上所有的 CPU,也可以设置成 n, 那么 TiDB 会使用 n 个 CPU 数量。 stmt-count-limit TiDB 一个事务允许的最大语句条数限制。 默认: 5000 在一个事务中,超过 stmt-count-limit 条语句后还没有 rollback 或者 commit,TiDB 将会返回 statement count 5001 exceeds the transaction limitation, autocommit = false 错误。 tcp-keep-alive TiDB 在 TCP 层开启 keepalive 默认: false retry-limit TiDB 在提交事务的时候遇到 key 冲突或者其他错误时进行的重试次数。 默认: 10 如果 TiDB 超过 retry-limit 次重试还是没有成功,将会返回错误。 cross-join 默认: true 在做 join 的时候,两边表没有任何条件(where 字段),默认可以执行这样的语句。但是设置为 false,则如有这样的 join 语句出现,server 会拒绝执行 stats-lease TiDB 重载统计信息, 更新表行数, 检查是否需要自动 analyze 以及加载列的统计信息的时间间隔 默认: 3s 每隔 stats-lease 时间, TiDB 会检查统计信息是否有更新,如果有会将其更新到内存中 每隔 5 * stats-lease 时间,TiDB 会将 DML 产生的总行数以及修改的行数变化持久化下来 每隔 stats-lease 时间,TiDB 会检查是否有表或者索引需要自动 analyze 每隔 stats-lease 时间,TiDB 会检查是否有列的统计信息需要被加载到内存中 run-auto-analyze TiDB 是否做自动的 Analyze。 默认: true feedback-probability TiDB 对查询收集统计信息反馈的概率 默认: 0 对于每一个查询,TiDB 会以 feedback-probability 的概率收集查询的反馈,用于更新统计信息。 prepared-plan-cache prepare 语句的 Plan cache 设置。enabled 开启 prepare 语句的 plan cache。 默认: false capacity 缓存语句的数量。 默认: 100 tikv-client grpc-connection-count 跟每个 TiKV 之间建立的最大连接数。 默认: 16 commit-timeout 执行事务提交时,最大的超时时间。 默认: 41s 这个值必须是大于两倍 Raft 选举的超时时间。 txn-local-latches 事务内存锁相关配置,当本地事务冲突比较多时建议开启。enable 开启 默认: false capacity Hash 对应的 slot 数, 会自动向上调整为 2 的指数倍。每个 slot 占 32 Bytes 内存。当写入数据的范围比较广时(如导数据),设置过小会导致变慢,性能下降。 默认:1024000 "}, {"url": "https://pingcap.com/docs-cn/op-guide/tidb-dashboard-info/", "title": "TiDB 重要监控指标详解", "content": " TiDB 重要监控指标详解 使用 Ansible 部署 TiDB 集群时,一键部署监控系统 (Prometheus/Grafana),监控架构请看 TiDB 监控框架概述。目前 Grafana Dashboard 整体分为 PD、TiDB、TiKV、Node_exporter、Overview 等。以下为 TiDB Dashboard 部分监控说明:说明 Query Summary Duration:SQL 执行的时间 Statement OPS:SQL 执行数量统计(包含 SELECT、INSERT、UPDATE 等) QPS By Instance:每个 TiDB 上的 QPS Query Detail Internal SQL OPS:TiDB 内部 SQL 语句执行数量统计 Server Connection count:每个 TiDB 的连接数 Failed Query OPM:失败 SQL 的统计,例如语法错误、主键冲突等 Heap Memory Usage:每个 TiDB 使用的堆内存大小 Events OPM:统计关键事件,例如 start,close,gracefull-shutdown,kill,hang 等 Uncommon Error OPM:TiDB 非正常错误的统计,包括 panic,binlog 写失败等 Transaction Transaction OPS:事务执行数量统计 Transaction Duration:事务执行的时间 Session Retry Error OPS:事务重试时遇到的错误数量 Executor Expensive Executor OPS:消耗系统资源比较多的算子统计,包括 Merge Join,Hash Join,Index Look Up Join,Hash Agg,Stream Agg,Sort,TopN 等 Queries Using Plan Cache OPS:使用 Plan Cache 的查询数量统计 Distsql Distsql Duration:Distsql 处理的时长 Distsql QPS:Distsql 的数量统计 KV Errors KV Retry Duration:KV 重试请求的时间 TiClient Region Error OPS:TiKV 返回 Region 相关错误信息的数量 KV Backoff OPS:TiKV 返回错误信息的数量(事务冲突等) Lock Resolve OPS:事务冲突相关的数量 Other Errors OPS:其他类型的错误数量,包括清锁和更新 SafePoint KV Duration KV Cmd Duration 99:KV 命令执行的时间 KV Count KV Cmd OPS:KV 命令执行数量统计 Txn OPS:启动事务的数量统计 Load SafePoint OPS:更新 SafePoint 的数量统计 PD Client PD TSO OPS:TiDB 从 PD 获取 TSO 的数量 PD TSO Wait Duration:TiDB 从 PD 获取 TSO 的时间 PD Client CMD OPS:PD Client 执行命令数量统计 PD Client CMD Duration: PD Client 执行命令耗时 PD Client CMD Fail OPS:PD Client 执行命令失败统计 Schema Load Load Schema Duration:TiDB 从 TiKV 获取 Schema 的时间 Load Schema OPS:TiDB 从 TiKV 获取 Schema 的数量统计 Schema Lease Error OPM:Schema Lease 出错,包括 change 和 outdate 两种,出现 outdate 错误时会报警 DDL DDL Duration 95:DDL 语句处理时间统计 DDL Batch Add Index Duration 100:创建索引时每个 Batch 所花费的时间统计 DDL Deploy Syncer Duration:Schema Version Syncer 初始化,重启,清空等操作耗时 Owner Handle Syncer Duration:DDL Owner 在执行更新,获取以及检查 Schema Version 的耗时 Update Self Version Duration:Schema Version Syncer 更新版本信息耗时 Statistics Auto Analyze Duration 95:自动 ANALYZE 耗时统计 Auto Analyze QPS:自动 ANALYZE 数量统计 Stats Inaccuracy Rate:统计信息不准确度统计 Pseudo Estimation OPS:使用假的统计信息优化 SQL 的数量统计 Dump Feedback OPS:存储统计信息 Feedback 的数量统计 Update Stats OPS:利用 Feedback 更新统计信息的数量统计 Meta AutoID QPS:AutoID 相关操作的数量统计,包括全局 ID 分配、单个 Table AutoID 分配、单个 Table AutoID Rebase 三种操作 AutoID Duration:AutoID 相关操作的耗时 GC Worker Action OPM:GC 相关操作的数量统计,包括 run_job,resolve_lock,delete_range 等操作 Duration 99:GC 相关操作的耗时统计 GC Failure OPM:GC 相关操作失败数量统计 Too Many Locks Error OPM:GC 清锁过多错误的数量统计 "}, {"url": "https://pingcap.com/docs-cn/op-guide/horizontal-scale/", "title": "TiDB 集群扩容缩容方案", "content": " TiDB 集群扩容缩容方案 概述 TiDB 集群可以在不影响线上服务的情况下动态进行扩容和缩容。 注:如果使用 Ansible 部署 TiDB 集群,请参考使用 Ansible 扩容缩容。 下面分别介绍如何增加或者删除 PD,TiKV 以及 TiDB 的节点。下面用到的 pd-ctl 文档可以参考 pd-control。PD 假设现在我们有三个 PD 服务,详细信息如下: Name ClientUrls PeerUrls pd1 http://host1:2379 http://host1:2380 pd2 http://host2:2379 http://host2:2380 pd3 http://host3:2379 http://host3:2380 我们可以通过 pd-ctl 来查看当前所有 PD 节点的信息:./pd-ctl -u http://host1:2379 >> member 动态添加节点 我们可以使用 join 参数,将一个新的 PD 服务加入到现有的 PD 集群里面。 如果我们需要添加 pd4,只需要在 --join 参数里面填入当前 PD 集群任意一个 PD 服务的 client url,比如:./bin/pd-server --name=pd4 --client-urls="http://host4:2379" --peer-urls="http://host4:2380" --join="http://host1:2379" 动态删除节点 如果我们需要删除 pd4,可以通过 pd-ctl 来完成:./pd-ctl -u http://host1:2379 >> member delete name pd4 动态迁移节点 如果想把现有的 PD 节点迁移到新的机器上,我们可以先在新的机器上添加节点,然后把旧的机器上的节点删除掉。迁移过程中应该一个节点一个节点逐个迁移,每完成一个步骤可以先查看一下当前的所有节点信息来进行确认。TiKV 我们可以通过 pd-ctl 来查看当前所有 TiKV 节点的信息:./pd-ctl -u http://host1:2379 >> store 动态添加节点 动态添加一个新的 TiKV 服务非常容易,只需要在新的机器上启动一个 TiKV 服务,不需要其他特殊操作。 新启动的 TiKV 服务会自动注册到现有集群的 PD 中,PD 会自动做负载均衡,逐步地把一部分数据迁移到新的TiKV 服务中,从而降低现有 TiKV 服务的压力。动态删除节点 安全地删除(下线)一个 TiKV 服务需要先告诉 PD,这样 PD 可以先把这个 TiKV 服务上面的数据迁移到其他 TiKV 服务上,保证数据有足够的副本数。假设我们需要删除 store id 为 1 的 TiKV 服务,可以通过 pd-ctl 来完成:./pd-ctl -u http://host1:2379 >> store delete 1 然后可以查看这个 TiKV 服务的状态:./pd-ctl -u http://host1:2379 >> store 1 { "store": { "id": 1, "address": "127.0.0.1:21060", "state": 1, "state_name": "Offline" }, "status": { ... } } 我们可以通过这个 store 的 state_name 来确定这个 store 的状态: Up:这个 store 正常服务 Disconnected:当前没有检测到这个 store 的心跳,可能是故障或网络连接中断 Down:超过一小时(可通过 max-down-time 配置)没有收到 store 心跳,此时 PD 会为这个 store 上的数据添加副本 Offline:这个 store 正在将其中的 Region 转移到其他节点,此时这个 store 仍在服务中 Tombstone:这个 store 已经完成下线,此时 store 上已经没有数据,可以关闭实例 动态迁移节点 迁移 TiKV 服务也是通过先在新的机器上添加节点,然后把旧的机器上的节点下线来完成。迁移过程中可以先把新集群的机器全部添加到已有的集群中,然后再把旧的节点一个一个地下线。可以通过查看正在下线的节点的状态信息来确定这个节点是否已经完成下线,确认完成以后再下线下一个节点。TiDB TiDB 是一个无状态的服务,这也就意味着我们能直接添加和删除 TiDB。需要注意的是,如果我们在 TiDB 的服务的前面搭建了一个 proxy(譬如 HAProxy),则需要更新 proxy 的配置并重新载入。"}, {"url": "https://pingcap.com/docs-cn/v1.0/op-guide/horizontal-scale/", "title": "TiDB 集群扩容缩容方案", "content": " TiDB 集群扩容缩容方案 概述 TiDB 集群可以在不影响线上服务的情况下动态进行扩容和缩容。下面分别介绍如果增加或者删除 PD,TiKV 以及 TiDB 的节点。下面用到的 pd-ctl 文档可以参考 pd-control。PD 假设现在我们有三个 PD 服务,详细信息如下: Name ClientUrls PeerUrls pd1 http://host1:2379 http://host1:2380 pd2 http://host2:2379 http://host2:2380 pd3 http://host3:2379 http://host3:2380 我们可以通过 pd-ctl 来查看当前所有 PD 节点的信息:./pd-ctl -u http://host1:2379 >> member 动态添加节点 我们可以使用 join 参数,将一个新的 PD 服务加入到现有的 PD 集群里面。 如果我们需要添加 pd4,只需要在 --join 参数里面填入当前 PD 集群任意一个 PD 服务的 client url,比如:./bin/pd-server --name=pd4 --client-urls="http://host4:2379" --peer-urls="http://host4:2380" --join="http://host1:2379" 动态删除节点 如果我们需要删除 pd4,可以通过 pd-ctl 来完成:./pd-ctl -u http://host1:2379 >> member delete pd4 动态迁移节点 如果想把现有的 PD 节点迁移到新的机器上,我们可以先在新的机器上添加节点,然后把旧的机器上的节点删除掉。 迁移过程中应该一个节点一个节点逐个迁移,每完成一个步骤可以先查看一下当前的所有节点信息来进行确认。TiKV 我们可以通过 pd-ctl 来查看当前所有 TiKV 节点的信息:./pd-ctl -u http://host1:2379 >> store 动态添加节点 动态添加一个新的 TiKV 服务非常容易,只需要在新的机器上启动一个 TiKV 服务,不需要其他特殊操作。 新启动的 TiKV 服务会自动注册到现有集群的 PD 中,PD 会自动做负载均衡,逐步地把一部分数据迁移到新的TiKV 服务中,从而降低现有 TiKV 服务的压力。动态删除节点 安全地删除(下线)一个 TiKV 服务需要先告诉 PD,这样 PD 可以先把这个 TiKV 服务上面的数据迁移到其他 TiKV 服务上,保证数据有足够的副本数。假设我们需要删除 store id 为 1 的 TiKV 服务,可以通过 pd-ctl 来完成:./pd-ctl -u http://host1:2379 >> store delete 1 然后可以查看这个 TiKV 服务的状态:./pd-ctl -u http://host1:2379 >> store 1 { "store": { "id": 1, "address": "127.0.0.1:21060", "state": 1, "state_name": "Offline" }, "status": { ... } } 我们可以通过这个 store 的 state_name 来确定这个 store 的状态: state_name=Up: 这个 store 正常服务 state_name=Disconnected: 当前没有检测到这个 store 的心跳,可能是故障或网络连接中断 state_name=Down: 超过一小时(可通过 max-down-time 配置)没有收到 store 心跳,此时 PD 会为这个 store 上的数据添加副本 state_name=Offline: 这个 store 正在下线,此时 store 仍在服务中 state_name=Tombstone: 这个 store 已经完成下线,此时 store 上已经没有数据,可以关闭实例 动态迁移节点 迁移 TiKV 服务也是通过先在新的机器上添加节点,然后把旧的机器上的节点下线来完成。 迁移过程中可以先把新集群的机器全部添加到已有的集群中,然后再把旧的节点一个一个地下线。 可以通过查看正在下线的节点的状态信息来确定这个节点是否已经完成下线,确认完成以后再下线下一个节点。TiDB TiDB 是一个无状态的服务,这也就意味着我们能直接添加和删除 TiDB。 需要注意的是,如果我们在 TiDB 的服务的前面搭建了一个 proxy(譬如 HAProxy),则需要更新 proxy 的配置并重新载入。"}, {"url": "https://pingcap.com/docs-cn/v2.0/op-guide/horizontal-scale/", "title": "TiDB 集群扩容缩容方案", "content": " TiDB 集群扩容缩容方案 概述 TiDB 集群可以在不影响线上服务的情况下动态进行扩容和缩容。下面分别介绍如果增加或者删除 PD,TiKV 以及 TiDB 的节点。下面用到的 pd-ctl 文档可以参考 pd-control。PD 假设现在我们有三个 PD 服务,详细信息如下: Name ClientUrls PeerUrls pd1 http://host1:2379 http://host1:2380 pd2 http://host2:2379 http://host2:2380 pd3 http://host3:2379 http://host3:2380 我们可以通过 pd-ctl 来查看当前所有 PD 节点的信息:./pd-ctl -u http://host1:2379 >> member 动态添加节点 我们可以使用 join 参数,将一个新的 PD 服务加入到现有的 PD 集群里面。 如果我们需要添加 pd4,只需要在 --join 参数里面填入当前 PD 集群任意一个 PD 服务的 client url,比如:./bin/pd-server --name=pd4 --client-urls="http://host4:2379" --peer-urls="http://host4:2380" --join="http://host1:2379" 动态删除节点 如果我们需要删除 pd4,可以通过 pd-ctl 来完成:./pd-ctl -u http://host1:2379 >> member delete pd4 动态迁移节点 如果想把现有的 PD 节点迁移到新的机器上,我们可以先在新的机器上添加节点,然后把旧的机器上的节点删除掉。 迁移过程中应该一个节点一个节点逐个迁移,每完成一个步骤可以先查看一下当前的所有节点信息来进行确认。TiKV 我们可以通过 pd-ctl 来查看当前所有 TiKV 节点的信息:./pd-ctl -u http://host1:2379 >> store 动态添加节点 动态添加一个新的 TiKV 服务非常容易,只需要在新的机器上启动一个 TiKV 服务,不需要其他特殊操作。 新启动的 TiKV 服务会自动注册到现有集群的 PD 中,PD 会自动做负载均衡,逐步地把一部分数据迁移到新的TiKV 服务中,从而降低现有 TiKV 服务的压力。动态删除节点 安全地删除(下线)一个 TiKV 服务需要先告诉 PD,这样 PD 可以先把这个 TiKV 服务上面的数据迁移到其他 TiKV 服务上,保证数据有足够的副本数。假设我们需要删除 store id 为 1 的 TiKV 服务,可以通过 pd-ctl 来完成:./pd-ctl -u http://host1:2379 >> store delete 1 然后可以查看这个 TiKV 服务的状态:./pd-ctl -u http://host1:2379 >> store 1 { "store": { "id": 1, "address": "127.0.0.1:21060", "state": 1, "state_name": "Offline" }, "status": { ... } } 我们可以通过这个 store 的 state_name 来确定这个 store 的状态: state_name=Up: 这个 store 正常服务 state_name=Disconnected: 当前没有检测到这个 store 的心跳,可能是故障或网络连接中断 state_name=Down: 超过一小时(可通过 max-down-time 配置)没有收到 store 心跳,此时 PD 会为这个 store 上的数据添加副本 state_name=Offline: 这个 store 正在下线,此时 store 仍在服务中 state_name=Tombstone: 这个 store 已经完成下线,此时 store 上已经没有数据,可以关闭实例 动态迁移节点 迁移 TiKV 服务也是通过先在新的机器上添加节点,然后把旧的机器上的节点下线来完成。 迁移过程中可以先把新集群的机器全部添加到已有的集群中,然后再把旧的节点一个一个地下线。 可以通过查看正在下线的节点的状态信息来确定这个节点是否已经完成下线,确认完成以后再下线下一个节点。TiDB TiDB 是一个无状态的服务,这也就意味着我们能直接添加和删除 TiDB。 需要注意的是,如果我们在 TiDB 的服务的前面搭建了一个 proxy(譬如 HAProxy),则需要更新 proxy 的配置并重新载入。"}, {"url": "https://pingcap.com/docs-cn/trouble-shooting/", "title": "TiDB 集群故障诊断", "content": " TiDB 集群故障诊断 当试用 TiDB 遇到问题时,请先参考本篇文档。如果问题未解决,请按文档要求收集必要的信息通过 Github 提供给 TiDB 开发者。如何给 TiDB 开发者报告错误 当使用 TiDB 遇到问题并且通过后面所列信息无法解决时,请收集以下信息并创建新 Issue: 具体的出错信息以及正在执行的操作 当前所有组件的状态 出问题组件 log 中的 error/fatal/panic 信息 机器配置以及部署拓扑 dmesg 中 TiDB 组件相关的问题 数据库连接不上 首先请确认集群的各项服务是否已经启动,包括 tidb-server、pd-server、tikv-server。请用 ps 命令查看所有进程是否在。如果某个组件的进程已经不在了,请参考对应的章节排查错误。如果所有的进程都在,请查看 tidb-server 的日志,看是否有报错?常见的错误包括: InformationSchema is out of date无法连接 tikv-server,请检查 pd-server 以及 tikv-server 的状态和日志。 panic程序有错误,请将具体的 panic log 提供给 TiDB 开发者。如果是清空数据并重新部署服务,请确认以下信息: pd-server、tikv-server 数据都已清空tikv-server 存储具体的数据,pd-server 存储 tikv-server 中数据的的元信息。如果只清空 pd-server 或只清空 tikv-server 的数据,会导致两边数据不匹配。 清空 pd-server 和 tikv-server 的数据并重启后,也需要重启 tidb-server集群 ID 是由 pd-server 在集群初始化时随机分配,所以重新部署集群后,集群 ID 会发生变化。tidb-server 业务需要重启以获取新的集群 ID。 tidb-server 启动报错 tidb-server 无法启动的常见情况包括: 启动参数错误请参考TiDB 命令行参数 端口被占用:lsof -i:port请确保 tidb-server 启动所需要的端口未被占用。 无法连接 pd-server首先检查 pd-server 的进程状态和日志,确保 pd-server 成功启动,对应端口已打开:lsof -i:port。若 pd-server 正常,则需要检查 tidb-server 机器和 pd-server 对应端口之间的连通性, 确保网段连通且对应服务端口已添加到防火墙白名单中,可通过 nc 或 curl 工具检查。例如,假设 tidb 服务位于 192.168.1.100,无法连接的 pd 位于 192.168.1.101,且 2379 为其 client port, 则可以在 tidb 机器上执行 nc -v -z 192.168.1.101 2379,测试是否可以访问端口。 或使用 curl -v 192.168.1.101:2379/pd/api/v1/leader 直接检查 pd 是否正常服务。 tikv-server 启动报错 启动参数错误请参考TiKV 启动参数文档。 端口被占用:lsof -i:port请确保 tikv-server 启动所需要的端口未被占用: lsof -i:port。 无法连接 pd-server首先检查 pd-server 的进程状态和日志。确保 pd-server 成功启动,对应端口已打开:lsof -i:port。若 pd-server 正常,则需要检查 tikv-server 机器和 pd-server 对应端口之间的连通性, 确保网段连通且对应服务端口已添加到防火墙白名单中,可通过 nc 或 curl 工具检查。具体命令参考上一节。 文件被占用不要在一个数据库文件目录上打开两个 tikv。 pd-server 启动报错 启动参数错误请参考PD 命令行参数文档。 端口被占用:lsof -i:port请确保 pd-server 启动所需要的端口未被占用: lsof -i:port。 TiDB/TiKV/PD 进程异常退出 进程是否是启动在前台当前终端退出给其所有子进程发送 HUP 信号,从而导致进程退出。 是否是在命令行用过 nohup+& 方式直接运行这样依然可能导致进程因终端连接突然中断,作为终端 SHELL 的子进程被杀掉。 推荐将启动命令写在脚本中,通过脚本运行(相当于二次 fork 启动)。 TiKV 进程异常重启 检查 dmesg 或者 syslog 里面是否有 OOM 信息如果有 OOM 信息并且杀掉的进程为 TiKV,请减少 TiKV 的 RocksDB 的各个 CF 的 block-cache-size 值。 检查 TiKV 日志是否有 panic 的 log提交 Issue 并附上 panic 的 log。 TiDB panic 请提供 panic 的 log连接被拒绝 请确保操作系统的网络参数正确,包括但不限于 连接字符串中的端口和 tidb-server 启动的端口需要一致 请保证防火墙的配置正确 Too many open files 在启动进程之前,请确保 ulimit -n 的结果足够大,推荐设为 unlimited 或者是大于 1000000。数据库访问超时,系统负载高 首先检查 SLOW-QUERY 日志, 判断是否是因为某条 SQL 语句导致。 如果未能解决,请提供如下信息: 部署的拓扑结构 tidb-server/pd-server/tikv-server 部署了几个实例 这些实例在机器上是如何分布的 机器的硬件配置 CPU 核数 内存大小 硬盘类型(SSD 还是机械硬盘) 是实体机还是虚拟机 机器上除了 TiDB 集群之外是否还有其他服务 pd-server 和 tikv-server 是否分开部署 目前正在进行什么操作 用 top -H 命令查看当前占用 CPU 的线程名 最近一段时间的网络/IO 监控数据是否有异常 "}, {"url": "https://pingcap.com/docs-cn/v1.0/trouble-shooting/", "title": "TiDB 集群故障诊断", "content": " TiDB 集群故障诊断 当试用 TiDB 遇到问题时,请先参考本篇文档。如果问题未解决,请按文档要求收集必要的信息通过 Github 提供给 TiDB 开发者。如何给 TiDB 开发者报告错误 当使用 TiDB 遇到问题并且通过后面所列信息无法解决时,请收集以下信息并创建新 Issue: 具体的出错信息以及正在执行的操作 当前所有组件的状态 出问题组件 log 中的 error/fatal/panic 信息 机器配置以及部署拓扑 dmesg 中 TiDB 组件相关的问题 数据库连接不上 首先请确认集群的各项服务是否已经启动,包括 tidb-server、pd-server、tikv-server。请用 ps 命令查看所有进程是否在。如果某个组件的进程已经不在了,请参考对应的章节排查错误。如果所有的进程都在,请查看 tidb-server 的日志,看是否有报错?常见的错误包括: InfomationSchema is out of date无法连接 tikv-server,请检查 pd-server 以及 tikv-server 的状态和日志。 panic程序有错误,请将具体的 panic log 提供给 TiDB 开发者。 如果是清空数据并重新部署服务,请确认以下信息: pd-server、tikv-server 数据都已清空tikv-server 存储具体的数据,pd-server 存储 tikv-server 中数据的的元信息。如果只清空 pd-server 或只清空 tikv-server 的数据,会导致两边数据不匹配。 清空 pd-server 和 tikv-server 的数据并重启后,也需要重启 tidb-server集群 ID 是由 pd-server 在集群初始化时随机分配,所以重新部署集群后,集群 ID 会发生变化。tidb-server 业务需要重启以获取新的集群 ID。 tidb-server 启动报错 tidb-server 无法启动的常见情况包括: 启动参数错误请参考TiDB 命令行参数文档。 端口被占用:lsof -i:port请确保 tidb-server 启动所需要的端口未被占用。 无法连接 pd-server首先检查 pd-server 的进程状态和日志,确保 pd-server 成功启动,对应端口已打开:lsof -i:port。若 pd-server 正常,则需要检查 tidb-server 机器和 pd-server 对应端口之间的连通性, 确保网段连通且对应服务端口已添加到防火墙白名单中,可通过 nc 或 curl 工具检查。例如,假设 tidb 服务位于 192.168.1.100,无法连接的 pd 位于 192.168.1.101,且 2379 为其 client port, 则可以在 tidb 机器上执行 nc -v -z 192.168.1.101 2379,测试是否可以访问端口。 或使用 curl -v 192.168.1.101:2379/pd/api/v1/leader 直接检查 pd 是否正常服务。 tikv-server 启动报错 启动参数错误请参考TiKV 启动参数文档。 端口被占用:lsof -i:port请确保 tikv-server 启动所需要的端口未被占用: lsof -i:port。 无法连接 pd-server首先检查 pd-server 的进程状态和日志。确保 pd-server 成功启动,对应端口已打开:lsof -i:port。若 pd-server 正常,则需要检查 tikv-server 机器和 pd-server 对应端口之间的连通性, 确保网段连通且对应服务端口已添加到防火墙白名单中,可通过 nc 或 curl 工具检查。具体命令参考上一节。 文件被占用不要在一个数据库文件目录上打开两个 tikv。 pd-server 启动报错 启动参数错误请参考PD 命令行参数文档。 端口被占用:lsof -i:port请确保 pd-server 启动所需要的端口未被占用: lsof -i:port。 TiDB/TiKV/PD 进程异常退出 进程是否是启动在前台当前终端退出给其所有子进程发送 HUP 信号,从而导致进程退出。 是否是在命令行用过 nohup+& 方式直接运行这样依然可能导致进程因终端连接突然中断,作为终端 SHELL 的子进程被杀掉。 推荐将启动命令写在脚本中,通过脚本运行(相当于二次 fork 启动)。 TiKV 进程异常重启 检查 dmesg 或者 syslog 里面是否有 OOM 信息如果有 OOM 信息并且杀掉的进程为 TiKV,请减少 TiKV 的 RocksDB 的各个 CF 的 block-cache-size 值。 检查 TiKV 日志是否有 panic 的 log提交 Issue 并附上 panic 的 log。 TiDB panic 请提供 panic 的 log连接被拒绝 请确保操作系统的网络参数正确,包括但不限于 连接字符串中的端口和 tidb-server 启动的端口需要一致 请保证防火墙的配置正确 Too many open files 在启动进程之前,请确保 ulimit -n 的结果足够大,推荐设为 unlimited 或者是大于 1000000。数据库访问超时,系统负载高 首先请提供如下信息: 部署的拓扑结构 tidb-server/pd-server/tikv-server 部署了几个实例 这些实例在机器上是如何分布的 机器的硬件配置 CPU 核数 内存大小 硬盘类型(SSD 还是机械硬盘) 是实体机还是虚拟机 机器上除了 TiDB 集群之外是否还有其他服务 pd-server 和 tikv-server 是否分开部署 目前正在进行什么操作 用 top -H 命令查看当前占用 CPU 的线程名 最近一段时间的网络/IO 监控数据是否有异常 "}, {"url": "https://pingcap.com/docs-cn/v2.0/trouble-shooting/", "title": "TiDB 集群故障诊断", "content": " TiDB 集群故障诊断 当试用 TiDB 遇到问题时,请先参考本篇文档。如果问题未解决,请按文档要求收集必要的信息通过 Github 提供给 TiDB 开发者。如何给 TiDB 开发者报告错误 当使用 TiDB 遇到问题并且通过后面所列信息无法解决时,请收集以下信息并创建新 Issue: 具体的出错信息以及正在执行的操作 当前所有组件的状态 出问题组件 log 中的 error/fatal/panic 信息 机器配置以及部署拓扑 dmesg 中 TiDB 组件相关的问题 数据库连接不上 首先请确认集群的各项服务是否已经启动,包括 tidb-server、pd-server、tikv-server。请用 ps 命令查看所有进程是否在。如果某个组件的进程已经不在了,请参考对应的章节排查错误。如果所有的进程都在,请查看 tidb-server 的日志,看是否有报错?常见的错误包括: InfomationSchema is out of date无法连接 tikv-server,请检查 pd-server 以及 tikv-server 的状态和日志。 panic程序有错误,请将具体的 panic log 提供给 TiDB 开发者。 如果是清空数据并重新部署服务,请确认以下信息: pd-server、tikv-server 数据都已清空tikv-server 存储具体的数据,pd-server 存储 tikv-server 中数据的的元信息。如果只清空 pd-server 或只清空 tikv-server 的数据,会导致两边数据不匹配。 清空 pd-server 和 tikv-server 的数据并重启后,也需要重启 tidb-server集群 ID 是由 pd-server 在集群初始化时随机分配,所以重新部署集群后,集群 ID 会发生变化。tidb-server 业务需要重启以获取新的集群 ID。 tidb-server 启动报错 tidb-server 无法启动的常见情况包括: 启动参数错误请参考TiDB 命令行参数文档。 端口被占用:lsof -i:port请确保 tidb-server 启动所需要的端口未被占用。 无法连接 pd-server首先检查 pd-server 的进程状态和日志,确保 pd-server 成功启动,对应端口已打开:lsof -i:port。若 pd-server 正常,则需要检查 tidb-server 机器和 pd-server 对应端口之间的连通性, 确保网段连通且对应服务端口已添加到防火墙白名单中,可通过 nc 或 curl 工具检查。例如,假设 tidb 服务位于 192.168.1.100,无法连接的 pd 位于 192.168.1.101,且 2379 为其 client port, 则可以在 tidb 机器上执行 nc -v -z 192.168.1.101 2379,测试是否可以访问端口。 或使用 curl -v 192.168.1.101:2379/pd/api/v1/leader 直接检查 pd 是否正常服务。 tikv-server 启动报错 启动参数错误请参考TiKV 启动参数文档。 端口被占用:lsof -i:port请确保 tikv-server 启动所需要的端口未被占用: lsof -i:port。 无法连接 pd-server首先检查 pd-server 的进程状态和日志。确保 pd-server 成功启动,对应端口已打开:lsof -i:port。若 pd-server 正常,则需要检查 tikv-server 机器和 pd-server 对应端口之间的连通性, 确保网段连通且对应服务端口已添加到防火墙白名单中,可通过 nc 或 curl 工具检查。具体命令参考上一节。 文件被占用不要在一个数据库文件目录上打开两个 tikv。 pd-server 启动报错 启动参数错误请参考PD 命令行参数文档。 端口被占用:lsof -i:port请确保 pd-server 启动所需要的端口未被占用: lsof -i:port。 TiDB/TiKV/PD 进程异常退出 进程是否是启动在前台当前终端退出给其所有子进程发送 HUP 信号,从而导致进程退出。 是否是在命令行用过 nohup+& 方式直接运行这样依然可能导致进程因终端连接突然中断,作为终端 SHELL 的子进程被杀掉。 推荐将启动命令写在脚本中,通过脚本运行(相当于二次 fork 启动)。 TiKV 进程异常重启 检查 dmesg 或者 syslog 里面是否有 OOM 信息如果有 OOM 信息并且杀掉的进程为 TiKV,请减少 TiKV 的 RocksDB 的各个 CF 的 block-cache-size 值。 检查 TiKV 日志是否有 panic 的 log提交 Issue 并附上 panic 的 log。 TiDB panic 请提供 panic 的 log连接被拒绝 请确保操作系统的网络参数正确,包括但不限于 连接字符串中的端口和 tidb-server 启动的端口需要一致 请保证防火墙的配置正确 Too many open files 在启动进程之前,请确保 ulimit -n 的结果足够大,推荐设为 unlimited 或者是大于 1000000。数据库访问超时,系统负载高 首先请提供如下信息: 部署的拓扑结构 tidb-server/pd-server/tikv-server 部署了几个实例 这些实例在机器上是如何分布的 机器的硬件配置 CPU 核数 内存大小 硬盘类型(SSD 还是机械硬盘) 是实体机还是虚拟机 机器上除了 TiDB 集群之外是否还有其他服务 pd-server 和 tikv-server 是否分开部署 目前正在进行什么操作 用 top -H 命令查看当前占用 CPU 的线程名 最近一段时间的网络/IO 监控数据是否有异常 "}, {"url": "https://pingcap.com/docs-cn/op-guide/monitor/", "title": "TiDB 集群监控", "content": " TiDB 集群监控 TiDB 集群状态监控目前有两种接口,第一种是通过 HTTP 接口对外汇报组件的信息,我们称之为组件的状态接口;第二种是使用 prometheus 记录组件中各种操作的详细信息,我们称之为 metrics 接口。组件状态接口 这类接口可以获取组件的一些基本信息,并且可以作为 keepalive 监测接口。另外 PD 的接口可以看到整个 TiKV 集群的详细信息。TiDB Server TiDB API 地址:http://${host}:${port}。其中 port 默认为 10080,各类 api_name 详细信息参见 TiDB API Doc。下面示例中,通过访问 http://${host}:${port}/status 获取当前 TiDB Server 的状态,以及判断是否存活。返回结果为 Json 格式:curl http://127.0.0.1:10080/status { connections: 0, version: "5.5.31-TiDB-1.0", git_hash: "b99521846ff6f71f06e2d49a3f98fa1c1d93d91b" } connections:当前 TiDB Server 上的客户端连接数 version:TiDB 版本号 git_hash:TiDB 当前代码的 Git Hash PD Server PD API 地址:http://${host}:${port}/pd/api/v1/${api_name}。其中 port 默认为 2379,各类 api_name 详细信息参见 PD API Doc。通过这个接口可以获取当前所有 TiKV 的状态以及负载均衡信息。其中最重要也是最常用的接口获取 TiKV 集群所有节点状态的接口,下面以一个单个 TiKV 构成的集群为例,说明一些用户需要了解的信息:curl http://127.0.0.1:2379/pd/api/v1/stores { "count": 1, TiKV 节点数量 "stores": [ // TiKV 节点的列表 // 下面列出的是这个集群中单个 TiKV 节点的信息 { "store": { "id": 1, "address": "127.0.0.1:22161", "state": 0 }, "status": { "store_id": 1, // 节点的 ID "capacity": 1968874332160, // 存储总容量 "available": 1264847716352, // 存储剩余容量 "region_count": 1, // 该节点上存放的 Region 数量 "sending_snap_count": 0, "receiving_snap_count": 0, "start_ts": "2016-10-24T19:54:00.110728339+08:00", // 启动时间 "last_heartbeat_ts": "2016-10-25T10:52:54.973669928+08:00", // 最后一次心跳时间 "total_region_count": 1, // 总 Region 数量 "leader_region_count": 1, // Leader Region 数量 "uptime": "14h58m54.862941589s" }, "scores": [ 100, 35 ] } ] } Metrics 监控 这部分主要对整个集群的状态、性能做监控,通过 Prometheus+Grafana 展现 metrics 数据,在下面一节会介绍如何搭建监控系统。TiDB Server query 处理时间,可以看到延迟和吞吐 ddl 过程监控 TiKV client 相关的监控 PD client 相关的监控 PD Server 命令执行的总次数 某个命令执行失败的总次数 某个命令执行成功的耗时统计 某个命令执行失败的耗时统计 某个命令执行完成并返回结果的耗时统计 TiKV Server GC 监控 执行 KV 命令的总次数 Scheduler 执行命令的耗时统计 Raft propose 命令的总次数 Raft 执行命令的耗时统计 Raft 执行命令失败的总次数 Raft 处理 ready 状态的总次数 使用 Prometheus+Grafana 部署架构 整个架构如下图所示,在 TiDB/PD/TiKV 三个组件的启动参数中添加 Prometheus Pushgateway 地址:搭建监控系统 Prometheus Push Gateway 参考:https://github.com/prometheus/pushgateway Prometheus Server 参考:https://github.com/prometheus/prometheus#install Grafana 参考:http://docs.grafana.org 配置 TiDB/PD/TiKV 配置 TiDB设置 --metrics-addr 和 --metrics-interval 两个参数,其中 metrics-addr 设为 Push Gateway 的地址,metrics-interval 为 push 的频率,单位为秒,默认值为 15 PD修改 toml 配置文件,填写 Push Gateway 的地址和推送频率[metric] # prometheus client push interval, set "0s" to disable prometheus. interval = "15s" # prometheus pushgateway address, leaves it empty will disable prometheus. address = "host:port" TiKV修改 toml 配置文件,填写 Push Gateway 的地址和推送频率,job 字段一般设为“tikv”。[metric] # the Prometheus client push interval. Setting the value to 0s stops Prometheus client from pushing. interval = "15s" # the Prometheus pushgateway address. Leaving it empty stops Prometheus client from pushing. address = "host:port" # the Prometheus client push job name. Note: A node id will automatically append, e.g., "tikv_1". job = "tikv" PushServer 配置 一般无需特殊配置,使用默认端口 9091 即可Prometheus 配置 在 yaml 配置文件中添加 Push Gateway 地址:scrape_configs: # The job name is added as a label `job=<job_name>` to any timeseries scraped from this config. - job_name: 'TiDB' # Override the global default and scrape targets from this job every 5 seconds. scrape_interval: 5s honor_labels: true static_configs: - targets: ['host:port'] # use the Push Gateway address labels: group: 'production' Grafana 配置 进入 Grafana Web 界面(默认地址: http://localhost:3000 ,默认账号: admin 密码: admin)点击 Grafana Logo -> 点击 Data Sources -> 点击 Add data source -> 填写 data source 信息 ( 注: Type 选 Prometheus,Url 为 Prometheus 地址,其他根据实际情况填写 ) 导入 dashboard 配置文件点击 Grafana Logo -> 点击 Dashboards -> 点击 Import -> 选择需要的 Dashboard 配置文件上传 -> 选择对应的 data source "}, {"url": "https://pingcap.com/docs-cn/v1.0/op-guide/monitor/", "title": "TiDB 集群监控", "content": " TiDB 集群监控 TiDB 集群状态监控目前有两种接口,第一种是通过 HTTP 接口对外汇报组件的信息,我们称之为组件的状态接口;第二种是使用 prometheus 记录组件中各种操作的详细信息,我们称之为 metrics 接口。组件状态接口 这类接口可以获取组件的一些基本信息,并且可以作为 keepalive 监测接口。另外 PD 的接口可以看到整个 TiKV 集群的详细信息。TiDB Server TiDB 对外暴露的 HTTP 接口是 http://host:port/status ,默认的端口号是 10080 (可以通过 –status 参数设置),可以通过访问这个接口获取当前 TiDB Server 的状态,以及判断是否存活。返回结果是 Json 格式:curl http://127.0.0.1:10080/status { connections: 0, version: "5.5.31-TiDB-1.0", git_hash: "b99521846ff6f71f06e2d49a3f98fa1c1d93d91b" } connection: 当前 TiDB Server 上的客户端连接数 version: TiDB 版本号 git_hash: TiDB 当前代码的 Git Hash PD Server PD API 地址: http://${host}:${port}/pd/api/v1/${api_name}。其中 port 默认为 2379,各类 api_name 详细信息参见 PD API Doc。通过这个接口可以获取当前所有 TiKV 的状态以及负载均衡信息。其中最重要也是最常用的接口获取 TiKV 集群所有节点状态的接口,下面以一个单个 TiKV 构成的集群为例,说明一些用户需要了解的信息:curl http://127.0.0.1:2379/pd/api/v1/stores { "count": 1, TiKV 节点数量 "stores": [ // TiKV 节点的列表 // 下面列出的是这个集群中单个 TiKV 节点的信息 { "store": { "id": 1, "address": "127.0.0.1:22161", "state": 0 }, "status": { "store_id": 1, // 节点的 ID "capacity": 1968874332160, // 存储总容量 "available": 1264847716352, // 存储剩余容量 "region_count": 1, // 该节点上存放的 Region 数量 "sending_snap_count": 0, "receiving_snap_count": 0, "start_ts": "2016-10-24T19:54:00.110728339+08:00", // 启动时间 "last_heartbeat_ts": "2016-10-25T10:52:54.973669928+08:00", // 最后一次心跳时间 "total_region_count": 1, // 总 Region 数量 "leader_region_count": 1, // Leader Region 数量 "uptime": "14h58m54.862941589s" }, "scores": [ 100, 35 ] } ] } Metrics 监控 这部分主要对整个集群的状态、性能做监控,通过 Prometheus+Grafana 展现 metrics 数据,在下面一节会介绍如何搭建监控系统。TiDB Server query 处理时间,可以看到延迟和吞吐 ddl 过程监控 TiKV client 相关的监控 PD client 相关的监控 PD Server 命令执行的总次数 某个命令执行失败的总次数 某个命令执行成功的耗时统计 某个命令执行失败的耗时统计 某个命令执行完成并返回结果的耗时统计 TiKV Server GC 监控 执行 KV 命令的总次数 Scheduler 执行命令的耗时统计 Raft propose 命令的总次数 Raft 执行命令的耗时统计 Raft 执行命令失败的总次数 Raft 处理 ready 状态的总次数 使用 Prometheus+Grafana 部署架构 整个架构如下图所示,在 TiDB/PD/TiKV 三个组件的启动参数中添加 Prometheus Pushgateway 地址:搭建监控系统 Prometheus Push Gateway 参考: https://github.com/prometheus/pushgatewayPrometheus Server 参考: https://github.com/prometheus/prometheus#installGrafana 参考: http://docs.grafana.org配置 TiDB/PD/TiKV 配置 TiDB设置 --metrics-addr 和 --metrics-interval 两个参数,其中 metrics-addr 设为 Push Gateway 的地址,metrics-interval 为 push 的频率,单位为秒,默认值为 15 PD修改 toml 配置文件,填写 Push Gateway 的地址和推送频率[metric] # prometheus client push interval, set "0s" to disable prometheus. interval = "15s" # prometheus pushgateway address, leaves it empty will disable prometheus. address = "host:port" TiKV修改 toml 配置文件,填写 Push Gateway 的地址和推送频率,job 字段一般设为“tikv”。[metric] # the Prometheus client push interval. Setting the value to 0s stops Prometheus client from pushing. interval = "15s" # the Prometheus pushgateway address. Leaving it empty stops Prometheus client from pushing. address = "host:port" # the Prometheus client push job name. Note: A node id will automatically append, e.g., "tikv_1". job = "tikv" PushServer 配置 一般无需特殊配置,使用默认端口 9091 即可Prometheus 配置:在 yaml 配置文件中添加 Push Gateway 地址:scrape_configs: # The job name is added as a label `job=<job_name>` to any timeseries scraped from this config. - job_name: 'TiDB' # Override the global default and scrape targets from this job every 5 seconds. scrape_interval: 5s honor_labels: true static_configs: - targets: ['host:port'] # use the Push Gateway address labels: group: 'production' Grafana 配置 进入 Grafana Web 界面(默认地址: http://localhost:3000 ,默认账号: admin 密码: admin)点击 Grafana Logo -> 点击 Data Sources -> 点击 Add data source -> 填写 data source 信息 ( 注: Type 选 Prometheus,Url 为 Prometheus 地址,其他根据实际情况填写 ) 导入 dashboard 配置文件点击 Grafana Logo -> 点击 Dashboards -> 点击 Import -> 选择需要的 Dashboard 配置文件上传 -> 选择对应的 data source "}, {"url": "https://pingcap.com/docs-cn/v2.0/op-guide/monitor/", "title": "TiDB 集群监控", "content": " TiDB 集群监控 TiDB 集群状态监控目前有两种接口,第一种是通过 HTTP 接口对外汇报组件的信息,我们称之为组件的状态接口;第二种是使用 prometheus 记录组件中各种操作的详细信息,我们称之为 metrics 接口。组件状态接口 这类接口可以获取组件的一些基本信息,并且可以作为 keepalive 监测接口。另外 PD 的接口可以看到整个 TiKV 集群的详细信息。TiDB Server TiDB 对外暴露的 HTTP 接口是 http://host:port/status ,默认的端口号是 10080 (可以通过 –status 参数设置),可以通过访问这个接口获取当前 TiDB Server 的状态,以及判断是否存活。返回结果是 Json 格式:curl http://127.0.0.1:10080/status { connections: 0, version: "5.5.31-TiDB-1.0", git_hash: "b99521846ff6f71f06e2d49a3f98fa1c1d93d91b" } connection: 当前 TiDB Server 上的客户端连接数 version: TiDB 版本号 git_hash: TiDB 当前代码的 Git Hash PD Server PD API 地址: http://${host}:${port}/pd/api/v1/${api_name}。其中 port 默认为 2379,各类 api_name 详细信息参见 PD API Doc。通过这个接口可以获取当前所有 TiKV 的状态以及负载均衡信息。其中最重要也是最常用的接口获取 TiKV 集群所有节点状态的接口,下面以一个单个 TiKV 构成的集群为例,说明一些用户需要了解的信息:curl http://127.0.0.1:2379/pd/api/v1/stores { "count": 1, TiKV 节点数量 "stores": [ // TiKV 节点的列表 // 下面列出的是这个集群中单个 TiKV 节点的信息 { "store": { "id": 1, "address": "127.0.0.1:22161", "state": 0 }, "status": { "store_id": 1, // 节点的 ID "capacity": 1968874332160, // 存储总容量 "available": 1264847716352, // 存储剩余容量 "region_count": 1, // 该节点上存放的 Region 数量 "sending_snap_count": 0, "receiving_snap_count": 0, "start_ts": "2016-10-24T19:54:00.110728339+08:00", // 启动时间 "last_heartbeat_ts": "2016-10-25T10:52:54.973669928+08:00", // 最后一次心跳时间 "total_region_count": 1, // 总 Region 数量 "leader_region_count": 1, // Leader Region 数量 "uptime": "14h58m54.862941589s" }, "scores": [ 100, 35 ] } ] } Metrics 监控 这部分主要对整个集群的状态、性能做监控,通过 Prometheus+Grafana 展现 metrics 数据,在下面一节会介绍如何搭建监控系统。TiDB Server query 处理时间,可以看到延迟和吞吐 ddl 过程监控 TiKV client 相关的监控 PD client 相关的监控 PD Server 命令执行的总次数 某个命令执行失败的总次数 某个命令执行成功的耗时统计 某个命令执行失败的耗时统计 某个命令执行完成并返回结果的耗时统计 TiKV Server GC 监控 执行 KV 命令的总次数 Scheduler 执行命令的耗时统计 Raft propose 命令的总次数 Raft 执行命令的耗时统计 Raft 执行命令失败的总次数 Raft 处理 ready 状态的总次数 使用 Prometheus+Grafana 部署架构 整个架构如下图所示,在 TiDB/PD/TiKV 三个组件的启动参数中添加 Prometheus Pushgateway 地址:搭建监控系统 Prometheus Push Gateway 参考: https://github.com/prometheus/pushgatewayPrometheus Server 参考: https://github.com/prometheus/prometheus#installGrafana 参考: http://docs.grafana.org配置 TiDB/PD/TiKV 配置 TiDB设置 --metrics-addr 和 --metrics-interval 两个参数,其中 metrics-addr 设为 Push Gateway 的地址,metrics-interval 为 push 的频率,单位为秒,默认值为 15 PD修改 toml 配置文件,填写 Push Gateway 的地址和推送频率[metric] # prometheus client push interval, set "0s" to disable prometheus. interval = "15s" # prometheus pushgateway address, leaves it empty will disable prometheus. address = "host:port" TiKV修改 toml 配置文件,填写 Push Gateway 的地址和推送频率,job 字段一般设为“tikv”。[metric] # the Prometheus client push interval. Setting the value to 0s stops Prometheus client from pushing. interval = "15s" # the Prometheus pushgateway address. Leaving it empty stops Prometheus client from pushing. address = "host:port" # the Prometheus client push job name. Note: A node id will automatically append, e.g., "tikv_1". job = "tikv" PushServer 配置 一般无需特殊配置,使用默认端口 9091 即可Prometheus 配置:在 yaml 配置文件中添加 Push Gateway 地址:scrape_configs: # The job name is added as a label `job=<job_name>` to any timeseries scraped from this config. - job_name: 'TiDB' # Override the global default and scrape targets from this job every 5 seconds. scrape_interval: 5s honor_labels: true static_configs: - targets: ['host:port'] # use the Push Gateway address labels: group: 'production' Grafana 配置 进入 Grafana Web 界面(默认地址: http://localhost:3000 ,默认账号: admin 密码: admin)点击 Grafana Logo -> 点击 Data Sources -> 点击 Add data source -> 填写 data source 信息 ( 注: Type 选 Prometheus,Url 为 Prometheus 地址,其他根据实际情况填写 ) 导入 dashboard 配置文件点击 Grafana Logo -> 点击 Dashboards -> 点击 Import -> 选择需要的 Dashboard 配置文件上传 -> 选择对应的 data source "}, {"url": "https://pingcap.com/docs/op-guide/ansible-operation/", "title": "TiDB-Ansible Common Operations", "content": " TiDB-Ansible Common Operations This guide describes the common operations when you administer a TiDB cluster using TiDB-Ansible.Start a cluster $ ansible-playbook start.yml This operation starts all the components in the entire TiDB cluster in order, which include PD, TiDB, TiKV, and the monitoring components.Stop a cluster $ ansible-playbook stop.yml This operation stops all the components in the entire TiDB cluster in order, which include PD, TiDB, TiKV, and the monitoring components.Clean up cluster data $ ansible-playbook unsafe_cleanup_data.yml This operation stops the TiDB, Pump, TiKV and PD services, and cleans up the data directory of Pump, TiKV and PD.Destroy a cluster $ ansible-playbook unsafe_cleanup.yml This operation stops the cluster and cleans up the data directory. Note: If the deployment directory is a mount point, an error will be reported, but implementation results remain unaffected, so you can ignore it. "}, {"url": "https://pingcap.com/docs/v2.0/op-guide/ansible-operation/", "title": "TiDB-Ansible Common Operations", "content": " TiDB-Ansible Common Operations This guide describes the common operations when you administer a TiDB cluster using TiDB-Ansible.Start a cluster $ ansible-playbook start.yml This operation starts all the components in the entire TiDB cluster in order, which include PD, TiDB, TiKV, and the monitoring components.Stop a cluster $ ansible-playbook stop.yml This operation stops all the components in the entire TiDB cluster in order, which include PD, TiDB, TiKV, and the monitoring components.Clean up cluster data $ ansible-playbook unsafe_cleanup_data.yml This operation stops the TiDB, Pump, TiKV and PD services, and cleans up the data directory of Pump, TiKV and PD.Destroy a cluster $ ansible-playbook unsafe_cleanup.yml This operation stops the cluster and cleans up the data directory. Note: If the deployment directory is a mount point, an error will be reported, but implementation results remain unaffected, so you can ignore it. "}, {"url": "https://pingcap.com/docs-cn/op-guide/ansible-operation/", "title": "TiDB-Ansible 常见运维操作", "content": " TiDB-Ansible 常见运维操作 启动集群 此操作会按顺序启动整个 TiDB 集群所有组件(包括 PD、TiDB、TiKV 等组件和监控组件)。$ ansible-playbook start.yml 关闭集群 此操作会按顺序关闭整个 TiDB 集群所有组件(包括 PD、TiDB、TiKV 等组件和监控组件)。$ ansible-playbook stop.yml 清除集群数据 此操作会关闭 TiDB、Pump、TiKV、PD 服务,并清空 Pump、TiKV、PD 数据目录。$ ansible-playbook unsafe_cleanup_data.yml 销毁集群 此操作会关闭集群,并清空部署目录,若部署目录为挂载点,会报错,可忽略。$ ansible-playbook unsafe_cleanup.yml"}, {"url": "https://pingcap.com/docs-cn/op-guide/ansible-deployment/", "title": "TiDB-Ansible 部署方案", "content": " TiDB-Ansible 部署方案 概述 Ansible 是一款自动化运维工具,TiDB-Ansible 是 PingCAP 基于 Ansible playbook 功能编写的集群部署工具。本文档介绍如何使用 TiDB-Ansible 部署一个完整的 TiDB 集群。本部署工具可以通过配置文件设置集群拓扑,完成以下各项运维工作: 初始化操作系统参数 部署 TiDB 集群(包括 PD、TiDB、TiKV 等组件和监控组件) 启动集群 关闭集群 变更组件配置 集群扩容缩容 升级组件版本 集群开启 binlog 清除集群数据 销毁集群 注:对于生产环境,须使用 TiDB-Ansible 部署 TiDB 集群。如果只是用于测试 TiDB 或体验 TiDB 的特性,建议使用 Docker Compose 在单机上快速部署 TiDB 集群。 准备机器 部署目标机器若干 建议 4 台及以上,TiKV 至少 3 实例,且与 TiDB、PD 模块不位于同一主机,详见部署建议。 推荐安装 CentOS 7.3 及以上版本 Linux 操作系统,x86_64 架构 (amd64)。 机器之间内网互通。 注:使用 Ansible 方式部署时,TiKV 及 PD 节点数据目录所在磁盘请使用 SSD 磁盘,否则无法通过检测。 如果仅验证功能,建议使用 Docker Compose 部署方案单机进行测试。 部署中控机一台: 中控机可以是部署目标机器中的某一台。 推荐安装 CentOS 7.3 及以上版本 Linux 操作系统(默认包含 Python 2.7)。 该机器需开放外网访问,用于下载 TiDB 及相关软件安装包。 在中控机上安装系统依赖包 以 root 用户登录中控机如果中控机是 CentOS 7 系统,执行以下命令:# yum -y install epel-release git curl sshpass # yum -y install python-pip 如果是中控机是 Ubuntu 系统,执行以下命令:# apt-get -y install git curl sshpass python-pip 在中控机上创建 tidb 用户,并生成 ssh key 以 root 用户登录中控机,执行以下命令创建 tidb 用户# useradd -m -d /home/tidb tidb 设置 tidb 用户密码# passwd tidb 配置 tidb 用户 sudo 免密码,将 tidb ALL=(ALL) NOPASSWD: ALL 添加到文件末尾即可。# visudo tidb ALL=(ALL) NOPASSWD: ALL 生成 ssh key: 执行 su 命令从 root 用户切换到 tidb 用户下。# su - tidb 创建 tidb 用户 ssh key, 提示 Enter passphrase 时直接回车即可。执行成功后,ssh 私钥文件为 /home/tidb/.ssh/id_rsa, ssh 公钥文件为 /home/tidb/.ssh/id_rsa.pub。$ ssh-keygen -t rsa Generating public/private rsa key pair. Enter file in which to save the key (/home/tidb/.ssh/id_rsa): Created directory '/home/tidb/.ssh'. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/tidb/.ssh/id_rsa. Your public key has been saved in /home/tidb/.ssh/id_rsa.pub. The key fingerprint is: SHA256:eIBykszR1KyECA/h0d7PRKz4fhAeli7IrVphhte7/So tidb@172.16.10.49 The key's randomart image is: +---[RSA 2048]----+ |=+o+.o. | |o=o+o.oo | | .O.=.= | | . B.B + | |o B * B S | | * + * + | | o + . | | o E+ . | |o ..+o. | +----[SHA256]-----+ 在中控机器上下载 TiDB-Ansible 以 tidb 用户登录中控机并进入 /home/tidb 目录。以下为 tidb-ansible 分支与 TiDB 版本对应关系,版本选择可以咨询官方。 tidb-ansible 分支 TiDB 版本 备注 release-2.0 2.0 版本 最新 2.0 稳定版本,可用于生产环境。 release-2.1 2.1 版本 最新 2.1 稳定版本,可用于生产环境(建议)。 master master 版本 包含最新特性,每日更新。 使用以下命令从 Github TiDB-Ansible 项目上下载 TiDB-Ansible 相应分支,默认的文件夹名称为 tidb-ansible。 下载 2.0 版本:$ git clone -b release-2.0 https://github.com/pingcap/tidb-ansible.git 下载 2.1 版本:$ git clone -b release-2.1 https://github.com/pingcap/tidb-ansible.git 下载 master 版本:$ git clone https://github.com/pingcap/tidb-ansible.git 注:请务必按文档操作,将 tidb-ansible 下载到 /home/tidb 目录下,权限为 tidb 用户,不要下载到 /root 下,否则会遇到权限问题。 在中控机器上安装 Ansible 及其依赖 以 tidb 用户登录中控机,请务必按以下方式通过 pip 安装 Ansible 及其相关依赖的指定版本,否则会有兼容问题。安装完成后,可通过 ansible --version 查看 Ansible 版本。目前 release-2.0、release-2.1 及 master 版本兼容 Ansible 2.4 及 Ansible 2.5 版本,Ansible 及相关依赖版本记录在 tidb-ansible/requirements.txt 文件中。$ cd /home/tidb/tidb-ansible $ sudo pip install -r ./requirements.txt $ ansible --version ansible 2.5.0 在中控机上配置部署机器 ssh 互信及 sudo 规则 以 tidb 用户登录中控机,将你的部署目标机器 IP 添加到 hosts.ini 文件 [servers] 区块下。$ cd /home/tidb/tidb-ansible $ vi hosts.ini [servers] 172.16.10.1 172.16.10.2 172.16.10.3 172.16.10.4 172.16.10.5 172.16.10.6 [all:vars] username = tidb ntp_server = pool.ntp.org 执行以下命令,按提示输入部署目标机器 root 用户密码。该步骤将在部署目标机器上创建 tidb 用户,并配置 sudo 规则,配置中控机与部署目标机器之间的 ssh 互信。$ ansible-playbook -i hosts.ini create_users.yml -u root -k 手工配置 ssh 互信及 sudo 免密码可参考如何手工配置 ssh 互信及 sudo 免密码。 在部署目标机器上安装 NTP 服务 如果你的部署目标机器时间、时区设置一致,已开启 NTP 服务且在正常同步时间,此步骤可忽略。可参考如何检测 NTP 服务是否正常。该步骤将在部署目标机器上使用系统自带软件源联网安装并启动 NTP 服务,服务使用安装包默认的 NTP server 列表,见配置文件 /etc/ntp.conf 中 server 参数,如果使用默认的 NTP server,你的机器需要连接外网。 为了让 NTP 尽快开始同步,启动 NTP 服务前,系统会 ntpdate hosts.ini 文件中的 ntp_server 一次,默认为 pool.ntp.org,也可替换为你的 NTP server。 以 tidb 用户登录中控机,执行以下命令:$ cd /home/tidb/tidb-ansible $ ansible-playbook -i hosts.ini deploy_ntp.yml -u tidb -b 在部署目标机器上配置 CPUfreq 调节器模式 为了让 CPU 发挥最大性能,请将 CPUfreq 调节器模式设置为 performance 模式。 你可以查看使用 CPUFREQ 调控器文档, 了解更多 CPUFREQ 相关信息。 你可以通过 cpupower 命令查看系统支持的调节器模式:# cpupower frequency-info --governors analyzing CPU 0: available cpufreq governors: performance powersave 本例中系统支持设置 performance 和 powersave 模式。如果返回 “Not Available”,表示当前系统不支持配置 CPUfreq,跳过该步骤即可。# cpupower frequency-info --governors analyzing CPU 0: available cpufreq governors: Not Available 你可以通过 cpupower 命令查看系统当前的 CPUfreq 调节器模式:# cpupower frequency-info --policy analyzing CPU 0: current policy: frequency should be within 1.20 GHz and 3.20 GHz. The governor "powersave" may decide which speed to use within this range. 本例中当前配置是 powersave 模式,你可以通过以下命令设置为 performance 模式。# cpupower frequency-set --governor performance 你也可以通过以下命令在部署目标机器上批量设置:$ ansible -i hosts.ini all -m shell -a "cpupower frequency-set --governor performance" -u tidb -b 在部署目标机器上添加数据盘 ext4 文件系统挂载参数 部署目标机器数据盘请格式化成 ext4 文件系统,挂载时请添加 nodelalloc 和 noatime 挂载参数。nodelalloc 是必选参数,否则 Ansible 安装时检测无法通过,noatime 是可选建议参数。 如果你的数据盘已经格式化成 ext4 并挂载,可先执行 umount 命令卸载,从编辑 /etc/fstab 文件步骤开始执行,添加挂载参数重新挂载即可。 # umount /dev/nvme0n1 下面以 /dev/nvme0n1 数据盘为例:查看数据盘# fdisk -l Disk /dev/nvme0n1: 1000 GB 创建分区表# parted -s -a optimal /dev/nvme0n1 mklabel gpt -- mkpart primary ext4 1 -1 格式化文件系统# mkfs.ext4 /dev/nvme0n1 查看数据盘分区 UUID,本例中 nvme0n1 的 UUID 为 c51eb23b-195c-4061-92a9-3fad812cc12f。# lsblk -f NAME FSTYPE LABEL UUID MOUNTPOINT sda ├─sda1 ext4 237b634b-a565-477b-8371-6dff0c41f5ab /boot ├─sda2 swap f414c5c0-f823-4bb1-8fdf-e531173a72ed └─sda3 ext4 547909c1-398d-4696-94c6-03e43e317b60 / sr0 nvme0n1 ext4 c51eb23b-195c-4061-92a9-3fad812cc12f 编辑 /etc/fstab 文件,添加 nodelalloc 挂载参数# vi /etc/fstab UUID=c51eb23b-195c-4061-92a9-3fad812cc12f /data1 ext4 defaults,nodelalloc,noatime 0 2 挂载数据盘# mkdir /data1 # mount -a 执行以下命令,如果文件系统为 ext4,并且挂载参数中包含 nodelalloc 表示生效:# mount -t ext4 /dev/nvme0n1 on /data1 type ext4 (rw,noatime,nodelalloc,data=ordered) 分配机器资源,编辑 inventory.ini 文件 以 tidb 用户登录中控机,inventory.ini 文件路径为 /home/tidb/tidb-ansible/inventory.ini。 注: 请使用内网 IP 来部署集群,如果部署目标机器 SSH 端口非默认 22 端口,需添加 ansible_port 变量,如: TiDB1 ansible_host=172.16.10.1 ansible_port=5555 标准 TiDB 集群需要 6 台机器: 2 个 TiDB 节点 3 个 PD 节点 3 个 TiKV 节点,第一台 TiDB 机器同时用作监控机 默认情况下,单台机器上只需部署一个 TiKV 实例。如果你的 TiKV 部署机器 CPU 及内存配置是部署建议的两倍或以上,并且拥有两块 SSD 硬盘或单块容量超 2T 的 SSD 硬盘,可以考虑部署两实例,但不建议部署两个以上实例。单机单 TiKV 实例集群拓扑 Name Host IP Services node1 172.16.10.1 PD1, TiDB1 node2 172.16.10.2 PD2, TiDB2 node3 172.16.10.3 PD3 node4 172.16.10.4 TiKV1 node5 172.16.10.5 TiKV2 node6 172.16.10.6 TiKV3 [tidb_servers] 172.16.10.1 172.16.10.2 [pd_servers] 172.16.10.1 172.16.10.2 172.16.10.3 [tikv_servers] 172.16.10.4 172.16.10.5 172.16.10.6 [monitoring_servers] 172.16.10.1 [grafana_servers] 172.16.10.1 [monitored_servers] 172.16.10.1 172.16.10.2 172.16.10.3 172.16.10.4 172.16.10.5 172.16.10.6 单机多 TiKV 实例集群拓扑 以两实例为例: Name Host IP Services node1 172.16.10.1 PD1, TiDB1 node2 172.16.10.2 PD2, TiDB2 node3 172.16.10.3 PD3 node4 172.16.10.4 TiKV1-1, TiKV1-2 node5 172.16.10.5 TiKV2-1, TiKV2-2 node6 172.16.10.6 TiKV3-1, TiKV3-2 [tidb_servers] 172.16.10.1 172.16.10.2 [pd_servers] 172.16.10.1 172.16.10.2 172.16.10.3 [tikv_servers] TiKV1-1 ansible_host=172.16.10.4 deploy_dir=/data1/deploy tikv_port=20171 labels="host=tikv1" TiKV1-2 ansible_host=172.16.10.4 deploy_dir=/data2/deploy tikv_port=20172 labels="host=tikv1" TiKV2-1 ansible_host=172.16.10.5 deploy_dir=/data1/deploy tikv_port=20171 labels="host=tikv2" TiKV2-2 ansible_host=172.16.10.5 deploy_dir=/data2/deploy tikv_port=20172 labels="host=tikv2" TiKV3-1 ansible_host=172.16.10.6 deploy_dir=/data1/deploy tikv_port=20171 labels="host=tikv3" TiKV3-2 ansible_host=172.16.10.6 deploy_dir=/data2/deploy tikv_port=20172 labels="host=tikv3" [monitoring_servers] 172.16.10.1 [grafana_servers] 172.16.10.1 [monitored_servers] 172.16.10.1 172.16.10.2 172.16.10.3 172.16.10.4 172.16.10.5 172.16.10.6 [pd_servers:vars] location_labels = ["host"] 服务配置文件参数调整 多实例情况下,需要修改 tidb-ansible/conf/tikv.yml 中的 block-cache-size 参数: rocksdb defaultcf block-cache-size(GB) = MEM * 80% / TiKV 实例 …"}, {"url": "https://pingcap.com/docs-cn/v1.0/op-guide/ansible-deployment/", "title": "TiDB-Ansible 部署方案", "content": " TiDB-Ansible 部署方案 概述 Ansible 是一款自动化运维工具,TiDB-Ansible 是 PingCAP 基于 Ansible playbook 功能编写的集群部署工具。使用 TiDB-Ansible 可以快速部署一个完整的 TiDB 集群(包括 PD、TiDB、TiKV 和集群监控模块)。本部署工具可以通过配置文件设置集群拓扑,一键完成以下各项运维工作: 初始化操作系统参数 部署组件 滚动升级,滚动升级时支持模块存活检测 数据清理 环境清理 配置监控模块 准备机器 部署目标机器若干 建议 4 台及以上,TiKV 至少 3 实例,且与 TiDB、PD 模块不位于同一主机,详见部署建议。 推荐安装 CentOS 7.3 及以上版本 Linux 操作系统,x86_64 架构(amd64),数据盘请使用 ext4 文件系统,挂载 ext4 文件系统时请添加 nodelalloc 挂载参数,可参考数据盘 ext4 文件系统挂载参数。 机器之间内网互通,防火墙如 iptables 等请在部署时关闭。 机器的时间、时区设置一致,开启 NTP 服务且在正常同步时间,可参考如何检测 NTP 服务是否正常。 创建 tidb 普通用户作为程序运行用户,tidb 用户可以免密码 sudo 到 root 用户,可参考如何配置 ssh 互信及 sudo 免密码。 注:使用 Ansible 方式部署时,TiKV 及 PD 节点数据目录所在磁盘请使用 SSD 磁盘,否则无法通过检测。 如果仅验证功能,建议使用 Docker Compose 部署方案单机进行测试。 部署中控机一台: 中控机可以是部署目标机器中的某一台。 推荐安装 CentOS 7.3 及以上版本 Linux 操作系统(默认包含 Python 2.7)。 该机器需开放外网访问,用于下载 TiDB 及相关软件安装包。 配置 ssh authorized_key 互信,在中控机上可以使用 tidb 用户免密码 ssh 登录到部署目标机器,可参考如何配置 ssh 互信及 sudo 免密码。 在中控机器上安装 Ansible 及其依赖 请按以下方式在 CentOS 7 系统的中控机上安装 Ansible。 通过 epel 源安装, 会自动安装 Ansible 相关依赖(如 Jinja2==2.7.2 MarkupSafe==0.11),安装完成后,可通过 ansible --version 查看版本,请务必确认是 Ansible 2.4 及以上版本,否则会有兼容问题。# yum install epel-release # yum install ansible curl # ansible --version ansible 2.4.2.0 其他系统可参考 如何安装 Ansible。 在中控机器上下载 TiDB-Ansible 以 tidb 用户登录中控机并进入 /home/tidb 目录,使用以下命令从 Github TiDB-Ansible 项目 上下载 TiDB-Ansible 相应版本,默认的文件夹名称为 tidb-ansible。下载 GA 版本:cd /home/tidb git clone -b release-1.0 https://github.com/pingcap/tidb-ansible.git 或下载 master 版本:cd /home/tidb git clone https://github.com/pingcap/tidb-ansible.git 注: 生产环境请下载 GA 版本部署 TiDB。 分配机器资源,编辑 inventory.ini 文件 inventory.ini 文件路径为 tidb-ansible/inventory.ini。标准 TiDB 集群需要 6 台机器: 2 个 TiDB 节点 3 个 PD 节点 3 个 TiKV 节点,第一台 TiDB 机器同时用作监控机 单机单 TiKV 实例集群拓扑如下 Name Host IP Services node1 172.16.10.1 PD1, TiDB1 node2 172.16.10.2 PD2, TiDB2 node3 172.16.10.3 PD3 node4 172.16.10.4 TiKV1 node5 172.16.10.5 TiKV2 node6 172.16.10.6 TiKV3 [tidb_servers] 172.16.10.1 172.16.10.2 [pd_servers] 172.16.10.1 172.16.10.2 172.16.10.3 [tikv_servers] 172.16.10.4 172.16.10.5 172.16.10.6 [monitoring_servers] 172.16.10.1 [grafana_servers] 172.16.10.1 [monitored_servers] 172.16.10.1 172.16.10.2 172.16.10.3 172.16.10.4 172.16.10.5 172.16.10.6 单机多 TiKV 实例集群拓扑如下(以两实例为例) Name Host IP Services node1 172.16.10.1 PD1, TiDB1 node2 172.16.10.2 PD2, TiDB2 node3 172.16.10.3 PD3 node4 172.16.10.4 TiKV1-1, TiKV1-2 node5 172.16.10.5 TiKV2-1, TiKV2-2 node6 172.16.10.6 TiKV3-1, TiKV3-2 [tidb_servers] 172.16.10.1 172.16.10.2 [pd_servers] 172.16.10.1 172.16.10.2 172.16.10.3 [tikv_servers] TiKV1-1 ansible_host=172.16.10.4 deploy_dir=/data1/deploy tikv_port=20171 labels="host=tikv1" TiKV1-2 ansible_host=172.16.10.4 deploy_dir=/data2/deploy tikv_port=20172 labels="host=tikv1" TiKV2-1 ansible_host=172.16.10.5 deploy_dir=/data1/deploy tikv_port=20171 labels="host=tikv2" TiKV2-2 ansible_host=172.16.10.5 deploy_dir=/data2/deploy tikv_port=20172 labels="host=tikv2" TiKV3-1 ansible_host=172.16.10.6 deploy_dir=/data1/deploy tikv_port=20171 labels="host=tikv3" TiKV3-2 ansible_host=172.16.10.6 deploy_dir=/data2/deploy tikv_port=20172 labels="host=tikv3" [monitoring_servers] 172.16.10.1 [grafana_servers] 172.16.10.1 [monitored_servers] 172.16.10.1 172.16.10.2 172.16.10.3 172.16.10.4 172.16.10.5 172.16.10.6 ...... [pd_servers:vars] location_labels = ["host"] 服务配置文件参数调整 多实例情况下,需要修改 tidb-ansible/conf/tikv.yml 中的 end-point-concurrency 以及 block-cache-size 参数: end-point-concurrency: 总数低于 CPU Vcores 即可 rocksdb defaultcf block-cache-size(GB) = MEM * 80% / TiKV 实例数量 * 30% rocksdb writecf block-cache-size(GB) = MEM * 80% / TiKV 实例数量 * 45% rocksdb lockcf block-cache-size(GB) = MEM * 80% / TiKV 实例数量 * 2.5% (最小 128 MB) raftdb defaultcf block-cache-size(GB) = MEM * 80% / TiKV 实例数量 * 2.5% (最小 128 MB) 如果多个 TiKV 实例部署在同一块物理磁盘上,需要修改 conf/tikv.yml 中的 capacity 参数: capacity = (DISK - 日志空间) / TiKV 实例数量,单位为 GB inventory.ini 变量调整 部署目录调整 部署目录通过 deploy_dir 变量控制,默认全局变量已设置为 /home/tidb/deploy,对所有服务生效。如数据盘挂载目录为 /data1,可设置为 /data1/deploy,样例如下:## Global variables [all:vars] deploy_dir = /data1/deploy 如为某一服务单独设置部署目录,可在配置服务主机列表时配置主机变量,以 TiKV 节点为例,其他服务类推,请务必添加第一列别名,以免服务混布时混淆。TiKV1-1 ansible_host=172.16.10.4 deploy_dir=/data1/deploy 其他变量调整 变量 含义 cluster_name 集群名称,可调整 tidb_version TiDB 版本,TiDB-Ansible 各分支默认已配置 deployment_method 部署方式,默认为 binary,可选 docker process_supervision 进程监管方式,默认为 systemd,可选 supervise timezone 修改部署目标机器时区,默认为 Asia/Shanghai,可调整,与 set_timezone 变量结合使用 set_timezone 默认为 True,即修改部署目标机器时区,关闭可修改为 False enable_firewalld 开启防火墙,默认不开启 enable_ntpd 检测部署目标机器 NTP 服务,默认为 True,请勿关闭 set_hostname 根据 IP 修改部署目标机器主机名,默认为 False enable_binlog 是否部署 pump 并开启 binlog,默认为 False,依赖 Kafka 集群,参见 zookeeper_addrs 变量 zookeeper_addrs binlog Kafka 集群的 zookeeper 地址 enable_slow_query_log TiDB 慢查询日志记录到单独文件({{ deploy_dir }}/log/tidb_slow_query.log),默认为 False,记录到 tidb 日志 deploy_without_tidb KV 模式,不部署 TiDB 服务,仅部署 PD、TiKV 及监控服务,请将 inventory.ini 文件中 tidb_servers 主机组 IP 设置为空。 部署任务 ansible-playbook 执行 Playbook 时默认并发为 5,部署目标机器较多时可添加 -f 参数指定并发,如 ansible-playbook deploy.yml -f 10 确认 tidb-ansible/inventory.ini 文件中 ansible_user = tidb,本例使用 tidb 用户作为服务运行用户,配置如下:## Connection # ssh via root: # ansible_user = root # ansible_become = true # ansible_become_user = tidb # ssh via normal user ansible_user = tidb 执行以下命令如果所有 server 返回 tidb 表示 ssh 互信配置成功。ansible -i inventory.ini all -m shell -a 'whoami' 执行以下命令如果所有 server 返回 root 表示 tidb 用户 sudo 免密码配置成功。ansible -i inventory.ini all -m shell -a 'whoami' -b 执行 local_prepare.yml playbook,联网下载 TiDB binary 到中控机:ansible-playbook local_prepare.yml 初始化系统环境,修改内核参数ansible-playbook bootstrap.yml 部署 TiDB 集群软件ansible-playbook deploy.yml 启动 TiDB 集群ansible-playbook start.yml 如希望使用 root 用户远程连接部署,请参考使用 root 用户远程连接 TiDB Ansible 部署方案,不推荐使用该方式部署。 测试集群 测试连接 TiDB 集群,推荐在 TiDB 前配置负载均衡来对外统一提供 SQL 接口。 使用 MySQL 客户端连接测试,TCP 4000 端口是 TiDB 服务默认端口。mysql -u root -h 172.16.10.1 -P 4000 通过浏览器访问监控平台。地址:http://172.16.10.1:3000 默认帐号密码是:admin/admin 滚动升级 滚动升级 TiDB 服务,滚动升级期间不影响业务运行(最小环境 :pd*3 、tidb*2、tikv*3) 如果集群环境中有 pump / drainer 服务,请先停止 drainer 后滚动升级 (升级 TiDB 时会升级 pump)。 自动下载 binary 修改 inventory.ini 中的 tidb_version 参数值,指定需要升级的版本号,本例指定升级的版本号为 v1.0.2tidb_version = v1.0.2 删除原有的 downloads 目录 tidb-ansible/downloads/rm -rf downloads 使用 playbook 下载 TiDB 1.0 版本 binary,自动替换 binary 到 tidb-ansible/resource/bin/ansible-playbook local_prepare.yml 手动下载 binary 除 “下载 binary” 中描述的方法之外,也可以手动下载 binary,解压后手动替换 binary 到 tidb-ansible/resource/bin/,请注意替换链接中的版本号wget http://download.pingcap.org/tidb-v1.0.0-linux-amd64-unportable.tar.gz 使用 Ansible 滚动升级 滚动升级 TiKV 节点( 只升级 TiKV 服务 )ansible-playbook rolling_update.yml --tags=tikv 滚动升级 PD 节点( 只升级单独 PD 服务 )ansible-playbook rolling_update.yml --tags=pd 滚动升级 TiDB 节点( 只升级单独 TiDB 服务 )ansible-playbook rolling_update.yml --tags=tidb 滚动升级所有服务ansible-playbook rolling_update.yml 常见运维操作汇总 任务 Playbook 启动集群 ansible-playbook start.yml 停止集群 ansible-playbook stop.yml 销毁集群 ansible-playbook unsafe_cleanup.yml (若部署目录为挂载点,会报错,可忽略) 清除数据(测试用) ansible-playbook unsafe_cleanup_data.yml 滚动升级 ansible-playbook rolling_update.yml 滚动升级 TiKV ansible-playbook rolling_update.yml --tags=tikv 滚动升级除 pd 外模块 ansible-playbook rolling_update.yml --skip-tags=pd 滚动升级监控组件 ansible-playbook rolling_update_monitor.yml 常见部署问题 如何下载安装指定版本 TiDB 如需安装 TiDB 1.0.4 版本,需要先下载 TiDB-Ansible release-1.0 分支,确认 inventory.ini 文件中 tidb_version = v1.0.4,安装步骤同上。从 github 下载 TiDB-Ansible release-1.0 分支:git clone -b release-1.0 https://github.com/pingcap/tidb-ansible.git 如何自定义端口 修改 inventory.ini 文件,在相应服务 IP 后添加以下主机变量即可: 组件 端口变量 默认端口 说明 TiDB tidb_port 4000 应用及 DBA 工具访问通信端口 TiDB tidb_status_port 10080 TiDB 状态信息上报通信端口 TiKV tikv_port 20160 TiKV 通信端口 PD pd_client_port 2379 提供 TiDB 和 PD 通信端口 PD pd_peer_port 2380 PD 集群节点间通信端口 pump pump_port 8250 pump 通信端口 prometheus prometheus_port 9090 Prometheus 服务通信端口 pushgateway pushgateway_port 9091 TiDB, TiKV, PD 监控聚合和上报端口 node_exporter node_exporter_port 9100 TiDB 集群每 …"}, {"url": "https://pingcap.com/docs-cn/v2.0/op-guide/ansible-deployment/", "title": "TiDB-Ansible 部署方案", "content": " TiDB-Ansible 部署方案 概述 Ansible 是一款自动化运维工具,TiDB-Ansible 是 PingCAP 基于 Ansible playbook 功能编写的集群部署工具。使用 TiDB-Ansible 可以快速部署一个完整的 TiDB 集群(包括 PD、TiDB、TiKV 和集群监控模块)。本部署工具可以通过配置文件设置集群拓扑,一键完成以下各项运维工作: 初始化操作系统参数 部署组件 滚动升级,滚动升级时支持模块存活检测 数据清理 环境清理 配置监控模块 准备机器 部署目标机器若干 建议 4 台及以上,TiKV 至少 3 实例,且与 TiDB、PD 模块不位于同一主机,详见部署建议。 推荐安装 CentOS 7.3 及以上版本 Linux 操作系统,x86_64 架构(amd64),数据盘请使用 ext4 文件系统,挂载 ext4 文件系统时请添加 nodelalloc 挂载参数,可参考数据盘 ext4 文件系统挂载参数。 机器之间内网互通,防火墙如 iptables 等请在部署时关闭。 机器的时间、时区设置一致,开启 NTP 服务且在正常同步时间,可参考如何检测 NTP 服务是否正常。 创建 tidb 普通用户作为程序运行用户,tidb 用户可以免密码 sudo 到 root 用户,可参考如何配置 ssh 互信及 sudo 免密码。 注:使用 Ansible 方式部署时,TiKV 及 PD 节点数据目录所在磁盘请使用 SSD 磁盘,否则无法通过检测。 如果仅验证功能,建议使用 Docker Compose 部署方案单机进行测试。 部署中控机一台: 中控机可以是部署目标机器中的某一台。 推荐安装 CentOS 7.3 及以上版本 Linux 操作系统(默认包含 Python 2.7)。 该机器需开放外网访问,用于下载 TiDB 及相关软件安装包。 配置 ssh authorized_key 互信,在中控机上可以使用 tidb 用户免密码 ssh 登录到部署目标机器,可参考如何配置 ssh 互信及 sudo 免密码。 在中控机器上安装 Ansible 及其依赖 请按以下方式在 CentOS 7 系统的中控机上安装 Ansible。 通过 epel 源安装, 会自动安装 Ansible 相关依赖(如 Jinja2==2.7.2 MarkupSafe==0.11),安装完成后,可通过 ansible --version 查看版本,请务必确认是 Ansible 2.4 及以上版本,否则会有兼容问题。# yum install epel-release # yum install ansible curl python2-jmespath # ansible --version ansible 2.4.2.0 其他系统可参考 如何安装 Ansible。 确认中控机上已安装 Python jmespath 模块(0.9.0 或以上版本),可参考 You need to install jmespath prior to running json_query filter 报错。在中控机器上下载 TiDB-Ansible 以 tidb 用户登录中控机并进入 /home/tidb 目录,使用以下命令从 Github TiDB-Ansible 项目 上下载 TiDB-Ansible 相应版本,默认的文件夹名称为 tidb-ansible。下载 GA 版本:cd /home/tidb git clone -b release-1.0 https://github.com/pingcap/tidb-ansible.git 或下载 master 版本:cd /home/tidb git clone https://github.com/pingcap/tidb-ansible.git 注: 生产环境请下载 GA 版本部署 TiDB。 分配机器资源,编辑 inventory.ini 文件 inventory.ini 文件路径为 tidb-ansible/inventory.ini。 注: 请使用内网 IP 来部署集群。 标准 TiDB 集群需要 6 台机器: 2 个 TiDB 节点 3 个 PD 节点 3 个 TiKV 节点,第一台 TiDB 机器同时用作监控机 单机单 TiKV 实例集群拓扑如下 Name Host IP Services node1 172.16.10.1 PD1, TiDB1 node2 172.16.10.2 PD2, TiDB2 node3 172.16.10.3 PD3 node4 172.16.10.4 TiKV1 node5 172.16.10.5 TiKV2 node6 172.16.10.6 TiKV3 [tidb_servers] 172.16.10.1 172.16.10.2 [pd_servers] 172.16.10.1 172.16.10.2 172.16.10.3 [tikv_servers] 172.16.10.4 172.16.10.5 172.16.10.6 [monitoring_servers] 172.16.10.1 [grafana_servers] 172.16.10.1 [monitored_servers] 172.16.10.1 172.16.10.2 172.16.10.3 172.16.10.4 172.16.10.5 172.16.10.6 单机多 TiKV 实例集群拓扑如下(以两实例为例) Name Host IP Services node1 172.16.10.1 PD1, TiDB1 node2 172.16.10.2 PD2, TiDB2 node3 172.16.10.3 PD3 node4 172.16.10.4 TiKV1-1, TiKV1-2 node5 172.16.10.5 TiKV2-1, TiKV2-2 node6 172.16.10.6 TiKV3-1, TiKV3-2 [tidb_servers] 172.16.10.1 172.16.10.2 [pd_servers] 172.16.10.1 172.16.10.2 172.16.10.3 [tikv_servers] TiKV1-1 ansible_host=172.16.10.4 deploy_dir=/data1/deploy tikv_port=20171 labels="host=tikv1" TiKV1-2 ansible_host=172.16.10.4 deploy_dir=/data2/deploy tikv_port=20172 labels="host=tikv1" TiKV2-1 ansible_host=172.16.10.5 deploy_dir=/data1/deploy tikv_port=20171 labels="host=tikv2" TiKV2-2 ansible_host=172.16.10.5 deploy_dir=/data2/deploy tikv_port=20172 labels="host=tikv2" TiKV3-1 ansible_host=172.16.10.6 deploy_dir=/data1/deploy tikv_port=20171 labels="host=tikv3" TiKV3-2 ansible_host=172.16.10.6 deploy_dir=/data2/deploy tikv_port=20172 labels="host=tikv3" [monitoring_servers] 172.16.10.1 [grafana_servers] 172.16.10.1 [monitored_servers] 172.16.10.1 172.16.10.2 172.16.10.3 172.16.10.4 172.16.10.5 172.16.10.6 ...... [pd_servers:vars] location_labels = ["host"] 服务配置文件参数调整 多实例情况下,需要修改 tidb-ansible/conf/tikv.yml 中的 end-point-concurrency 以及 block-cache-size 参数: end-point-concurrency: 总数低于 CPU Vcores 即可 rocksdb defaultcf block-cache-size(GB) = MEM * 80% / TiKV 实例数量 * 30% rocksdb writecf block-cache-size(GB) = MEM * 80% / TiKV 实例数量 * 45% rocksdb lockcf block-cache-size(GB) = MEM * 80% / TiKV 实例数量 * 2.5% (最小 128 MB) raftdb defaultcf block-cache-size(GB) = MEM * 80% / TiKV 实例数量 * 2.5% (最小 128 MB) 如果多个 TiKV 实例部署在同一块物理磁盘上,需要修改 conf/tikv.yml 中的 capacity 参数: capacity = (DISK - 日志空间) / TiKV 实例数量,单位为 GB inventory.ini 变量调整 部署目录调整 部署目录通过 deploy_dir 变量控制,默认全局变量已设置为 /home/tidb/deploy,对所有服务生效。如数据盘挂载目录为 /data1,可设置为 /data1/deploy,样例如下:## Global variables [all:vars] deploy_dir = /data1/deploy 如为某一服务单独设置部署目录,可在配置服务主机列表时配置主机变量,以 TiKV 节点为例,其他服务类推,请务必添加第一列别名,以免服务混布时混淆。TiKV1-1 ansible_host=172.16.10.4 deploy_dir=/data1/deploy 其他变量调整 注: 以下控制变量开启请使用首字母大写 True,关闭请使用首字母大写 False。 变量 含义 cluster_name 集群名称,可调整 tidb_version TiDB 版本,TiDB-Ansible 各分支默认已配置 deployment_method 部署方式,默认为 binary,可选 docker process_supervision 进程监管方式,默认为 systemd,可选 supervise timezone 修改部署目标机器时区,默认为 Asia/Shanghai,可调整,与 set_timezone 变量结合使用 set_timezone 默认为 True,即修改部署目标机器时区,关闭可修改为 False enable_firewalld 开启防火墙,默认不开启 enable_ntpd 检测部署目标机器 NTP 服务,默认为 True,请勿关闭 set_hostname 根据 IP 修改部署目标机器主机名,默认为 False enable_binlog 是否部署 pump 并开启 binlog,默认为 False,依赖 Kafka 集群,参见 zookeeper_addrs 变量 zookeeper_addrs binlog Kafka 集群的 zookeeper 地址 enable_slow_query_log TiDB 慢查询日志记录到单独文件({{ deploy_dir }}/log/tidb_slow_query.log),默认为 False,记录到 tidb 日志 deploy_without_tidb KV 模式,不部署 TiDB 服务,仅部署 PD、TiKV 及监控服务,请将 inventory.ini 文件中 tidb_servers 主机组 IP 设置为空。 部署任务 ansible-playbook 执行 Playbook 时默认并发为 5,部署目标机器较多时可添加 -f 参数指定并发,如 ansible-playbook deploy.yml -f 10 确认 tidb-ansible/inventory.ini 文件中 ansible_user = tidb,本例使用 tidb 用户作为服务运行用户,配置如下:## Connection # ssh via root: # ansible_user = root # ansible_become = true # ansible_become_user = tidb # ssh via normal user ansible_user = tidb 执行以下命令如果所有 server 返回 tidb 表示 ssh 互信配置成功。ansible -i inventory.ini all -m shell -a 'whoami' 执行以下命令如果所有 server 返回 root 表示 tidb 用户 sudo 免密码配置成功。ansible -i inventory.ini all -m shell -a 'whoami' -b 执行 local_prepare.yml playbook,联网下载 TiDB binary 到中控机:ansible-playbook local_prepare.yml 初始化系统环境,修改内核参数ansible-playbook bootstrap.yml 部署 TiDB 集群软件ansible-playbook deploy.yml 启动 TiDB 集群ansible-playbook start.yml 如希望使用 root 用户远程连接部署,请参考使用 root 用户远程连接 TiDB Ansible 部署方案,不推荐使用该方式部署。 测试集群 测试连接 TiDB 集群,推荐在 TiDB 前配置负载均衡来对外统一提供 SQL 接口。 使用 MySQL 客户端连接测试,TCP 4000 端口是 TiDB 服务默认端口。mysql -u root -h 172.16.10.1 -P 4000 通过浏览器访问监控平台。地址:http://172.16.10.1:3000 默认帐号密码是:admin/admin 滚动升级 滚动升级 TiDB 服务,滚动升级期间不影响业务运行(最小环境 :pd*3 、tidb*2、tikv*3) 如果集群环境中有 pump / drainer 服务,请先停止 drainer 后滚动升级 (升级 TiDB 时会升级 pump)。 自动下载 binary 修改 inventory.ini 中的 tidb_version 参数值,指定需要升级的版本号,本例指定升级的版本号为 v1.0.2tidb_version = v1.0.2 删除原有的 downloads 目录 tidb-ansible/downloads/rm -rf downloads 使用 playbook 下载 TiDB 1.0 版本 binary,自动替换 binary 到 tidb-ansible/resource/bin/ansible-playbook local_prepare.yml 手动下载 binary 除 “下载 binary” 中描述的方法之外,也可以手动下载 binary,解压后手动替换 binary 到 tidb-ansible/resource/bin/,请注意替换链接中的版本号wget http://download.pingcap.org/tidb-v1.0.0-linux-amd64-unportable.tar.gz 使用 Ansible 滚动升级 滚动升级 TiKV 节点( 只升级 TiKV 服务 )ansible-playbook rolling_update.yml --tags=tikv 滚动升级 PD 节点( 只升级单独 PD 服务 )ansible-playbook rolling_update.yml --tags=pd 滚动升级 TiDB 节点( 只升级单独 TiDB 服务 )ansible-playbook rolling_update.yml --tags=tidb 滚动升级所有服务ansible-playbook rolling_update.yml 常见运维操作汇总 任务 Playbook 启动集群 ansible-playbook start.yml 停止集群 ansible-playbook stop.yml 销毁集群 ansible-playbook unsafe_cleanup.yml (若部署目录为挂载点,会报错,可忽略) 清除数据(测试用) ansible-playbook unsafe_cleanup_data.yml 滚动升级 ansible-playbook rolling_update.yml 滚动升级 TiKV ansible-playbook rolling_update.yml --tags=tikv 滚动升级除 pd 外模块 ansible-playbook rolling_update.yml --skip-tags=pd 滚动升级监控组件 ansible-playbook rolling_update_monitor.yml 常见部署问题 如何下载安装指定版本 TiDB 如需安装 TiDB 1.0.4 版本,需要先下载 TiDB-Ansible release-1.0 分支,确认 inventory.ini 文件中 tidb_version = v1.0.4,安装步骤同上。从 github 下载 TiDB-Ansible release-1.0 分支:git clone -b release-1.0 https://github.com/pingcap/tidb-ansible.git 如何自定义端口 修改 inventory.ini 文件,在相应服务 IP 后添加以下主机变量即可: 组件 端口变量 默认端口 说明 TiDB tidb_port 4000 应用及 DBA 工具访问通信端口 TiDB tidb_status_port 10080 TiDB 状态信息上报通信端口 TiKV tikv_port 20160 TiKV 通信端口 PD pd_client_port 2379 提供 TiDB 和 PD 通信端口 PD pd_peer_port 2380 PD …"}, {"url": "https://pingcap.com/docs/tools/tidb-binlog-cluster/", "title": "TiDB-Binlog Cluster User Guide", "content": " TiDB-Binlog Cluster User Guide This document introduces the architecture and the deployment of TiDB-Binlog of the cluster version.TiDB-Binlog is an enterprise tool used to collect the binlog data of TiDB and provide real-time backup and synchronization.TiDB-Binlog has the following features: Data synchronization: synchronize the data in the TiDB cluster to other databases Real-time backup and restoration: back up the data in the TiDB cluster and restore the TiDB cluster when the cluster fails TiDB-Binlog architecture The TiDB-Binlog architecture is as follows:The TiDB-Binlog cluster is composed of Pump and Drainer.Pump Pump is used to record the binlogs generated in TiDB, sort the binlogs based on the commit time of the transaction, and send binlogs to Drainer for consumption.Drainer Drainer collects and merges binlogs from each Pump, converts the binlog to SQL or data of a specific format, and synchronizes the data to the downstream.Main features Multiple Pumps form a cluster which can scale out horizontally. TiDB uses the built-in Pump Client to send the binlog to each Pump. Pump stores binlogs and sends the binlogs to Drainer in order. Drainer reads binlogs of each Pump, merges and sorts the binlogs, and sends the binlogs to the downstream. Hardware requirements Pump and Drainer can be deployed and run on common 64-bit hardware server platforms with the Intel x86-64 architecture.The server hardware requirements for development, testing, and the production environment are as follows: Service The Number of Servers CPU Disk Memory Pump 3 8 core+ SSD, 200 GB+ 16G Drainer 1 8 core+ SAS, 100 GB+ (If you need to output a local file, use SSD and increase the disk size) 16G Notes You need to use TiDB v2.0.8-binlog, v2.1.0-rc.5 or the later version. Otherwise, the TiDB cluster is not compatible with the cluster version of TiDB-Binlog. When TiDB is running, you need to guarantee that at least one Pump is running normally. To enable TiDB-Binlog, add the enable-binlog startup parameter to TiDB. Drainer does not support the rename DDL operation on the table of ignore schemas (the schemas in the filter list). If you want to start Drainer in the existing TiDB cluster, generally, you need to make a full backup of the cluster data, obtain savepoint, import the data to the target database, and then start Drainer to synchronize the incremental data from savepoint. Drainer supports synchronizing binlogs to MySQL, TiDB, Kafka or the local files. If you need to synchronize binlogs to other destinations, you can set Drainer to synchronize the binlog to Kafka and read the data in Kafka for customization processing. See Binlog Slave Client User Guide. If TiDB-Binlog is used for recovering the incremental data, you can set the downstream to pb (local files in the proto buffer format). Drainer converts the binlog to data in the specified proto buffer format and writes the data to local files. In this way, you can use Reparo to recover the incremental data. Pump/Drainer has two states: paused and offline. If you press Ctrl + C or kill the process, both Pump and Drainer become paused. The paused Pump do not need to send all the binlog data to Drainer. If you need to exit from Pump for a long period of time (or do not use Pump any more), use binlogctl to make Pump offline. The same goes for Drainer. If the downstream is MySQL/TiDB, you can use sync-diff-inspector to verify the data after data synchronization. TiDB-Binlog deployment This section shows two methods of deploying TiDB-Binlog: Deploy TiDB-Binlog using TiDB-Ansible Deploy TiDB-Binlog using Binary It is recommended to deploy TiDB-Binlog using TiDB-Ansible. If you just want to do a simple testing, you can deploy TiDB-Binlog using Binary.Deploy TiDB-Binlog using TiDB-Ansible Step 1: Download TiDB-Ansible Use the TiDB user account to log in to the central control machine and go to the /home/tidb directory. The information about the branch of TiDB-Ansible and the corresponding TiDB version is as follows. If you have questions regarding which version to use, email to info@pingcap.com for more information or file an issue. tidb-ansible branch TiDB version Note release-2.0 2.0 version The latest 2.0 stable version. You can use it in the production environment. release-2.1 2.1 version The latest 2.1 stable version. You can use it in the production environment (recommended). master master version This version includes the latest features with a daily update. Use the following command to download the corresponding branch of TiDB-Ansible from the TiDB-Ansible project on GitHub. The default folder name is tidb-ansible. Download the 2.0 version:$ git clone -b release-2.0-new-binlog https://github.com/pingcap/tidb-ansible.git Download the 2.1 version:$ git clone -b release-2.1 https://github.com/pingcap/tidb-ansible.git Download the master version:$ git clone https://github.com/pingcap/tidb-ansible.git Step 2: Deploy Pump Modify the tidb-ansible/inventory.ini file. Set enable_binlog = True to start binlog of the TiDB cluster.## binlog trigger enable_binlog = True Add the deployment machine IPs for pump_servers.## Binlog Part [pump_servers] 172.16.10.72 172.16.10.73 172.16.10.74 Pump retains the data of the latest 5 days by default. You can modify the value of the gc variable in the tidb-ansible/conf/pump.yml file and remove the related comments. Take modifying the variable value to 7 as an example:global: # an integer value to control the expiry date of the binlog data, which indicates for how long (in days) the binlog data would be stored # must be bigger than 0 gc: 7 Make sure the space of the deployment directory is sufficient for storing Binlog. For more details, see Configure the deployment directory. You can also set a separate deployment directory for Pump.## Binlog Part [pump_servers] pump1 ansible_host=172.16.10.72 deploy_dir=/data1/pump pump2 ansible_host=172.16.10.73 deploy_dir=/data1/pump pump3 ansible_host=172.16.10.74 deploy_dir=/data1/pump Deploy and start the TiDB cluster.For how to use Ansible to deploy the TiDB cluster, see Deploy TiDB Using Ansible. When Binlog is enabled, Pump is deployed and started by default. Check the Pump status.Use binlogctl to check the Pump status. Change the pd-urls parameter to the PD address of the cluster. If State is online, Pump is started successfully.$ cd /home/tidb/tidb-ansible $ resources/bin/binlogctl -pd-urls=http://172.16.10.72:2379 -cmd pumps 2018/09/21 16:45:54 nodes.go:46: [info] pump: &{NodeID:ip-172-16-10-72:8250 Addr:172.16.10.72:8250 State:online IsAlive:false Score:0 Label:<nil> MaxCommitTS:0 UpdateTS:403051525690884099} 2018/09/21 16:45:54 nodes.go:46: [info] pump: &{NodeID:ip-172-16-10-73:8250 Addr:172.16.10.73:8250 State:online IsAlive:false Score:0 Label:<nil> MaxCommitTS:0 UpdateTS:403051525703991299} 2018/09/21 16:45:54 nodes.go:46: [info] pump: &{NodeID:ip-172-16-10-74:8250 Addr:172.16.10.74:8250 State:online IsAlive:false Score:0 Label:<nil> MaxCommitTS:0 UpdateTS:403051525717360643} Step 3: Deploy Drainer Obtain initial_commit_ts.Run the following command to use binlogctl to generate the tso information which is needed for the initial start of Drainer:$ cd /home/tidb/tidb-ansible $ resources/bin/binlogctl -pd-urls=http://127.0.0.1:2379 -cmd generate_meta INFO[0000] [pd] create pd client with endpoints [http://192.168.199.118:32379] INFO[0000] [pd] leader switches to: http://192.168.199.118:32379, previous: INFO[0000] [pd] init cluster id 6569368151110378289 2018/06/21 11:24:47 meta.go:117: [info] meta: &{CommitTS:400962745252184065} After this command is executed, a file named {data-dir}/savepoint is generated. This file contains tso, whose value is used as the value of the initial-commit-ts parameter needed for the initial start of Drainer. Back up and restore all the data.If the downstream is MySQL/TiDB, to guarantee the data integrity, you need to make a full backup and restore of …"}, {"url": "https://pingcap.com/docs-cn/tools/tidb-binlog-cluster/", "title": "TiDB-Binlog Cluster 版本用户文档", "content": " TiDB-Binlog Cluster 版本用户文档 本文档介绍 cluster 版本 TiDB-Binlog 的架构以及部署方案。TiDB-Binlog 是一个用于收集 TiDB 的 Binlog,并提供实时备份和同步功能的商业工具。TiDB-Binlog 支持以下功能场景: 数据同步:同步 TiDB 集群数据到其他数据库 实时备份和恢复:备份 TiDB 集群数据,同时可以用于 TiDB 集群故障时恢复 TiDB-Binlog 架构 TiDB-Binlog 的整体架构:TiDB-Binlog 集群主要分为 Pump 和 Drainer 两个组件:Pump Pump 用于实时记录 TiDB 产生的 Binlog,并将 Binlog 按照事务的提交时间进行排序,再提供给 Drainer 进行消费。Drainer Drainer 从各个 Pump 中收集 Binlog 进行归并,再将 Binlog 转化成 SQL 或者指定格式的数据,最终同步到下游。主要特性 多个 Pump 形成一个集群,可以水平扩容; TiDB 通过内置的 Pump Client 将 Binlog 分发到各个 Pump; Pump 负责存储 Binlog,并将 Binlog 按顺序提供给 Drainer; Drainer 负责读取各个 Pump 的 Binlog,归并排序后发送到下游。 服务器要求 Pump 和 Drainer 都支持部署和运行在 Intel x86-64 架构的 64 位通用硬件服务器平台上。对于开发,测试以及生产环境的服务器硬件配置有以下要求和建议: 服务 部署数量 CPU 磁盘 内存 Pump 3 8核+ SSD, 200 GB+ 16G Drainer 1 8核+ SAS, 100 GB+ (如果输出为本地文件,则使用 SSD,并增加磁盘大小) 16G 注意 需要使用 TiDB v2.0.8-binlog、v2.1.0-rc.5 及以上版本,否则不兼容该版本的 TiDB-Binlog。 在运行 TiDB 时,需要保证至少一个 Pump 正常运行。 通过给 TiDB 增加启动参数 enable-binlog 来开启 binlog 服务。尽量保证同一集群的所有 TiDB 都开启了 binlog 服务,否则在同步数据时可能会导致上下游数据不一致。如果要临时运行一个不开启 binlog 服务的 TiDB 实例,需要在 TiDB 的配置文件中设置 run_ddl= false。 Drainer 不支持对 ignore schemas(在过滤列表中的 schemas)的 table 进行 rename DDL 操作。 在已有的 TiDB 集群中启动 Drainer,一般需要全量备份并且获取 savepoint,然后导入全量备份,最后启动 Drainer 从 savepoint 开始同步增量数据。 Drainer 支持将 Binlog 同步到 MySQL、TiDB、Kafka 或者本地文件。如果需要将 Binlog 同步到其他类型的目的地中,可以设置 Drainer 将 Binlog 同步到 Kafka,再读取 Kafka 中的数据进行自定义处理,参考 binlog slave client 用户文档。 如果 TiDB-Binlog 用于增量恢复,可以设置下游为 pb,drainer 会将 binlog 转化为指定的 proto buffer 格式的数据,再写入到本地文件中。这样就可以使用 Reparo 恢复增量数据。 Pump/Drainer 的状态需要区分已暂停(paused)和下线(offline),Ctrl + C 或者 kill 进程,Pump 和 Drainer 的状态都将变为 paused。暂停状态的 Pump 不需要将已保存的 Binlog 数据全部发送到 Drainer;如果需要较长时间退出 Pump(或不再使用该 Pump),需要使用 binlogctl 工具来下线 Pump。Drainer 同理。 如果下游为 MySQL/TiDB,数据同步后可以使用 sync-diff-inspector 进行数据校验。 TiDB-Binlog 部署 使用 TiDB-Ansible 部署 TiDB-Binlog 第 1 步:下载 TiDB-Ansible 以 TiDB 用户登录中控机并进入 /home/tidb 目录。以下为 TiDB-Ansible 分支与 TiDB 版本的对应关系,版本选择可咨询官方 info@pingcap.com。 TiDB-Ansible 分支 TiDB 版本 备注 release-2.0-new-binlog 2.0 版本 最新 2.0 稳定版本,可用于生产环境。 release-2.1 2.1 版本 最新 2.1 稳定版本,可用于生产环境(建议)。 master master 版本 包含最新特性,每日更新。 使用以下命令从 GitHub TiDB-Ansible 项目上下载 TiDB-Ansible 相应分支,默认的文件夹名称为 tidb-ansible。 下载 2.0 版本:$ git clone -b release-2.0-new-binlog https://github.com/pingcap/tidb-ansible.git 下载 2.1 版本:$ git clone -b release-2.1 https://github.com/pingcap/tidb-ansible.git 下载 master 版本:$ git clone https://github.com/pingcap/tidb-ansible.git 第 2 步:部署 Pump 修改 tidb-ansible/inventory.ini 文件 设置 enable_binlog = True,表示 TiDB 集群开启 binlog。## binlog trigger enable_binlog = True 为 pump_servers 主机组添加部署机器 IP。## Binlog Part [pump_servers] 172.16.10.72 172.16.10.73 172.16.10.74 默认 Pump 保留 5 天数据,如需修改可修改 tidb-ansible/conf/pump.yml 文件中 gc 变量值,并取消注释,如修改为 7。global: # an integer value to control the expiry date of the binlog data, which indicates for how long (in days) the binlog data would be stored # must be bigger than 0 gc: 7 请确保部署目录有足够空间存储 binlog,详见:部署目录调整,也可为 Pump 设置单独的部署目录。## Binlog Part [pump_servers] pump1 ansible_host=172.16.10.72 deploy_dir=/data1/pump pump2 ansible_host=172.16.10.73 deploy_dir=/data1/pump pump3 ansible_host=172.16.10.74 deploy_dir=/data1/pump 部署并启动 TiDB 集群使用 Ansible 部署 TiDB 集群的具体方法参考 TiDB Ansible 部署方案,开启 binlog 后默认会部署和启动 Pump 服务。 查看 Pump 服务状态使用 binlogctl 查看 Pump 服务状态,pd-urls 参数请替换为集群 PD 地址,结果 State 为 online 表示 Pump 启动成功。$ cd /home/tidb/tidb-ansible $ resources/bin/binlogctl -pd-urls=http://172.16.10.72:2379 -cmd pumps 2018/09/21 16:45:54 nodes.go:46: [info] pump: &{NodeID:ip-172-16-10-72:8250 Addr:172.16.10.72:8250 State:online IsAlive:false Score:0 Label:<nil> MaxCommitTS:0 UpdateTS:403051525690884099} 2018/09/21 16:45:54 nodes.go:46: [info] pump: &{NodeID:ip-172-16-10-73:8250 Addr:172.16.10.73:8250 State:online IsAlive:false Score:0 Label:<nil> MaxCommitTS:0 UpdateTS:403051525703991299} 2018/09/21 16:45:54 nodes.go:46: [info] pump: &{NodeID:ip-172-16-10-74:8250 Addr:172.16.10.74:8250 State:online IsAlive:false Score:0 Label:<nil> MaxCommitTS:0 UpdateTS:403051525717360643} 第 3 步:部署 Drainer 获取 initial_commit_ts使用 binlogctl 工具生成 Drainer 初次启动所需的 tso 信息,命令:$ cd /home/tidb/tidb-ansible $ resources/bin/binlogctl -pd-urls=http://127.0.0.1:2379 -cmd generate_meta INFO[0000] [pd] create pd client with endpoints [http://192.168.199.118:32379] INFO[0000] [pd] leader switches to: http://192.168.199.118:32379, previous: INFO[0000] [pd] init cluster id 6569368151110378289 2018/06/21 11:24:47 meta.go:117: [info] meta: &{CommitTS:400962745252184065} 该命令会生成一个文件 {data-dir}/savepoint,该文件中包含 tso,用该 tso 作为 Drainer 初次启动使用的 initial-commit-ts 参数的值。 全量数据的备份与恢复如果下游为 MySQL/TiDB, 需要保证数据的完整性,在 Drainer 启动前(Pump 运行后十分钟左右)进行数据的全量备份和恢复。推荐使用 mydumper 备份 TiDB 的全量数据,再使用 loader 将备份数据导入到下游。具体使用方法参考:备份与恢复。 修改 tidb-ansible/inventory.ini 文件为 drainer_servers 主机组添加部署机器 IP,initial_commit_ts 请设置为获取的 initial_commit_ts,仅用于 Drainer 第一次启动。 以下游为 MySQL 为例,别名为 drainer_mysql。[drainer_servers] drainer_mysql ansible_host=172.16.10.71 initial_commit_ts="402899541671542785" 以下游为 pb 为例,别名为 drainer_pb。[drainer_servers] drainer_pb ansible_host=172.16.10.71 initial_commit_ts="402899541671542785" 修改配置文件 以下游为 MySQL 为例$ cd /home/tidb/tidb-ansible/conf $ cp drainer.toml drainer_mysql_drainer.toml $ vi drainer_mysql_drainer.toml 注意: 配置文件名命名规则为 别名_drainer.toml,否则部署时无法找到自定义配置文件。 db-type 设置为 “mysql”, 配置下游 MySQL 信息。# downstream storage, equal to --dest-db-type # Valid values are "mysql", "pb", "kafka", "flash". db-type = "mysql" # the downstream MySQL protocol database [syncer.to] host = "172.16.10.72" user = "root" password = "123456" port = 3306 # Time and size limits for flash batch write # time-limit = "30s" # size-limit = "100000" 以下游为 proto buffer(pb)格式的本地文件为例$ cd /home/tidb/tidb-ansible/conf $ cp drainer.toml drainer_pb_drainer.toml $ vi drainer_pb_drainer.toml db-type 设置为 “pb”。# downstream storage, equal to --dest-db-type # Valid values are "mysql", "pb", "kafka", "flash". db-type = "pb" # Uncomment this if you want to use `pb` or `sql` as `db-type`. # `Compress` compresses the output file, like the `pb` and `sql` file. Now it supports the `gzip` algorithm only. # The value can be `gzip`. Leave it empty to disable compression. [syncer.to] compression = "" # default data directory: "{{ deploy_dir }}/data.drainer" # dir = "data.drainer" 部署 Drainer$ ansible-playbook deploy_drainer.yml 启动 Drainer$ ansible-playbook start_drainer.yml 使用 Binary 部署 TiDB-Binlog 下载官方 Binary wget https://download.pingcap.org/tidb-{version}-linux-amd64.tar.gz wget https://download.pingcap.org/tidb-{version}-linux-amd64.sha256 # 检查文件完整性,返回 ok 则正确 sha256sum -c tidb-{version}-linux-amd64.sha256 对于 v2.1.0 GA 及以上版本,Pump 和 Drainer 已经包含在 TiDB 的下载包中,其他版本需要单独下载 Pump 和 Drainer:wget https://download.pingcap.org/tidb-binlog-{version}-linux-amd64.tar.gz wget https://download.pingcap.org/tidb-binlog-{version}-linux-amd64.sha256 # 检查文件完整性,返回 ok 则正确 sha256sum -c tidb-binlog-{version}-linux-amd64.sha256 使用样例 假设有三个 PD,一个 TiDB,另外有两台机器用于部署 Pump,一台机器用于部署 Drainer。各个节点信息如下:TiDB="192.168.0.10" PD1="192.168.0.16" PD2="192.168.0.15" PD3="192.168.0.14" Pump="192.168.0.11" Pump="192.168.0.12" Drainer="192.168.0.13" 下面以此为例,说明 Pump/Drainer 的使用。 使用 binary 部署 Pump Pump 命令行参数说明(以在 “192.168.0.11” 上部署为例)Usage of Pump: -L string 日志输出信息等级设置:debug,info,warn,error,fatal (默认 "info") -V 打印版本信息 -addr string Pump 提供服务的 RPC 地址(-addr="192.168.0.11:8250") -advertise-addr string Pump 对外提供服务的 RPC 地址(-advertise-addr="192.168.0.11:8250") -config string 配置文件路径,如果你指定了配置文件,Pump 会首先读取配置文件的配置; 如果对应的配置在命令行参数里面也存在,Pump 就会使用命令行参数的配置来覆盖配置文件里的配置。 -data-dir string Pump 数据存储位置路径 -enable-tolerant 开启 tolerant 后,如果 binlog 写入失败,Pump 不会报错(默认开启) -gc int Pump 只保留多少天以内的数据 (默认 7) -heartbeat-interval int Pump 向 PD 发送心跳间隔 (单位 秒) -log-file string log 文件路径 -log-rotate string log 文件切换频 …"}, {"url": "https://pingcap.com/docs/tools/tidb-binlog-monitor/", "title": "TiDB-Binlog Monitoring Metrics and Alert Rules", "content": " TiDB-Binlog Monitoring Metrics and Alert Rules This document describes TiDB-Binlog monitoring metrics in Grafana and explains the alert rules.Monitoring metrics TiDB-Binlog consists of two components: Pump and Drainer. This section shows the monitoring metrics of Pump and Drainer.Pump monitoring metrics To understand the Pump monitoring metrics, check the following table: Pump monitoring metrics Description Storage Size Records the total disk space (capacity) and the available disk space (available) Metadata Records the biggest TSO (gc_tso) of the binlog that each Pump node can delete, and the biggest commit TSO (max_commit_tso) of the saved binlog Write Binlog QPS by Instance Shows QPS of writing binlog requests received by each Pump node Write Binlog Latency Records the latency time of each Pump node writing binlog Storage Write Binlog Size Shows the size of the binlog data written by Pump Storage Write Binlog Latency Records the latency time of the Pump storage module writing binlog Pump Storage Error By Type Records the number of errors encountered by Pump, counted based on the type of error Query TiKV The number of times that Pump queries the transaction status through TiKV Drainer monitoring metrics To understand the Drainer monitoring metrics, check the following table: Drainer monitoring metrics Description Checkpoint TSO Shows the biggest TSO time of the binlog that Drainer has already synchronized into the downstream. You can get the lag by using the current time to subtract the binlog timestamp. But be noted that the timestamp is allocated by PD of the master cluster and is determined by the time of PD. Pump Handle TSO Records the biggest TSO time among the binlog files that Drainer obtains from each Pump node Pull Binlog QPS by Pump NodeID Shows the QPS when Drainer obtains binlog from each Pump node 95% Binlog Reach Duration By Pump Records the delay from the time when binlog is written into Pump to the time when the binlog is obtained by Drainer Error By Type Shows the number of errors encountered by Drainer, counted based on the type of error Drainer Event Shows the number of various types of events, including “ddl”, “insert”, “delete”, “update”, “flush”, and “savepoint” Execute Time Records the time it takes to execute the SQL statement in the downstream, or the time it takes to write data into downstream 95% Binlog Size Shows the size of the binlog data that Drainer obtains from each Pump node DDL Job Count Records the number of DDL statements handled by Drainer Alert rules Currently, TiDB-Binlog monitoring metrics are divided into the following three types based on the level of importance: Emergency Critical Warning Emergency binlog_pump_storage_error_count Description: Pump fails to write the binlog data to the local storage Monitoring rule: changes(binlog_pump_storage_error_count[1m]) > 0 Solution: Check whether an error exists in the pump_storage_error monitoring and check the Pump log to find the causes Critical binlog_drainer_checkpoint_high_delay Description: The delay of Drainer synchronization exceeds one hour Monitoring rule: (time() - binlog_drainer_checkpoint_tso / 1000) > 3600 Solutions: Check whether it is too slow to obtain the data from Pump:You can check handle tso of Pump to get the time for the latest message of each Pump. Check whether a high latency exists for Pump and make sure the corresponding Pump is running normally Check whether it is too slow to synchronize data in the downstream based on Drainer event and Drainer execute latency: If Drainer execute time is too large, check the network bandwidth and latency between the machine with Drainer deployed and the machine with the target database deployed, and the state of the target database If Drainer execute time is not too large and Drainer event is too small, add work count and batch and retry If the two solutions above cannot work, contact support@pingcap.com Warning binlog_pump_write_binlog_rpc_duration_seconds_bucket Description: It takes too much time for Pump to handle the TiDB request of writing binlog Monitoring rule: histogram_quantile(0.9, rate(binlog_pump_rpc_duration_seconds_bucket{method="WriteBinlog"}[5m])) > 1 Solution: Verify the disk performance pressure and check the disk performance monitoring via node exported If both disk latency and util are low, contact support@pingcap.com binlog_pump_storage_write_binlog_duration_time_bucket Description: The time it takes for Pump to write the local binlog to the local disk Monitoring rule: histogram_quantile(0.9, rate(binlog_pump_storage_write_binlog_duration_time_bucket{type="batch"}[5m])) > 1 Solution: Check the state of the local disk of Pump and fix the problem binlog_pump_storage_available_size_less_than_20G Description: The available disk space of Pump is less than 20G Monitoring rule: binlog_pump_storage_storage_size_bytes{type="available"} < 20 * 1024 * 1024 * 1024 Solution: Check whether Pump gc_tso is normal. If not, adjust the GC time configuration of Pump or get the corresponding Pump offline binlog_drainer_checkpoint_tso_no_change_for_1m Description: Drainer checkpoint has not been updated for one minute Monitoring rule: changes(binlog_drainer_checkpoint_tso[1m]) < 1 Solution: Check whether all the Pumps that are not offline are running normally binlog_drainer_execute_duration_time_more_than_10s Description: The transaction time it takes Drainer to synchronize data to TiDB. If it is too large, the Drainer synchronization of data is affected Monitoring rule: histogram_quantile(0.9, rate(binlog_drainer_execute_duration_time_bucket[1m])) > 10 Solutions: Check the TiDB cluster state Check the Drainer log or monitor. If a DDL operation causes this problem, you can ignore it "}, {"url": "https://pingcap.com/docs/tools/tidb-binlog-kafka/", "title": "TiDB-Binlog user guide", "content": " TiDB-Binlog User Guide This document describes how to deploy the Kafka version of TiDB-Binlog.About TiDB-Binlog TiDB-Binlog is a tool for enterprise users to collect binlog files for TiDB and provide real-time backup and synchronization.TiDB-Binlog supports the following scenarios: Data synchronization: to synchronize TiDB cluster data to other databases Real-time backup and recovery: to back up TiDB cluster data, and recover in case of cluster outages TiDB-Binlog architecture The TiDB-Binlog architecture is as follows:The TiDB-Binlog cluster mainly consists of three components:Pump Pump is a daemon that runs on the background of each TiDB host. Its main function is to record the binlog files generated by TiDB in real time and write to the file in the disk sequentially.Drainer Drainer collects binlog files from each Pump node, converts them into specified database-compatible SQL statements in the commit order of the transactions in TiDB, and synchronizes to the target database or writes to the file sequentially.Kafka & ZooKeeper The Kafka cluster stores the binlog data written by Pump and provides the binlog data to Drainer for reading. Note: In the local version of TiDB-Binlog, the binlog is stored in files, while in the latest version, the binlog is stored using Kafka. Install TiDB-Binlog The corresponding relationship between the tidb-ansible branch and the TiDB version is as follows: tidb-ansible branch TiDB version Note release-2.0 2.0 version The latest 2.0 stable version. You can use it in the production environment. Download Binary for the CentOS 7.3+ platform # Download the tool package. wget http://download.pingcap.org/tidb-binlog-kafka-linux-amd64.tar.gz wget http://download.pingcap.org/tidb-binlog-kafka-linux-amd64.sha256 # Check the file integrity. If the result is OK, the file is correct. sha256sum -c tidb-binlog-kafka-linux-amd64.sha256 # Extract the package. tar -xzf tidb-binlog-kafka-linux-amd64.tar.gz cd tidb-binlog-kafka-linux-amd64 Deploy TiDB-Binlog Note You need to deploy a Pump for each TiDB server in the TiDB cluster. Currently, the TiDB server only supports the binlog in UNIX socket. When you deploy a Pump manually, to start the service, follow the order of Pump -> TiDB; to stop the service, follow the order of TiDB -> Pump.We set the startup parameter binlog-socket as the specified unix socket file path of the corresponding parameter socket in Pump. The final deployment architecture is as follows: Drainer does not support renaming DDL on the table of the ignored schemas (schemas in the filter list). To start Drainer in the existing TiDB cluster, usually you need to do a full backup, get the savepoint, import the full backup, and start Drainer and synchronize from the savepoint.To guarantee the integrity of data, perform the following operations 10 minutes after Pump is started: Use binlogctl of the tidb-tools project to generate the position for the initial start of Drainer. Do a full backup. For example, back up TiDB using Mydumper. Import the full backup to the target system. The savepoint metadata started by the Kafka version of Drainer is stored in the checkpoint table of the downstream database tidb_binlog by default. If no valid data exists in the checkpoint table, configure initial-commit-ts to make Drainer work from a specified position when it is started:bin/drainer --config=conf/drainer.toml --initial-commit-ts=${position} The drainer outputs pb and you need to set the following parameters in the configuration file:[syncer] db-type = "pb" disable-dispatch = true [syncer.to] dir = "/path/pb-dir" The drainer outputs kafka and you need to set the following parameters in the configuration file:[syncer] db-type = "kafka" # when db-type is kafka, you can uncomment this to config the down stream kafka, or it will be the same kafka addrs where drainer pulls binlog from. # [syncer.to] # kafka-addrs = "127.0.0.1:9092" # kafka-version = "0.8.2.0" The data which outputs to kafka follows the binlog format sorted by ts and defined by protobuf. See driver to access the data and sync to the down stream. Deploy Kafka and ZooKeeper cluster before deploying TiDB-Binlog. Make sure that Kafka is 0.9 version or later. Recommended Kafka cluster configuration Name Number Memory size CPU Hard disk Kafka 3+ 16G 8+ 2+ 1TB ZooKeeper 3+ 8G 4+ 2+ 300G Recommended Kafka parameter configuration auto.create.topics.enable = true: if no topic exists, Kafka automatically creates a topic on the broker. broker.id: a required parameter to identify the Kafka cluster. Keep the parameter value unique. For example, broker.id = 1. fs.file-max = 1000000: Kafka uses a lot of files and network sockets. It is recommended to change the parameter value to 1000000. Change the value using vi /etc/sysctl.conf. Configure the following three parameters to 1G, to avoid the failure of writing into Kafka caused by too large a single message when a large number of data is modified in a transaction. message.max.bytes=1073741824 replica.fetch.max.bytes=1073741824 fetch.message.max.bytes=1073741824 Deploy Pump using TiDB-Ansible If you have not deployed the Kafka cluster, use the Kafka-Ansible to deploy. When you deploy the TiDB cluster using TiDB-Ansible, edit the tidb-ansible/inventory.ini file, set enable_binlog = True, and configure the zookeeper_addrs variable as the ZooKeeper address of the Kafka cluster. In this way, Pump is deployed while you deploy the TiDB cluster. Configuration example:# binlog trigger enable_binlog = True # ZooKeeper address of the Kafka cluster. Example: # zookeeper_addrs = "192.168.0.11:2181,192.168.0.12:2181,192.168.0.13:2181" # You can also append an optional chroot string to the URLs to specify the root directory for all Kafka znodes. Example: # zookeeper_addrs = "192.168.0.11:2181,192.168.0.12:2181,192.168.0.13:2181/kafka/123" zookeeper_addrs = "192.168.0.11:2181,192.168.0.12:2181,192.168.0.13:2181" Deploy Pump using Binary A usage example:Assume that we have three PDs, three ZooKeepers, and one TiDB. The information of each node is as follows:TiDB="192.168.0.10" PD1="192.168.0.16" PD2="192.168.0.15" PD3="192.168.0.14" ZK1="192.168.0.13" ZK2="192.168.0.12" ZK3="192.168.0.11" Deploy Drainer/Pump on the machine with the IP address “192.168.0.10”.The IP address of the corresponding PD cluster is “192.168.0.16,192.168.0.15,192.168.0.14”.The ZooKeeper IP address of the corresponding Kafka cluster is “192.168.0.13,192.168.0.12,192.168.0.11”.This example describes how to use Pump/Drainer. Description of Pump command line optionsUsage of Pump: -L string log level: debug, info, warn, error, fatal (default "info") -V to print Pump version info -addr string the RPC address that Pump provides service (-addr= "192.168.0.10:8250") -advertise-addr string the RPC address that Pump provides external service (-advertise-addr="192.168.0.10:8250") -config string to configure the file path of Pump; if you specifies the configuration file, Pump reads the configuration first; if the corresponding configuration also exists in the command line argument, Pump uses the command line configuration to cover that in the configuration file -data-dir string the path of storing Pump data -enable-tolerant after enabling tolerant, Pump wouldn't return error if it fails to write binlog (default true) -zookeeper-addrs string (-zookeeper_addrs="192.168.0.11:2181,192.168.0.12:2181,192.168.0.13:2181") the ZooKeeper address; this option gets the Kafka address from ZooKeeper, and you need to keep it the same with the configuration in Kafka -gc int the maximum days that the binlog is retained (default 7), and 0 means retaining the binlog permanently -heartbeat-interval int the interval between heartbeats that Pump sends to PD (unit: second) -log-file …"}, {"url": "https://pingcap.com/docs/tools/tidb-binlog/", "title": "TiDB-Binlog user guide", "content": " TiDB-Binlog User Guide About TiDB-Binlog TiDB-Binlog is a tool for enterprise users to collect binlog files for TiDB and provide real-time backup and synchronization.TiDB-Binlog supports the following scenarios: Data synchronization: to synchronize TiDB cluster data to other databases Real-time backup and recovery: to back up TiDB cluster data, and recover in case of cluster outages TiDB-Binlog architecture The TiDB-Binlog architecture is as follows:The TiDB-Binlog cluster mainly consists of two components:Pump Pump is a daemon that runs on the background of each TiDB host. Its main function is to record the binlog files generated by TiDB in real time and write to the file in the disk sequentially.Drainer Drainer collects binlog files from each Pump node, converts them into specified database-compatible SQL statements in the commit order of the transactions in TiDB, and synchronizes to the target database or writes to the file sequentially.Install TiDB-Binlog Download Binary for the CentOS 7.3+ platform # Download the tool package. wget http://download.pingcap.org/tidb-binlog-latest-linux-amd64.tar.gz wget http://download.pingcap.org/tidb-binlog-latest-linux-amd64.sha256 # Check the file integrity. If the result is OK, the file is correct. sha256sum -c tidb-binlog-latest-linux-amd64.sha256 # Extract the package. tar -xzf tidb-binlog-latest-linux-amd64.tar.gz cd tidb-binlog-latest-linux-amd64 Deploy TiDB-Binlog It is recommended to deploy Pump using Ansible. Build a new TiDB cluster with a startup order of pd-server -> tikv-server -> pump -> tidb-server -> drainer. Edit the tidb-ansible inventory.ini file:enable_binlog = True Run ansible-playbook deploy.yml Run ansible-playbook start.yml Deploy Binlog for an existing TiDB cluster. Edit the tidb-ansible inventory.ini file:enable_binlog = True Run ansible-playbook rolling_update.yml Note You need to deploy a Pump for each TiDB server in a TiDB cluster. Currently, the TiDB server only supports the binlog in UNIX socket. We set the startup parameter binlog-socket as the specified unix socket file path of the corresponding parameter socket in Pump. The final deployment architecture is as follows: Currently, you need to deploy Drainer manually. Drainer does not support renaming DDL on the table of the ignored schemas (schemas in the filter list). To start Drainer in the existing TiDB cluster, usually you need to do a full backup, get the savepoint, import the full backup, and start Drainer and synchronize from the savepoint. To guarantee the integrity of data, perform the following operations 10 minutes after Pump is started: Run Drainer at the gen-savepoint model and generate the Drainer savepoint file:bin/drainer -gen-savepoint --data-dir= ${drainer_savepoint_dir} --pd-urls=${pd_urls} Do a full backup. For example, back up TiDB using mydumper. Import the full backup to the target system. Set the file path of the savepoint and start Drainer:bin/drainer --config=conf/drainer.toml --data-dir=${drainer_savepoint_dir} The drainer outputs pb and you need to set the following parameters in the configuration file.[syncer] db-type = "pb" disable-dispatch = true [syncer.to] dir = "/path/pb-dir" Examples and parameters explanation Pump Example./bin/pump -config pump.toml Parameters ExplanationUsage of Pump: -L string log level: debug, info, warn, error, fatal (default "info") -V print Pump version info -addr string addr(i.e. 'host:port') to listen on for client traffic (default "127.0.0.1:8250"). -advertise-addr string addr(i.e. 'host:port') to advertise to the public -config string path to the Pump configuration file -data-dir string path to store binlog data -gc int recycle binlog files older than gc days, zero means never recycle (default 7) -heartbeat-interval int number of seconds between heartbeat ticks (default 2) -log-file string log file path -log-rotate string log file rotate type, hour/day -metrics-addr string Prometheus Pushgateway address; leaving it empty will disable Prometheus push -metrics-interval int Prometheus client push interval in second, set "0" to disable Prometheus push (default 15) -pd-urls string a comma separated list of the PD endpoints (default "http://127.0.0.1:2379") -socket string unix socket addr to listen on for client traffic Configuration file# Pump Configuration. # addr(i.e. 'host:port') to listen on for client traffic addr = "127.0.0.1:8250" # addr(i.e. 'host:port') to advertise to the public advertise-addr = "" # a integer value to control expiry date of the binlog data, indicates for how long (in days) the binlog data would be stored. # (default value is 0, means binlog data would never be removed) gc = 7 # path to the data directory of Pump's data data-dir = "data.pump" # number of seconds between heartbeat ticks (in 2 seconds) heartbeat-interval = 2 # a comma separated list of PD endpoints pd-urls = "http://127.0.0.1:2379" # unix socket addr to listen on for client traffic socket = "unix:///tmp/pump.sock" Drainer Example./bin/drainer -config drainer.toml Parameters ExplanationUsage of Drainer: -L string log level: debug, info, warn, error, fatal (default "info") -V print version info -addr string addr (i.e. 'host:port') to listen on for Drainer connections (default "127.0.0.1:8249") -c int parallel worker count (default 1) -config string path to the configuration file -data-dir string Drainer data directory path (default data.drainer) (default "data.drainer") -dest-db-type string target db type: mysql or pb; see syncer section in conf/drainer.toml (default "mysql") -detect-interval int the interval time (in seconds) of detecting Pumps' status (default 10) -disable-dispatch disable dispatching sqls that in one same binlog; if set true, work-count and txn-batch would be useless -gen-savepoint generate the savepoint from cluster -ignore-schemas string disable synchronizing those schemas (default "INFORMATION_SCHEMA,PERFORMANCE_SCHEMA,mysql") -log-file string log file path -log-rotate string log file rotate type, hour/day -metrics-addr string Prometheus pushgateway address; leaving it empty will disable Prometheus push -metrics-interval int Prometheus client push interval in second, set "0" to disable Prometheus push (default 15) -pd-urls string a comma separated list of PD endpoints (default "http://127.0.0.1:2379") -txn-batch int number of binlog events in a transaction batch (default 1) Configuration file# Drainer Configuration # addr (i.e. 'host:port') to listen on for Drainer connections addr = "127.0.0.1:8249" # the interval time (in seconds) of detect Pumps' status detect-interval = 10 # Drainer meta data directory path data-dir = "data.drainer" # a comma separated list of PD endpoints pd-urls = "http://127.0.0.1:2379" # The file path of log log-file = "drainer.log" # syncer Configuration [syncer] # disable synchronizing these schemas ignore-schemas = "INFORMATION_SCHEMA,PERFORMANCE_SCHEMA,mysql" # number of binlog events in a transaction batc txn-batch = 1 # worker count to execute binlogs worker-count = 1 disable-dispatch = false # downstream storage, equal to --dest-db-type # valid values are "mysql", "pb" db-type = "mysql" # The replicate-do-db prioritizes over replicate-do-table if having the same db name. # Regular expressions are supported, and starting with '~' declares the use of regular expressions. # replicate-do-db = ["~^b.*","s1"] # [[syncer.replicate-do-table]] # db-name ="test" # tbl-name = "log" # [[syncer.replicate-do-table]] # db-name ="test" # tbl-name = "~^a.*" # the downstream mysql protocol database [syncer.to] host = "127.0.0.1" user = "root" password = "" port = 3306 # …"}, {"url": "https://pingcap.com/docs/v1.0/tools/tidb-binlog-kafka/", "title": "TiDB-Binlog user guide", "content": " TiDB-Binlog User Guide This document describes how to deploy the Kafka version of TiDB-Binlog. If you need to deploy the local version of TiDB-Binlog, see the TiDB-Binlog user guide for the local version.About TiDB-Binlog TiDB-Binlog is a tool for enterprise users to collect binlog files for TiDB and provide real-time backup and synchronization.TiDB-Binlog supports the following scenarios: Data synchronization: to synchronize TiDB cluster data to other databases Real-time backup and recovery: to back up TiDB cluster data, and recover in case of cluster outages TiDB-Binlog architecture The TiDB-Binlog architecture is as follows:The TiDB-Binlog cluster mainly consists of three components:Pump Pump is a daemon that runs on the background of each TiDB host. Its main function is to record the binlog files generated by TiDB in real time and write to the file in the disk sequentially.Drainer Drainer collects binlog files from each Pump node, converts them into specified database-compatible SQL statements in the commit order of the transactions in TiDB, and synchronizes to the target database or writes to the file sequentially.Kafka & ZooKeeper The Kafka cluster stores the binlog data written by Pump and provides the binlog data to Drainer for reading. Note: In the local version of TiDB-Binlog, the binlog is stored in files, while in the latest version, the binlog is stored using Kafka. Install TiDB-Binlog Download Binary for the CentOS 7.3+ platform # Download the tool package. wget http://download.pingcap.org/tidb-binlog-latest-linux-amd64.tar.gz wget http://download.pingcap.org/tidb-binlog-latest-linux-amd64.sha256 # Check the file integrity. If the result is OK, the file is correct. sha256sum -c tidb-binlog-latest-linux-amd64.sha256 # Extract the package. tar -xzf tidb-binlog-latest-linux-amd64.tar.gz cd tidb-binlog-latest-linux-amd64 Deploy TiDB-Binlog Note You need to deploy a Pump for each TiDB server in the TiDB cluster. Currently, the TiDB server only supports the binlog in UNIX socket. When you deploy a Pump manually, to start the service, follow the order of Pump -> TiDB; to stop the service, follow the order of TiDB -> Pump.We set the startup parameter binlog-socket as the specified unix socket file path of the corresponding parameter socket in Pump. The final deployment architecture is as follows: Drainer does not support renaming DDL on the table of the ignored schemas (schemas in the filter list). To start Drainer in the existing TiDB cluster, usually you need to do a full backup, get the savepoint, import the full backup, and start Drainer and synchronize from the savepoint.To guarantee the integrity of data, perform the following operations 10 minutes after Pump is started: Use the generate_binlog_position tool of the tidb-toolsproject to generate the Drainer savepoint file. Use generate_binlog_position to compile this tool. See the README description for usage. You can also download this tool from generate_binlog_position and use sha256sum to verify the sha256 file. Do a full backup. For example, back up TiDB using mydumper. Import the full backup to the target system. The savepoint file started by the Kafka version of Drainer is stored in the checkpoint table of the downstream database tidb_binlog by default. If no valid data exists in the checkpoint table, configure initial-commit-ts to make Drainer work from a specified position when it is started:bin/drainer --config=conf/drainer.toml --data-dir=${drainer_savepoint_dir} The drainer outputs pb and you need to set the following parameters in the configuration file:[syncer] db-type = "pb" disable-dispatch = true [syncer.to] dir = "/path/pb-dir" Deploy Kafka and ZooKeeper cluster before deploying TiDB-Binlog. Make sure that Kafka is 0.9 version or later. Recommended Kafka cluster configuration Name Number Memory size CPU Hard disk Kafka 3+ 16G 8+ 2+ 1TB ZooKeeper 3+ 8G 4+ 2+ 300G Recommended Kafka parameter configuration auto.create.topics.enable = true: if no topic exists, Kafka automatically creates a topic on the broker. broker.id: a required parameter to identify the Kafka cluster. Keep the parameter value unique. For example, broker.id = 1. fs.file-max = 1000000: Kafka uses a lot of files and network sockets. It is recommended to change the parameter value to 1000000. Change the value using vi /etc/sysctl.conf. Deploy Pump using TiDB-Ansible If you have not deployed the Kafka cluster, use the Kafka-Ansible to deploy. When you deploy the TiDB cluster using TiDB-Ansible, edit the tidb-ansible/inventory.ini file, set enable_binlog = True, and configure the zookeeper_addrs variable as the ZooKeeper address of the Kafka cluster. In this way, Pump is deployed while you deploy the TiDB cluster. Configuration example:# binlog trigger enable_binlog = True # zookeeper address of kafka cluster, example: # zookeeper_addrs = "192.168.0.11:2181,192.168.0.12:2181,192.168.0.13:2181" zookeeper_addrs = "192.168.0.11:2181,192.168.0.12:2181,192.168.0.13:2181" Deploy Pump using Binary A usage example:Assume that we have three PDs, three ZooKeepers, and one TiDB. The information of each node is as follows:TiDB="192.168.0.10" PD1="192.168.0.16" PD2="192.168.0.15" PD3="192.168.0.14" ZK1="192.168.0.13" ZK2="192.168.0.12" ZK3="192.168.0.11" Deploy Drainer/Pump on the machine with the IP address “192.168.0.10”.The IP address of the corresponding PD cluster is “192.168.0.16,192.168.0.15,192.168.0.14”.The ZooKeeper IP address of the corresponding Kafka cluster is “192.168.0.13,192.168.0.12,192.168.0.11”.This example describes how to use Pump/Drainer. Description of Pump command line optionsUsage of Pump: -L string log level: debug, info, warn, error, fatal (default "info") -V to print Pump version info -addr string the RPC address that Pump provides service (-addr= "192.168.0.10:8250") -advertise-addr string the RPC address that Pump provides external service (-advertise-addr="192.168.0.10:8250") -config string to configure the file path of Pump; if you specifies the configuration file, Pump reads the configuration first; if the corresponding configuration also exists in the command line argument, Pump uses the command line configuration to cover that in the configuration file -data-dir string the path of storing Pump data -enable-tolerant after enabling tolerant, Pump wouldn't return error if it fails to write binlog (default true) -zookeeper-addrs string (-zookeeper_addrs="192.168.0.11:2181,192.168.0.12:2181,192.168.0.13:2181") the ZooKeeper address; this option gets the Kafka address from ZooKeeper -gc int the maximum days that the binlog is retained (default 7), and 0 means retaining the binlog permanently -heartbeat-interval int the interval between heartbeats that Pump sends to PD (unit: second) -log-file string the path of the log file -log-rotate string the log file rotating frequency (hour/day) -metrics-addr string the Prometheus pushgataway address; leaving it empty disables Prometheus push -metrics-interval int the frequency of reporting monitoring information (default 15, unit: second) -pd-urls string the node address of the PD cluster (-pd-urls="http://192.168.0.16:2379,http://192.168.0.15:2379,http://192.168.0.14:2379") -socket string the monitoring address of the unix socket service (default "unix:///tmp/pump.sock") Pump configuration file# Pump configuration. # the RPC address that Pump provides service (default "192.168.0.10:8250") addr = "192.168.0.10:8250" # the RPC address that Pump provides external service (default "192.168.0.10:8250") advertise-addr = "" # an integer value to control expiry date of the binlog data, indicates how long (in days) the binlog data is stored. # (default value is 0, means binlog data would never be removed) gc = 7 # the path of …"}, {"url": "https://pingcap.com/docs/v1.0/tools/tidb-binlog/", "title": "TiDB-Binlog user guide", "content": " TiDB-Binlog User Guide About TiDB-Binlog TiDB-Binlog is a tool for enterprise users to collect binlog files for TiDB and provide real-time backup and synchronization.TiDB-Binlog supports the following scenarios: Data synchronization: to synchronize TiDB cluster data to other databases Real-time backup and recovery: to back up TiDB cluster data, and recover in case of cluster outages TiDB-Binlog architecture The TiDB-Binlog architecture is as follows:The TiDB-Binlog cluster mainly consists of two components:Pump Pump is a daemon that runs on the background of each TiDB host. Its main function is to record the binlog files generated by TiDB in real time and write to the file in the disk sequentially.Drainer Drainer collects binlog files from each Pump node, converts them into specified database-compatible SQL statements in the commit order of the transactions in TiDB, and synchronizes to the target database or writes to the file sequentially.Install TiDB-Binlog Download Binary for the CentOS 7.3+ platform # Download the tool package. wget http://download.pingcap.org/tidb-binlog-latest-linux-amd64.tar.gz wget http://download.pingcap.org/tidb-binlog-latest-linux-amd64.sha256 # Check the file integrity. If the result is OK, the file is correct. sha256sum -c tidb-binlog-latest-linux-amd64.sha256 # Extract the package. tar -xzf tidb-binlog-latest-linux-amd64.tar.gz cd tidb-binlog-latest-linux-amd64 Deploy TiDB-Binlog It is recommended to deploy Pump using Ansible. Build a new TiDB cluster with a startup order of pd-server -> tikv-server -> pump -> tidb-server -> drainer. Edit the tidb-ansible inventory.ini file:enable_binlog = True Run ansible-playbook deploy.yml Run ansible-playbook start.yml Deploy Binlog for an existing TiDB cluster. Edit the tidb-ansible inventory.ini file:enable_binlog = True Run ansible-playbook rolling_update.yml Note You need to deploy a Pump for each TiDB server in a TiDB cluster. Currently, the TiDB server only supports the binlog in UNIX socket. We set the startup parameter binlog-socket as the specified unix socket file path of the corresponding parameter socket in Pump. The final deployment architecture is as follows: Currently, you need to deploy Drainer manually. Drainer does not support renaming DDL on the table of the ignored schemas (schemas in the filter list). To start Drainer in the existing TiDB cluster, usually you need to do a full backup, get the savepoint, import the full backup, and start Drainer and synchronize from the savepoint. To guarantee the integrity of data, perform the following operations 10 minutes after Pump is started: Run Drainer at the gen-savepoint model and generate the Drainer savepoint file:bin/drainer -gen-savepoint --data-dir= ${drainer_savepoint_dir} --pd-urls=${pd_urls} Do a full backup. For example, back up TiDB using mydumper. Import the full backup to the target system. Set the file path of the savepoint and start Drainer:bin/drainer --config=conf/drainer.toml --data-dir=${drainer_savepoint_dir} The drainer outputs pb and you need to set the following parameters in the configuration file.[syncer] db-type = "pb" disable-dispatch = true [syncer.to] dir = "/path/pb-dir" Examples and parameters explanation Pump Example./bin/pump -config pump.toml Parameters ExplanationUsage of Pump: -L string log level: debug, info, warn, error, fatal (default "info") -V print Pump version info -addr string addr(i.e. 'host:port') to listen on for client traffic (default "127.0.0.1:8250"). -advertise-addr string addr(i.e. 'host:port') to advertise to the public -config string path to the Pump configuration file -data-dir string path to store binlog data -gc int recycle binlog files older than gc days, zero means never recycle (default 7) -heartbeat-interval int number of seconds between heartbeat ticks (default 2) -log-file string log file path -log-rotate string log file rotate type, hour/day -metrics-addr string Prometheus pushgataway address; leaving it empty will disable Prometheus push -metrics-interval int Prometheus client push interval in second, set "0" to disable Prometheus push (default 15) -pd-urls string a comma separated list of the PD endpoints (default "http://127.0.0.1:2379") -socket string unix socket addr to listen on for client traffic Configuration file# Pump Configuration. # addr(i.e. 'host:port') to listen on for client traffic addr = "127.0.0.1:8250" # addr(i.e. 'host:port') to advertise to the public advertise-addr = "" # a integer value to control expiry date of the binlog data, indicates for how long (in days) the binlog data would be stored. # (default value is 0, means binlog data would never be removed) gc = 7 # path to the data directory of Pump's data data-dir = "data.pump" # number of seconds between heartbeat ticks (in 2 seconds) heartbeat-interval = 2 # a comma separated list of PD endpoints pd-urls = "http://127.0.0.1:2379" # unix socket addr to listen on for client traffic socket = "unix:///tmp/pump.sock" Drainer Example./bin/drainer -config drainer.toml Parameters ExplanationUsage of Drainer: -L string log level: debug, info, warn, error, fatal (default "info") -V print version info -addr string addr (i.e. 'host:port') to listen on for Drainer connections (default "127.0.0.1:8249") -c int parallel worker count (default 1) -config string path to the configuration file -data-dir string Drainer data directory path (default data.drainer) (default "data.drainer") -dest-db-type string target db type: mysql or pb; see syncer section in conf/drainer.toml (default "mysql") -detect-interval int the interval time (in seconds) of detecting Pumps' status (default 10) -disable-dispatch disable dispatching sqls that in one same binlog; if set true, work-count and txn-batch would be useless -gen-savepoint generate the savepoint from cluster -ignore-schemas string disable synchronizing those schemas (default "INFORMATION_SCHEMA,PERFORMANCE_SCHEMA,mysql") -log-file string log file path -log-rotate string log file rotate type, hour/day -metrics-addr string Prometheus pushgateway address; leaving it empty will disable Prometheus push -metrics-interval int Prometheus client push interval in second, set "0" to disable Prometheus push (default 15) -pd-urls string a comma separated list of PD endpoints (default "http://127.0.0.1:2379") -txn-batch int number of binlog events in a transaction batch (default 1) Configuration file# Drainer Configuration # addr (i.e. 'host:port') to listen on for Drainer connections addr = "127.0.0.1:8249" # the interval time (in seconds) of detect Pumps' status detect-interval = 10 # Drainer meta data directory path data-dir = "data.drainer" # a comma separated list of PD endpoints pd-urls = "http://127.0.0.1:2379" # The file path of log log-file = "drainer.log" # syncer Configuration [syncer] # disable synchronizing these schemas ignore-schemas = "INFORMATION_SCHEMA,PERFORMANCE_SCHEMA,mysql" # number of binlog events in a transaction batc txn-batch = 1 # worker count to execute binlogs worker-count = 1 disable-dispatch = false # downstream storage, equal to --dest-db-type # valid values are "mysql", "pb" db-type = "mysql" # The replicate-do-db prioritizes over replicate-do-table if having the same db name. # Regular expressions are supported, and starting with '~' declares the use of regular expressions. # replicate-do-db = ["~^b.*","s1"] # [[syncer.replicate-do-table]] # db-name ="test" # tbl-name = "log" # [[syncer.replicate-do-table]] # db-name ="test" # tbl-name = "~^a.*" # the downstream mysql protocol database [syncer.to] host = "127.0.0.1" user = "root" password = "" port = 3306 # uncomment …"}, {"url": "https://pingcap.com/docs/v2.0/tools/tidb-binlog-kafka/", "title": "TiDB-Binlog user guide", "content": " TiDB-Binlog User Guide This document describes how to deploy the Kafka version of TiDB-Binlog. If you need to deploy the local version of TiDB-Binlog, see the TiDB-Binlog user guide for the local version.About TiDB-Binlog TiDB-Binlog is a tool for enterprise users to collect binlog files for TiDB and provide real-time backup and synchronization.TiDB-Binlog supports the following scenarios: Data synchronization: to synchronize TiDB cluster data to other databases Real-time backup and recovery: to back up TiDB cluster data, and recover in case of cluster outages TiDB-Binlog architecture The TiDB-Binlog architecture is as follows:The TiDB-Binlog cluster mainly consists of three components:Pump Pump is a daemon that runs on the background of each TiDB host. Its main function is to record the binlog files generated by TiDB in real time and write to the file in the disk sequentially.Drainer Drainer collects binlog files from each Pump node, converts them into specified database-compatible SQL statements in the commit order of the transactions in TiDB, and synchronizes to the target database or writes to the file sequentially.Kafka & ZooKeeper The Kafka cluster stores the binlog data written by Pump and provides the binlog data to Drainer for reading. Note: In the local version of TiDB-Binlog, the binlog is stored in files, while in the latest version, the binlog is stored using Kafka. Install TiDB-Binlog Download Binary for the CentOS 7.3+ platform # Download the tool package. wget http://download.pingcap.org/tidb-binlog-latest-linux-amd64.tar.gz wget http://download.pingcap.org/tidb-binlog-latest-linux-amd64.sha256 # Check the file integrity. If the result is OK, the file is correct. sha256sum -c tidb-binlog-latest-linux-amd64.sha256 # Extract the package. tar -xzf tidb-binlog-latest-linux-amd64.tar.gz cd tidb-binlog-latest-linux-amd64 Deploy TiDB-Binlog Note You need to deploy a Pump for each TiDB server in the TiDB cluster. Currently, the TiDB server only supports the binlog in UNIX socket. When you deploy a Pump manually, to start the service, follow the order of Pump -> TiDB; to stop the service, follow the order of TiDB -> Pump.We set the startup parameter binlog-socket as the specified unix socket file path of the corresponding parameter socket in Pump. The final deployment architecture is as follows: Drainer does not support renaming DDL on the table of the ignored schemas (schemas in the filter list). To start Drainer in the existing TiDB cluster, usually you need to do a full backup, get the savepoint, import the full backup, and start Drainer and synchronize from the savepoint.To guarantee the integrity of data, perform the following operations 10 minutes after Pump is started: Use binlogctl of the tidb-tools project to generate the position for the initial start of Drainer. Do a full backup. For example, back up TiDB using Mydumper. Import the full backup to the target system. The savepoint metadata started by the Kafka version of Drainer is stored in the checkpoint table of the downstream database tidb_binlog by default. If no valid data exists in the checkpoint table, configure initial-commit-ts to make Drainer work from a specified position when it is started:bin/drainer --config=conf/drainer.toml --initial-commit-ts=${position} The drainer outputs pb and you need to set the following parameters in the configuration file:[syncer] db-type = "pb" disable-dispatch = true [syncer.to] dir = "/path/pb-dir" The drainer outputs kafka and you need to set the following parameters in the configuration file:[syncer] db-type = "kafka" # when db-type is kafka, you can uncomment this to config the down stream kafka, or it will be the same kafka addrs where drainer pulls binlog from. # [syncer.to] # kafka-addrs = "127.0.0.1:9092" # kafka-version = "0.8.2.0" The data which outputs to kafka follows the binlog format sorted by ts and defined by protobuf. See driver to access the data and sync to the down stream. Deploy Kafka and ZooKeeper cluster before deploying TiDB-Binlog. Make sure that Kafka is 0.9 version or later. Recommended Kafka cluster configuration Name Number Memory size CPU Hard disk Kafka 3+ 16G 8+ 2+ 1TB ZooKeeper 3+ 8G 4+ 2+ 300G Recommended Kafka parameter configuration auto.create.topics.enable = true: if no topic exists, Kafka automatically creates a topic on the broker. broker.id: a required parameter to identify the Kafka cluster. Keep the parameter value unique. For example, broker.id = 1. fs.file-max = 1000000: Kafka uses a lot of files and network sockets. It is recommended to change the parameter value to 1000000. Change the value using vi /etc/sysctl.conf. Deploy Pump using TiDB-Ansible If you have not deployed the Kafka cluster, use the Kafka-Ansible to deploy. When you deploy the TiDB cluster using TiDB-Ansible, edit the tidb-ansible/inventory.ini file, set enable_binlog = True, and configure the zookeeper_addrs variable as the ZooKeeper address of the Kafka cluster. In this way, Pump is deployed while you deploy the TiDB cluster. Configuration example:# binlog trigger enable_binlog = True # ZooKeeper address of the Kafka cluster. Example: # zookeeper_addrs = "192.168.0.11:2181,192.168.0.12:2181,192.168.0.13:2181" # You can also append an optional chroot string to the URLs to specify the root directory for all Kafka znodes. Example: # zookeeper_addrs = "192.168.0.11:2181,192.168.0.12:2181,192.168.0.13:2181/kafka/123" zookeeper_addrs = "192.168.0.11:2181,192.168.0.12:2181,192.168.0.13:2181" Deploy Pump using Binary A usage example:Assume that we have three PDs, three ZooKeepers, and one TiDB. The information of each node is as follows:TiDB="192.168.0.10" PD1="192.168.0.16" PD2="192.168.0.15" PD3="192.168.0.14" ZK1="192.168.0.13" ZK2="192.168.0.12" ZK3="192.168.0.11" Deploy Drainer/Pump on the machine with the IP address “192.168.0.10”.The IP address of the corresponding PD cluster is “192.168.0.16,192.168.0.15,192.168.0.14”.The ZooKeeper IP address of the corresponding Kafka cluster is “192.168.0.13,192.168.0.12,192.168.0.11”.This example describes how to use Pump/Drainer. Description of Pump command line optionsUsage of Pump: -L string log level: debug, info, warn, error, fatal (default "info") -V to print Pump version info -addr string the RPC address that Pump provides service (-addr= "192.168.0.10:8250") -advertise-addr string the RPC address that Pump provides external service (-advertise-addr="192.168.0.10:8250") -config string to configure the file path of Pump; if you specifies the configuration file, Pump reads the configuration first; if the corresponding configuration also exists in the command line argument, Pump uses the command line configuration to cover that in the configuration file -data-dir string the path of storing Pump data -enable-tolerant after enabling tolerant, Pump wouldn't return error if it fails to write binlog (default true) -zookeeper-addrs string (-zookeeper_addrs="192.168.0.11:2181,192.168.0.12:2181,192.168.0.13:2181") the ZooKeeper address; this option gets the Kafka address from ZooKeeper, and you need to keep it the same with the configuration in Kafka -gc int the maximum days that the binlog is retained (default 7), and 0 means retaining the binlog permanently -heartbeat-interval int the interval between heartbeats that Pump sends to PD (unit: second) -log-file string the path of the log file -log-rotate string the log file rotating frequency (hour/day) -metrics-addr string the Prometheus pushgateway address; leaving it empty disables Prometheus push -metrics-interval int the frequency of reporting monitoring information (default 15, unit: second) -pd-urls string the node address of the PD cluster …"}, {"url": "https://pingcap.com/docs/v2.0/tools/tidb-binlog/", "title": "TiDB-Binlog user guide", "content": " TiDB-Binlog User Guide About TiDB-Binlog TiDB-Binlog is a tool for enterprise users to collect binlog files for TiDB and provide real-time backup and synchronization.TiDB-Binlog supports the following scenarios: Data synchronization: to synchronize TiDB cluster data to other databases Real-time backup and recovery: to back up TiDB cluster data, and recover in case of cluster outages TiDB-Binlog architecture The TiDB-Binlog architecture is as follows:The TiDB-Binlog cluster mainly consists of two components:Pump Pump is a daemon that runs on the background of each TiDB host. Its main function is to record the binlog files generated by TiDB in real time and write to the file in the disk sequentially.Drainer Drainer collects binlog files from each Pump node, converts them into specified database-compatible SQL statements in the commit order of the transactions in TiDB, and synchronizes to the target database or writes to the file sequentially.Install TiDB-Binlog Download Binary for the CentOS 7.3+ platform # Download the tool package. wget http://download.pingcap.org/tidb-binlog-latest-linux-amd64.tar.gz wget http://download.pingcap.org/tidb-binlog-latest-linux-amd64.sha256 # Check the file integrity. If the result is OK, the file is correct. sha256sum -c tidb-binlog-latest-linux-amd64.sha256 # Extract the package. tar -xzf tidb-binlog-latest-linux-amd64.tar.gz cd tidb-binlog-latest-linux-amd64 Deploy TiDB-Binlog It is recommended to deploy Pump using Ansible. Build a new TiDB cluster with a startup order of pd-server -> tikv-server -> pump -> tidb-server -> drainer. Edit the tidb-ansible inventory.ini file:enable_binlog = True Run ansible-playbook deploy.yml Run ansible-playbook start.yml Deploy Binlog for an existing TiDB cluster. Edit the tidb-ansible inventory.ini file:enable_binlog = True Run ansible-playbook rolling_update.yml Note You need to deploy a Pump for each TiDB server in a TiDB cluster. Currently, the TiDB server only supports the binlog in UNIX socket. We set the startup parameter binlog-socket as the specified unix socket file path of the corresponding parameter socket in Pump. The final deployment architecture is as follows: Currently, you need to deploy Drainer manually. Drainer does not support renaming DDL on the table of the ignored schemas (schemas in the filter list). To start Drainer in the existing TiDB cluster, usually you need to do a full backup, get the savepoint, import the full backup, and start Drainer and synchronize from the savepoint. To guarantee the integrity of data, perform the following operations 10 minutes after Pump is started: Run Drainer at the gen-savepoint model and generate the Drainer savepoint file:bin/drainer -gen-savepoint --data-dir= ${drainer_savepoint_dir} --pd-urls=${pd_urls} Do a full backup. For example, back up TiDB using mydumper. Import the full backup to the target system. Set the file path of the savepoint and start Drainer:bin/drainer --config=conf/drainer.toml --data-dir=${drainer_savepoint_dir} The drainer outputs pb and you need to set the following parameters in the configuration file.[syncer] db-type = "pb" disable-dispatch = true [syncer.to] dir = "/path/pb-dir" Examples and parameters explanation Pump Example./bin/pump -config pump.toml Parameters ExplanationUsage of Pump: -L string log level: debug, info, warn, error, fatal (default "info") -V print Pump version info -addr string addr(i.e. 'host:port') to listen on for client traffic (default "127.0.0.1:8250"). -advertise-addr string addr(i.e. 'host:port') to advertise to the public -config string path to the Pump configuration file -data-dir string path to store binlog data -gc int recycle binlog files older than gc days, zero means never recycle (default 7) -heartbeat-interval int number of seconds between heartbeat ticks (default 2) -log-file string log file path -log-rotate string log file rotate type, hour/day -metrics-addr string Prometheus pushgataway address; leaving it empty will disable Prometheus push -metrics-interval int Prometheus client push interval in second, set "0" to disable Prometheus push (default 15) -pd-urls string a comma separated list of the PD endpoints (default "http://127.0.0.1:2379") -socket string unix socket addr to listen on for client traffic Configuration file# Pump Configuration. # addr(i.e. 'host:port') to listen on for client traffic addr = "127.0.0.1:8250" # addr(i.e. 'host:port') to advertise to the public advertise-addr = "" # a integer value to control expiry date of the binlog data, indicates for how long (in days) the binlog data would be stored. # (default value is 0, means binlog data would never be removed) gc = 7 # path to the data directory of Pump's data data-dir = "data.pump" # number of seconds between heartbeat ticks (in 2 seconds) heartbeat-interval = 2 # a comma separated list of PD endpoints pd-urls = "http://127.0.0.1:2379" # unix socket addr to listen on for client traffic socket = "unix:///tmp/pump.sock" Drainer Example./bin/drainer -config drainer.toml Parameters ExplanationUsage of Drainer: -L string log level: debug, info, warn, error, fatal (default "info") -V print version info -addr string addr (i.e. 'host:port') to listen on for Drainer connections (default "127.0.0.1:8249") -c int parallel worker count (default 1) -config string path to the configuration file -data-dir string Drainer data directory path (default data.drainer) (default "data.drainer") -dest-db-type string target db type: mysql or pb; see syncer section in conf/drainer.toml (default "mysql") -detect-interval int the interval time (in seconds) of detecting Pumps' status (default 10) -disable-dispatch disable dispatching sqls that in one same binlog; if set true, work-count and txn-batch would be useless -gen-savepoint generate the savepoint from cluster -ignore-schemas string disable synchronizing those schemas (default "INFORMATION_SCHEMA,PERFORMANCE_SCHEMA,mysql") -log-file string log file path -log-rotate string log file rotate type, hour/day -metrics-addr string Prometheus pushgateway address; leaving it empty will disable Prometheus push -metrics-interval int Prometheus client push interval in second, set "0" to disable Prometheus push (default 15) -pd-urls string a comma separated list of PD endpoints (default "http://127.0.0.1:2379") -txn-batch int number of binlog events in a transaction batch (default 1) Configuration file# Drainer Configuration # addr (i.e. 'host:port') to listen on for Drainer connections addr = "127.0.0.1:8249" # the interval time (in seconds) of detect Pumps' status detect-interval = 10 # Drainer meta data directory path data-dir = "data.drainer" # a comma separated list of PD endpoints pd-urls = "http://127.0.0.1:2379" # The file path of log log-file = "drainer.log" # syncer Configuration [syncer] # disable synchronizing these schemas ignore-schemas = "INFORMATION_SCHEMA,PERFORMANCE_SCHEMA,mysql" # number of binlog events in a transaction batc txn-batch = 1 # worker count to execute binlogs worker-count = 1 disable-dispatch = false # downstream storage, equal to --dest-db-type # valid values are "mysql", "pb" db-type = "mysql" # The replicate-do-db prioritizes over replicate-do-table if having the same db name. # Regular expressions are supported, and starting with '~' declares the use of regular expressions. # replicate-do-db = ["~^b.*","s1"] # [[syncer.replicate-do-table]] # db-name ="test" # tbl-name = "log" # [[syncer.replicate-do-table]] # db-name ="test" # tbl-name = "~^a.*" # the downstream mysql protocol database [syncer.to] host = "127.0.0.1" user = "root" password = "" port = 3306 # uncomment …"}, {"url": "https://pingcap.com/docs-cn/tools/tidb-binlog-monitor/", "title": "TiDB-Binlog 监控指标说明", "content": " TiDB-Binlog 监控指标及告警说明 本文档介绍 Grafana 中 TiDB-Binlog 的各项监控指标说明,以及报警规则说明。监控指标 Pump Storage Size 记录磁盘的总空间大小 (capacity),以及可用磁盘空间大小 (available)。 Metadata 记录每个 Pump 的可删除 binlog 的最大 tso (gc_tso),以及保存的 binlog 的最大的 commit tso (max_commit_tso)。 Write Binlog QPS by Instance 每个 Pump 接收到的写 binlog 请求的 QPS。 Write Binlog Latency 记录每个 Pump 写 binlog 的延迟时间。 Storage Write Binlog Size Pump 写 binlog 数据的大小。 Storage Write Binlog Latency Pump 中的 storage 模块写 binlog 数据的延迟。 Pump Storage Error By Type Pump 遇到的 error 数量,按照 error 的类型进行统计。 Query TiKV Pump 通过 TiKV 查询事务状态的次数。 Drainer Checkpoint TSO Drainer 已经同步到下游的 binlog 的最大 TSO 对应的时间。可以通过该指标估算同步延迟时间。 Pump Handle TSO 记录 Drainer 从各个 Pump 获取到的 binlog 的最大 TSO 对应的时间。 Pull Binlog QPS by Pump NodeID Drainer 从每个 Pump 获取 binlog 的 QPS。 95% Binlog Reach Duration By Pump 记录 binlog 从写入 Pump 到被 Drainer 获取到这个过程的延迟时间。 Error By Type Drainer 遇到的 error 数量,按照 error 的类型进行统计。 Drainer Event 各种类型 event 的数量,event 包括 ddl、insert、delete、update、flush、savepoint。 Execute Time 在下游执行 SQL/写数据所消耗的时间。 95% Binlog Size Drainer 从各个 Pump 获取到 binlog 数据的大小。 DDL Job Count Drainer 处理的 DDL 的数量。 监控告警规则 目前对 TiDB-Binlog 中一些比较重要的方面配置了监控,根据指标的重要程度分为 Emergency、Critical 和 Warning 三种级别。Emergency binlog_pump_storage_error_count 含义:Pump 写 binlog 到本地存储时失败 监控规则:changes(binlog_pump_storage_error_count[1m]) > 0 处理方法:先确认 pump_storage_error 监控是否存在错误,查看 Pump 日志确认原因 Critical binlog_drainer_checkpoint_high_delay 含义:Drainer 同步落后延迟超过 1 个小时 监控规则:(time() - binlog_drainer_checkpoint_tso / 1000) > 3600 处理方法: 判断从 Pump 获取数据是否太慢:监控 Pump handle tso 可以看每个 Pump 最近一条消息的时间,是不是有延迟特别大的 Pump,确认对应 Pump 正常运行 根据 Drainer event 和 Drainer execute latency 来判断是否下游同步太慢: 如果 Drainer execute time 过大,则检查到目标库网络带宽和延迟,以及目标库状态 如果 Drainer execute time 不大,Drainer event 过小,则增加 work count 和 batch 进行重试 上面都不满足或者操作后没有改观,则报备开发 support@pingcap.com 进行处理 Warning binlog_pump_write_binlog_rpc_duration_seconds_bucket 含义:Pump 处理 TiDB 写 Binlog 请求耗时过大 监控规则:histogram_quantile(0.9, rate(binlog_pump_rpc_duration_seconds_bucket{method=“WriteBinlog”}[5m])) > 1 处理方法: 确认磁盘性能压力,通过 node exported 查看 disk performance 监控 如果 disk latency 和 util 都很低,那么报备研发 support@pingcap.com 处理 binlog_pump_storage_write_binlog_duration_time_bucket 含义:Pump 写本地 binlog 到本地盘的耗时 监控规则:histogram_quantile(0.9, rate(binlog_pump_storage_write_binlog_duration_time_bucket{type=“batch”}[5m])) > 1 处理方法:确认 Pump 本地盘情况,进行修复 binlog_pump_storage_available_size_less_than_20G 含义:Pump 剩余可用磁盘空间不足 20G 监控规则:binlog_pump_storage_storage_size_bytes{type=“available”} < 20 * 1024 * 1024 * 1024 处理方法:监控确认 Pump gc_tso 正常,需要的话调整 Pump gc 时间配置或者下线对应 Pump binlog_drainer_checkpoint_tso_no_change_for_1m 含义:Drainer checkpoint 一分钟没有更新 监控规则:changes(binlog_drainer_checkpoint_tso[1m]) < 1 处理方法:确认是否所有非下线 Pump 正常运行 binlog_drainer_execute_duration_time_more_than_10s 含义:Drainer 同步到 TiDB 的 transaction 耗时;如果过大则影响 Drainer 同步 监控规则:histogram_quantile(0.9, rate(binlog_drainer_execute_duration_time_bucket[1m])) > 10 处理方法: 查看 TiDB cluster 状态情况 查看 Drainer 日志或监控,如果是 DDL 则忽略 "}, {"url": "https://pingcap.com/docs-cn/tools/tidb-binlog-kafka/", "title": "TiDB-Binlog 部署方案", "content": " TiDB-Binlog 部署方案 本文档介绍如何部署 Kafka 版本的 TiDB-Binlog。TiDB-Binlog 简介 TiDB-Binlog 用于收集 TiDB 的 Binlog,并提供实时备份和同步功能的商业工具。TiDB-Binlog 支持以下功能场景: 数据同步:同步 TiDB 集群数据到其他数据库 实时备份和恢复:备份 TiDB 集群数据,同时可以用于 TiDB 集群故障时恢复 TiDB-Binlog 架构 首先介绍 TiDB-Binlog 的整体架构。TiDB-Binlog 集群主要分为三个组件:Pump Pump 是一个守护进程,在每个 TiDB 主机的后台运行。其主要功能是实时记录 TiDB 产生的 Binlog 并顺序写入 Kafka 中。Drainer Drainer 从 Kafka 中收集 Binlog,并按照 TiDB 中事务的提交顺序转化为指定数据库兼容的 SQL 语句,最后同步到目的数据库或者写到顺序文件。Kafka & ZooKeeper Kafka 集群用来存储由 Pump 写入的 Binlog 数据,并提供给 Drainer 进行读取。 注:local 版本将 Binlog 存储在文件中,最新版本则使用 Kafka 存储。 TiDB-Binlog 安装 以下为 TiDB-Ansible 分支与 TiDB 版本的对应关系,版本选择可咨询官方 info@pingcap.com。| TiDB-Ansible 分支 | TiDB 版本 | 备注 | | ---------------- | --------- | --- | | release-2.0 | 2.0 版本 | 最新 2.0 稳定版本,可用于生产环境。 | 下载官方 Binary CentOS 7+# 下载压缩包 wget http://download.pingcap.org/tidb-binlog-kafka-linux-amd64.tar.gz wget http://download.pingcap.org/tidb-binlog-kafka-linux-amd64.sha256 # 检查文件完整性,返回 ok 则正确 sha256sum -c tidb-binlog-kafka-linux-amd64.sha256 # 解开压缩包 tar -xzf tidb-binlog-kafka-linux-amd64.tar.gz cd tidb-binlog-kafka-linux-amd64 TiDB-Binlog 部署 注意 需要为一个 TiDB 集群中的每台 TiDB server 部署一个 Pump,目前 TiDB server 只支持以 unix socket 的方式输出 Binlog。 手动部署时,启动优先级为:Pump > TiDB;停止优先级为 TiDB > Pump。设置 TiDB 启动参数 binlog-socket 为对应的 Pump 参数 socket 所指定的 unix socket 文件路径,最终部署结构如下图所示: Drainer 不支持对 ignore schemas(在过滤列表中的 schemas)的 table 进行 rename DDL 操作。 在已有的 TiDB 集群中启动 Drainer,一般需要全量备份并且获取 savepoint,然后导入全量备份,最后启动 Drainer 从 savepoint 开始同步;为了保证数据的完整性,在 Pump 运行 10 分钟左右后按顺序进行如下操作: 使用 tidb-tools 项目中的 binlogctl 工具生成 Drainer 初次启动所需的 position 全量备份,例如 mydumper 备份 TiDB 全量导入备份到目标系统 Kafka 版本 Drainer 启动的 savepoint 默认保存在下游 database tidb_binlog 下的 checkpoint 表中,如果 checkpoint 表中没有效的数据,可以通过设置 initial-commit-ts 启动 Drainer 从指定位置开始消费 - bin/drainer --config=conf/drainer.toml --initial-commit-ts=${position} Drainer 输出为 pb,要在配置文件中设置如下参数:[syncer] db-type = "pb" disable-dispatch = true [syncer.to] dir = "/path/pb-dir" Drainer 输出为 kafka,要在配置文件中设置如下参数:[syncer] db-type = "kafka" # when db-type is kafka, you can uncomment this to config the down stream kafka, or it will be the same kafka addrs where drainer pull binlog from. #[syncer.to] # kafka-addrs = "127.0.0.1:9092" # kafka-version = "0.8.2.0" 输出到 kafka 的数据为按 ts 排好序的 protobuf 定义 binlog 格式,可以参考 driver 获取数据同步到下游。 Kafka 和 ZooKeeper 集群需要在部署 TiDB-Binlog 之前部署好。Kafka 需要 0.9 及以上版本。 Kafka 集群配置推荐 名字 数量 内存 CPU 硬盘 Kafka 3+ 16G 8+ 2+ 1TB ZooKeeper 3+ 8G 4+ 2+ 300G Kafka 配置参数推荐 auto.create.topics.enable = true:如果还没有创建 topic,Kafka 会在 broker 上自动创建 topic broker.id:用来标识 Kafka 集群的必备参数,不能重复;如 broker.id = 1 fs.file-max = 1000000:Kafka 会使用大量文件和网络 socket,建议修改成 1000000,通过 vi /etc/sysctl.conf 进行修改 修改以下配置为1G, 否则很容易出现事务修改数据较多导致单个消息过大写 kafka 失败 message.max.bytes=1073741824 replica.fetch.max.bytes=1073741824 fetch.message.max.bytes=1073741824 使用 tidb-ansible 部署 Pump 如无 Kafka 集群,可使用 kafka-ansible 部署 Kafka 集群。 使用 tidb-ansible 部署 TiDB 集群时,修改 tidb-ansible/inventory.ini 文件,设置 enable_binlog = True,并配置 zookeeper_addrs 变量为 Kafka 集群的 ZooKeeper 地址,这样部署 TiDB 集群时会部署 Pump。 配置样例:# binlog trigger enable_binlog = True # ZooKeeper address of Kafka cluster, example: # zookeeper_addrs = "192.168.0.11:2181,192.168.0.12:2181,192.168.0.13:2181" # You can also append an optional chroot string to the URLs to specify the root directory for all Kafka znodes, example: # zookeeper_addrs = "192.168.0.11:2181,192.168.0.12:2181,192.168.0.13:2181/kafka/123" zookeeper_addrs = "192.168.0.11:2181,192.168.0.12:2181,192.168.0.13:2181" 使用 Binary 部署 Pump 使用样例:假设我们有三个 PD,三个 ZooKeeper,一个 TiDB,各个节点信息如下:TiDB="192.168.0.10" PD1="192.168.0.16" PD2="192.168.0.15" PD3="192.168.0.14" ZK1="192.168.0.13" ZK2="192.168.0.12" ZK3="192.168.0.11" 在 ip=“192.168.0.10” 的机器上面部署 Drainer/Pump;对应的 PD 集群的 ip=“192.168.0.16,192.168.0.15,192.168.0.14”;对应的 Kafka 集群的 ZooKeeper 的 ip=“192.168.0.13,192.168.0.12,192.168.0.11”。以此为例,说明 Pump/Drainer 的使用。 Pump 命令行参数说明Usage of Pump: -L string 日志输出信息等级设置: debug, info, warn, error, fatal (默认 "info") -V 打印版本信息 -addr string Pump 提供服务的 RPC 地址(-addr="192.168.0.10:8250") -advertise-addr string Pump 对外提供服务的 RPC 地址(-advertise-addr="192.168.0.10:8250") -config string 配置文件路径,如果你指定了配置文件,Pump 会首先读取配置文件的配置; 如果对应的配置在命令行参数里面也存在,Pump 就会使用命令行参数的配置来覆盖配置文件里面的。 -data-dir string Pump 数据存储位置路径 -enable-tolerant 开启 tolerant 后,如果 binlog 写入失败,Pump 不会报错(默认开启) -zookeeper-addrs string (-zookeeper_addrs = "192.168.0.11:2181,192.168.0.12:2181,192.168.0.13:2181") ZooKeeper 地址,该选项从 ZooKeeper 中获取 Kafka 地址,需要和 Kafka 中配置相同 -gc int 日志最大保留天数 (默认 7),设置为 0 可永久保存 -heartbeat-interval int Pump 向 PD 发送心跳间隔 (单位 秒) -log-file string log 文件路径 -log-rotate string log 文件切换频率,hour/day -metrics-addr string Prometheus pushgateway 地址,不设置则禁止上报监控信息 -metrics-interval int 监控信息上报频率 (默认 15,单位 秒) -pd-urls string PD 集群节点的地址 (-pd-urls="http://192.168.0.16:2379,http://192.168.0.15:2379,http://192.168.0.14:2379") -socket string unix socket 模式服务监听地址(默认 unix:///tmp/pump.sock) Pump 配置文件# Pump Configuration. # Pump 提供服务的 RPC 地址("192.168.0.10:8250") addr = "192.168.0.10:8250" # Pump 对外提供服务的 RPC 地址("192.168.0.10:8250") advertise-addr = "" # binlog 最大保留天数 (默认 7),设置为 0 可永久保存 gc = 7 # Pump 数据存储位置路径 data-dir = "data.pump" # ZooKeeper 地址,该选项从 ZooKeeper 中获取 Kafka 地址,若 Kafka 中配置了命名空间,则此处需同样配置 # zookeeper-addrs = "192.168.0.11:2181,192.168.0.12:2181,192.168.0.13:2181" # 配置了命令空间的 ZooKeeper 地址配置示例 # zookeeper-addrs = "192.168.0.11:2181,192.168.0.12:2181,192.168.0.13:2181/kafka/123" # Pump 向 PD 发送心跳的间隔 (单位 秒) heartbeat-interval = 3 # PD 集群节点的地址 pd-urls = "http://192.168.0.16:2379,http://192.168.0.15:2379,http://192.168.0.14:2379" # unix socket 模式服务监听地址 (默认 unix:///tmp/pump.sock) socket = "unix:///tmp/pump.sock" 启动示例./bin/pump -config pump.toml 使用 Binary 部署 Drainer Drainer 命令行参数说明Usage of Drainer: -L string 日志输出信息等级设置:debug, info, warn, error, fatal (默认 "info") -V 打印版本信息 -addr string Drainer 提供服务的地址(-addr="192.168.0.10:8249") -c int 同步下游的并发数,该值设置越高同步的吞吐性能越好 (default 1) -config string 配置文件路径,Drainer 会首先读取配置文件的配置; 如果对应的配置在命令行参数里面也存在,Drainer 就会使用命令行参数的配置来覆盖配置文件里面的 -data-dir string Drainer 数据存储位置路径 (默认 "data.drainer") -zookeeper-addrs string (-zookeeper-addrs="192.168.0.11:2181,192.168.0.12:2181,192.168.0.13:2181") ZooKeeper 地址,该选项从 ZooKeeper 中获取 Kafka 地址,需要和 Kafka 中配置相同 -dest-db-type string Drainer 下游服务类型 (默认为 mysql) -detect-interval int 向 PD 查询在线 Pump 的时间间隔 (默认 10,单位 秒) -disable-dispatch 是否禁用拆分单个 binlog 的 sqls 的功能,如果设置为 true,则按照每个 binlog 顺序依次还原成单个事务进行同步(下游服务类型为 mysql,该项设置为 False) -ignore-schemas string db 过滤列表 (默认 "INFORMATION_SCHEMA,PERFORMANCE_SCHEMA,mysql,test"), 不支持对 ignore schemas 的 table 进行 rename DDL 操作 -initial-commit-ts (默认为 0) 如果 Drainer 没有相关的断点信息,可以通过该项来设置相关的断点信息 -log-file string log 文件路径 -log-rotate string log 文件切换频率,hour/day -metrics-addr string Prometheus pushgateway 地址,不设置则禁止上报监控信息 -metrics-interval int 监控信息上报频率(默认 15,单位 秒) -pd-urls string PD 集群节点的地址 (-pd-urls="http://192.168.0.16:2379,http://192.168.0.15:2379,http://192.168.0.14:2379") -txn-batch int 输出到下游数据库一个事务的 SQL 数量(默认 1) Drainer 配置文件# Drainer Configuration. # Drainer 提供服务的地址("192.168.0.10:8249") addr = "192.168.0.10:8249" # 向 PD 查询在线 Pump 的时间间隔 (默认 10,单位 秒) detect-interval = 10 # Drainer 数据存储位置路径 (默认 "data.drainer") data-dir = "data.drainer" # ZooKeeper 地址,该选项从 ZooKeeper 中获取 Kafka 地址,若 Kafka 中配置了命名空间,则此处需同样配置 # zookeeper-addrs = "192.168.0.11:2181,192.168.0.12:2181,192.168.0.13:2181" # 配置了命令空间的 ZooKeeper 地址配置示例 # zookeeper-addrs = "192.168.0.11:2181,192.168.0.12:2181,192.168.0.13:2181/kafka/123" # PD 集群节点的地址 pd-urls = "http://192.168.0.16:2379,http://192.168.0.15:2379,http://192.168.0.14:2379" # log 文件路径 log-file = "drainer.log" # Syncer Configuration. [syncer] ## db 过滤列表 ( …"}, {"url": "https://pingcap.com/docs-cn/tools/tidb-binlog/", "title": "TiDB-Binlog 部署方案", "content": " TiDB-Binlog 部署方案 TiDB-Binlog 简介 TiDB-Binlog 用于收集 TiDB 的 Binlog,并提供实时备份和同步功能的商业工具。TiDB-Binlog 支持以下功能场景: 数据同步:同步 TiDB 集群数据到其他数据库。 实时备份和恢复:备份 TiDB 集群数据,同时可以用于 TiDB 集群故障时恢复。 TiDB-Binlog 架构 首先介绍 TiDB-Binlog 的整体架构。TiDB-Binlog 集群主要分为两个组件:Pump Pump 是一个守护进程,在每个 TiDB 的主机上后台运行。他的主要功能是实时记录 TiDB 产生的 Binlog 并顺序写入磁盘文件Drainer Drainer 从各个 Pump 节点收集 Binlog,并按照在 TiDB 中事务的提交顺序转化为指定数据库兼容的 SQL 语句,最后同步到目的数据库或者写到顺序文件TiDB-Binlog 安装 下载官方 Binary CentOS 7+# 下载压缩包 wget http://download.pingcap.org/tidb-binlog-local-linux-amd64.tar.gz wget http://download.pingcap.org/tidb-binlog-local-linux-amd64.sha256 # 检查文件完整性,返回 ok 则正确 sha256sum -c tidb-binlog-local-linux-amd64.sha256 # 解开压缩包 tar -xzf tidb-binlog-local-linux-amd64.tar.gz cd tidb-binlog-local-linux-amd64 TiDB-Binlog 部署 注意 需要为一个 TiDB 集群中的每台 TiDB server 部署一个 Pump,目前 TiDB server 只支持以 unix socket 方式的输出 binlog。 手动部署时, 启动优先级为: Pump > TiDB ; 停止优先级为 TiDB > Pump我们设置 TiDB 启动参数 binlog-socket 为对应的 Pump 的参数 socket 所指定的 unix socket 文件路径,最终部署结构如下图所示: drainer 不支持对 ignore schemas(在过滤列表中的 schemas) 的 table 进行 rename DDL 操作 在已有的 TiDB 集群中启动 drainer,一般需要全量备份 并且获取 savepoint,然后导入全量备份,最后启动 drainer 从 savepoint 开始同步;为了保证数据的完整性,在 pump 运行 10 分钟左右后按顺序进行下面的操作 以 gen-savepoint model 运行 drainer 生成 drainer savepint 文件,bin/drainer -gen-savepoint --data-dir= ${drainer_savepoint_dir} --pd-urls=${pd_urls} 全量备份,例如 mydumper 备份 tidb 全量导入备份到目标系统 设置 savepoint 文件路径,然后启动 drainer,bin/drainer --config=conf/drainer.toml --data-dir=${drainer_savepoint_dir} drainer 输出的 pb, 需要在配置文件设置下面的参数[syncer] db-type = "pb" disable-dispatch = true [syncer.to] dir = "/path/pb-dir" 使用 tidb-ansible 部署 PUMP (推荐) 搭建全新的 TiDB Cluster,启动顺序 pd-server -> tikv-server -> pump -> tidb-server -> drainer 修改 tidb-ansible inventory.ini 文件 enable_binlog = True 执行 ansible-playbook deploy.yml 执行 ansible-playbook start.yml drainer 目前需要手动部署 对已有的 TiDB Cluster 部署 binlog 修改 tidb-ansible inventory.ini 文件 enable_binlog = True 执行 ansible-playbook rolling_update.yml –tags=tidb drainer 目前需要手动部署 使用 Binary 部署 PUMP PUMP 命令行参数说明Usage of pump: -L string 日志输出信息等级设置: debug, info, warn, error, fatal (默认 "info") -V 打印版本信息 -addr string pump 提供服务的 rpc 地址(默认 "127.0.0.1:8250") -advertise-addr string pump 对外提供服务的 rpc 地址(默认 "127.0.0.1:8250") -config string 配置文件路径,如果你指定了配置文件,pump 会首先读取配置文件的配置 如果对应的配置在命令行参数里面也存在,pump 就会使用命令行参数的配置来覆盖配置文件里面的 -data-dir string pump 数据存储位置路径 -gc int 日志最大保留天数 (默认 7), 设置为 0 可永久保存 -heartbeat-interval uint pump 向 pd 发送心跳间隔 (单位 秒) -log-file string log 文件路径 -log-rotate string log 文件切换频率, hour/day -metrics-addr string prometheus Pushgateway 地址,不设置则禁止上报监控信息 -metrics-interval int 监控信息上报频率 (默认 15,单位 秒) -pd-urls string pd 集群节点的地址 (默认 "http://127.0.0.1:2379") -socket string unix socket 模式服务监听地址 (默认 unix:///tmp/pump.sock) PUMP 配置文件 # pump Configuration. # pump 提供服务的 rpc 地址(默认 "127.0.0.1:8250") addr = "127.0.0.1:8250" # pump 对外提供服务的 rpc 地址(默认 "127.0.0.1:8250") advertise-addr = "" # binlog 最大保留天数 (默认 7), 设置为 0 可永久保存 gc = 7 # pump 数据存储位置路径 data-dir = "data.pump" # pump 向 pd 发送心跳间隔 (单位 秒) heartbeat-interval = 3 # pd 集群节点的地址 (默认 "http://127.0.0.1:2379") pd-urls = "http://127.0.0.1:2379" # unix socket 模式服务监听地址 (默认 unix:///tmp/pump.sock) socket = "unix:///tmp/pump.sock" 启动示例./bin/pump -config pump.toml 使用 Binary 部署 Drainer Drainer 命令行参数说明Usage of drainer: -L string 日志输出信息等级设置: debug, info, warn, error, fatal (默认 "info") -V 打印版本信息 -addr string drainer 提供服务的地址(默认 "127.0.0.1:8249") -c int 同步下游的并发数,该值设置越高同步的吞吐性能越好 (default 1) -config string 配置文件路径, drainer 会首先读取配置文件的配置 如果对应的配置在命令行参数里面也存在,drainer 就会使用命令行参数的配置来覆盖配置文件里面的 -data-dir string drainer 数据存储位置路径 (默认 "data.drainer") -dest-db-type string drainer 下游服务类型 (默认为 mysql) -detect-interval int 向 pd 查询在线 Pump 的时间间隔 (默认 10,单位 秒) -disable-dispatch 是否禁用拆分单个 binlog 的 sqls 的功能,如果设置为 true,则按照每个 binlog 顺序依次还原成单个事务进行同步( 下游服务类型为 mysql, 该项设置为 False ) -gen-savepoint 如果设置为 true, 则只生成 drainer 的 savepoint meta 文件, 可以配合 mydumper 使用 -ignore-schemas string db 过滤列表 (默认 "INFORMATION_SCHEMA,PERFORMANCE_SCHEMA,mysql,test"), 不支持对 ignore schemas 的 table 进行 rename DDL 操作 -log-file string log 文件路径 -log-rotate string log 文件切换频率, hour/day -metrics-addr string Prometheus Pushgateway 地址,不设置则禁止上报监控信息 -metrics-interval int 监控信息上报频率 (默认 15,单位 秒) -pd-urls string pd 集群节点的地址 (默认 "http://127.0.0.1:2379") -txn-batch int 输出到下游数据库一个事务的 sql 数量 (default 1) Drainer 配置文件# drainer Configuration. # drainer 提供服务的地址(默认 "127.0.0.1:8249") addr = "127.0.0.1:8249" # 向 pd 查询在线 pump 的时间间隔 (默认 10,单位 秒) detect-interval = 10 # drainer 数据存储位置路径 (默认 "data.drainer") data-dir = "data.drainer" # pd 集群节点的地址 (默认 "http://127.0.0.1:2379") pd-urls = "http://127.0.0.1:2379" # log 文件路径 log-file = "drainer.log" # Syncer Configuration. [syncer] ## db 过滤列表 (默认 "INFORMATION_SCHEMA,PERFORMANCE_SCHEMA,mysql,test"), ## 不支持对 ignore schemas 的 table 进行 rename DDL 操作 ignore-schemas = "INFORMATION_SCHEMA,PERFORMANCE_SCHEMA,mysql" # 输出到下游数据库一个事务的 sql 数量 (default 1) txn-batch = 1 # 同步下游的并发数,该值设置越高同步的吞吐性能越好 (default 1) worker-count = 1 # 是否禁用拆分单个 binlog 的 sqls 的功能,如果设置为 true,则按照每个 binlog # 顺序依次还原成单个事务进行同步( 下游服务类型为 mysql, 该项设置为 False ) disable-dispatch = false # drainer 下游服务类型 (默认为 mysql) # 参数有效值为 "mysql", "pb" db-type = "mysql" # replicate-do-db priority over replicate-do-table if have same db name # and we support regex expression , # 以 '~' 开始声明使用正则表达式 #replicate-do-db = ["~^b.*","s1"] #[[syncer.replicate-do-table]] #db-name ="test" #tbl-name = "log" #[[syncer.replicate-do-table]] #db-name ="test" #tbl-name = "~^a.*" # db-type 设置为 mysql 时,下游数据库服务器参数 [syncer.to] host = "127.0.0.1" user = "root" password = "" port = 3306 # db-type 设置为 pb 时,存放 binlog 文件的目录 # [syncer.to] # dir = "data.drainer" 启动示例./bin/drainer -config drainer.toml TiDB-Binlog 监控 这部分主要对 TiDB-Binlog 的状态、性能做监控,通过 Prometheus + Grafana 展现 metrics 数据,pump/drainer 配置 使用 ansible 部署的 pump 服务,已经在启动参数设置 metrics 。drainer 启动时可以设置 --metrics-addr 和 --metrics-interval 两个参数,其中 metrics-addr 设为 Push Gateway 的地址,metrics-interval 为 push 的频率,单位为秒,默认值为15Grafana 配置 进入 Grafana Web 界面(默认地址: http://localhost:3000,默认账号: admin 密码: admin)点击 Grafana Logo -> 点击 Data Sources -> 点击 Add data source -> 填写 data source 信息 ( 注: Type 选 Prometheus,Url 为 Prometheus 地址,根据实际情况 添加/填写 ) 导入 dashboard 配置文件点击 Grafana Logo -> 点击 Dashboards -> 点击 Import -> 选择需要的 dashboard 配置文件上传 -> 选择对应的 data source "}, {"url": "https://pingcap.com/docs-cn/v1.0/tools/tidb-binlog-kafka/", "title": "TiDB-Binlog 部署方案", "content": " TiDB-Binlog 部署方案 本文档介绍如何部署 Kafka 版本的 TiDB-Binlog。如需部署 local 版本的 TiDB-Binlog,可参考 local 版本的 TiDB-Binlog 部署文档。TiDB-Binlog 简介 TiDB-Binlog 用于收集 TiDB 的 Binlog,并提供实时备份和同步功能的商业工具。TiDB-Binlog 支持以下功能场景: 数据同步:同步 TiDB 集群数据到其他数据库 实时备份和恢复:备份 TiDB 集群数据,同时可以用于 TiDB 集群故障时恢复 TiDB-Binlog 架构 首先介绍 TiDB-Binlog 的整体架构。TiDB-Binlog 集群主要分为三个组件:Pump Pump 是一个守护进程,在每个 TiDB 主机的后台运行。其主要功能是实时记录 TiDB 产生的 Binlog 并顺序写入 Kafka 中。Drainer Drainer 从 Kafka 中收集 Binlog,并按照 TiDB 中事务的提交顺序转化为指定数据库兼容的 SQL 语句,最后同步到目的数据库或者写到顺序文件。Kafka & ZooKeeper Kafka 集群用来存储由 Pump 写入的 Binlog 数据,并提供给 Drainer 进行读取。 注:local 版本将 Binlog 存储在文件中,最新版本则使用 Kafka 存储。 TiDB-Binlog 安装 下载官方 Binary CentOS 7+# 下载压缩包 wget http://download.pingcap.org/tidb-binlog-latest-linux-amd64.tar.gz wget http://download.pingcap.org/tidb-binlog-latest-linux-amd64.sha256 # 检查文件完整性,返回 ok 则正确 sha256sum -c tidb-binlog-latest-linux-amd64.sha256 # 解开压缩包 tar -xzf tidb-binlog-latest-linux-amd64.tar.gz cd tidb-binlog-latest-linux-amd64 TiDB-Binlog 部署 注意 需要为一个 TiDB 集群中的每台 TiDB server 部署一个 Pump,目前 TiDB server 只支持以 unix socket 的方式输出 Binlog。 手动部署时,启动优先级为:Pump > TiDB;停止优先级为 TiDB > Pump。设置 TiDB 启动参数 binlog-socket 为对应的 Pump 参数 socket 所指定的 unix socket 文件路径,最终部署结构如下图所示: Drainer 不支持对 ignore schemas(在过滤列表中的 schemas)的 table 进行 rename DDL 操作。 在已有的 TiDB 集群中启动 Drainer,一般需要全量备份并且获取 savepoint,然后导入全量备份,最后启动 Drainer 从 savepoint 开始同步;为了保证数据的完整性,在 Pump 运行 10 分钟左右后按顺序进行如下操作: 使用 tidb-tools 项目中的 generate_binlog_position 工具生成 Drainer 启动需要的 savepoint 文件中,make generate_binlog_position 编译该工具。具体使用参考工具的 README 说明,也可以直接下载获取该工具:generate_binlog_position, 并使用sha256sum验证该文件 sha256。 全量备份,例如 mydumper 备份 TiDB 全量导入备份到目标系统 Kafka 版本 Drainer 启动的 savepoint 默认保存在下游 database tidb_binlog 下的 checkpoint 表中,如果 checkpoint 表中没有效的数据,可以通过设置 initial-commit-ts 启动 Drainer 从指定位置开始消费 - bin/drainer --config=conf/drainer.toml --initial-commit-ts=${commitTS} Drainer 输出的 pb,要在配置文件中设置如下参数:[syncer] db-type = "pb" disable-dispatch = true [syncer.to] dir = "/path/pb-dir" Kafka 和 ZooKeeper 集群需要在部署 TiDB-Binlog 之前部署好。Kafka 需要 0.9 及以上版本。 Kafka 集群配置推荐 名字 数量 内存 CPU 硬盘 Kafka 3+ 16G 8+ 2+ 1TB ZooKeeper 3+ 8G 4+ 2+ 300G Kafka 配置参数推荐 auto.create.topics.enable = true:如果还没有创建 topic,Kafka 会在 broker 上自动创建 topic broker.id:用来标识 Kafka 集群的必备参数,不能重复;如 broker.id = 1 fs.file-max = 1000000:Kafka 会使用大量文件和网络 socket,建议修改成 1000000,通过 vi /etc/sysctl.conf 进行修改 使用 tidb-ansible 部署 Pump 如无 Kafka 集群,可使用 kafka-ansible 部署 Kafka 集群。 使用 TiDB-Ansible 部署 TiDB 集群时,修改 tidb-ansible/inventory.ini 文件,设置 enable_binlog = True,并配置 zookeeper_addrs 变量为 Kafka 集群的 ZooKeeper 地址,这样部署 TiDB 集群时会部署 Pump。 配置样例:# binlog trigger enable_binlog = True # ZooKeeper address of Kafka cluster, example: # zookeeper_addrs = "192.168.0.11:2181,192.168.0.12:2181,192.168.0.13:2181" zookeeper_addrs = "192.168.0.11:2181,192.168.0.12:2181,192.168.0.13:2181" 使用 Binary 部署 Pump 使用样例:假设我们有三个 PD,三个 ZooKeeper,一个 TiDB,各个节点信息如下:TiDB="192.168.0.10" PD1="192.168.0.16" PD2="192.168.0.15" PD3="192.168.0.14" ZK1="192.168.0.13" ZK2="192.168.0.12" ZK3="192.168.0.11" 在 ip=“192.168.0.10” 的机器上面部署 Drainer/Pump;对应的 PD 集群的 ip=“192.168.0.16,192.168.0.15,192.168.0.14”;对应的 Kafka 集群的 ZooKeeper 的 ip=“192.168.0.13,192.168.0.12,192.168.0.11”。以此为例,说明 Pump/Drainer 的使用。 Pump 命令行参数说明Usage of Pump: -L string 日志输出信息等级设置: debug, info, warn, error, fatal (默认 "info") -V 打印版本信息 -addr string Pump 提供服务的 RPC 地址(-addr="192.168.0.10:8250") -advertise-addr string Pump 对外提供服务的 RPC 地址(-advertise-addr="192.168.0.10:8250") -config string 配置文件路径,如果你指定了配置文件,Pump 会首先读取配置文件的配置; 如果对应的配置在命令行参数里面也存在,Pump 就会使用命令行参数的配置来覆盖配置文件里面的。 -data-dir string Pump 数据存储位置路径 -zookeeper-addrs string (-zookeeper_addrs = "192.168.0.11:2181,192.168.0.12:2181,192.168.0.13:2181") ZooKeeper 地址,该选项从 ZooKeeper 中获取 Kafka 地址 -gc int 日志最大保留天数 (默认 7),设置为 0 可永久保存 -heartbeat-interval uint Pump 向 PD 发送心跳间隔 (单位 秒) -log-file string log 文件路径 -log-rotate string log 文件切换频率,hour/day -metrics-addr string Prometheus pushgataway 地址,不设置则禁止上报监控信息 -metrics-interval int 监控信息上报频率 (默认 15,单位 秒) -pd-urls string PD 集群节点的地址 (-pd-urls="http://192.168.0.16:2379,http://192.168.0.15:2379,http://192.168.0.14:2379") -socket string unix socket 模式服务监听地址(默认 unix:///tmp/pump.sock) Pump 配置文件# Pump Configuration. # Pump 提供服务的 RPC 地址("192.168.0.10:8250") addr = "192.168.0.10:8250" # Pump 对外提供服务的 RPC 地址("192.168.0.10:8250") advertise-addr = "" # binlog 最大保留天数 (默认 7),设置为 0 可永久保存 gc = 7 # Pump 数据存储位置路径 data-dir = "data.pump" # ZooKeeper 地址,设置该选项从 ZooKeeper 中获取 Kafka 地址 # ZooKeeper-addrs = "192.168.0.11:2181,192.168.0.12:2181,192.168.0.13:2181" # Pump 向 PD 发送心跳的间隔 (单位 秒) heartbeat-interval = 3 # PD 集群节点的地址 pd-urls = "http://192.168.0.16:2379,http://192.168.0.15:2379,http://192.168.0.14:2379" # unix socket 模式服务监听地址 (默认 unix:///tmp/pump.sock) socket = "unix:///tmp/pump.sock" 启动示例./bin/pump -config pump.toml 使用 Binary 部署 Drainer Drainer 命令行参数说明Usage of Drainer: -L string 日志输出信息等级设置:debug, info, warn, error, fatal (默认 "info") -V 打印版本信息 -addr string Drainer 提供服务的地址(-addr="192.168.0.10:8249") -c int 同步下游的并发数,该值设置越高同步的吞吐性能越好 (default 1) -config string 配置文件路径,Drainer 会首先读取配置文件的配置; 如果对应的配置在命令行参数里面也存在,Drainer 就会使用命令行参数的配置来覆盖配置文件里面的 -data-dir string Drainer 数据存储位置路径 (默认 "data.drainer") -zookeeper-addrs string (-zookeeper-addrs="192.168.0.11:2181,192.168.0.12:2181,192.168.0.13:2181") ZooKeeper 地址,该选项从 ZooKeeper 中获取 Kafka 地址 -dest-db-type string Drainer 下游服务类型 (默认为 mysql) -detect-interval int 向 PD 查询在线 Pump 的时间间隔 (默认 10,单位 秒) -disable-dispatch 是否禁用拆分单个 binlog 的 sqls 的功能,如果设置为 true,则按照每个 binlog 顺序依次还原成单个事务进行同步(下游服务类型为 mysql,该项设置为 False) -ignore-schemas string db 过滤列表 (默认 "INFORMATION_SCHEMA,PERFORMANCE_SCHEMA,mysql,test"), 不支持对 ignore schemas 的 table 进行 rename DDL 操作 -initial-commit-ts (默认为 0) 如果 Drainer 没有相关的断点信息,可以通过该项来设置相关的断点信息 -log-file string log 文件路径 -log-rotate string log 文件切换频率,hour/day -metrics-addr string Prometheus pushgataway 地址,不设置则禁止上报监控信息 -metrics-interval int 监控信息上报频率(默认 15,单位 秒) -pd-urls string PD 集群节点的地址 (-pd-urls="http://192.168.0.16:2379,http://192.168.0.15:2379,http://192.168.0.14:2379") -txn-batch int 输出到下游数据库一个事务的 SQL 数量(默认 1) Drainer 配置文件# Drainer Configuration. # Drainer 提供服务的地址("192.168.0.10:8249") addr = "192.168.0.10:8249" # 向 PD 查询在线 Pump 的时间间隔 (默认 10,单位 秒) detect-interval = 10 # Drainer 数据存储位置路径 (默认 "data.drainer") data-dir = "data.drainer" # ZooKeeper 地址,该选项从 ZooKeeper 中获取 kafka 地址 # zookeeper-addrs = "192.168.0.11:2181,192.168.0.12:2181,192.168.0.13:2181" # PD 集群节点的地址 pd-urls = "http://192.168.0.16:2379,http://192.168.0.15:2379,http://192.168.0.14:2379" # log 文件路径 log-file = "drainer.log" # Syncer Configuration. [syncer] ## db 过滤列表 (默认 "INFORMATION_SCHEMA,PERFORMANCE_SCHEMA,mysql,test"), ## 不支持对 ignore schemas 的 table 进行 rename DDL 操作 ignore-schemas = "INFORMATION_SCHEMA,PERFORMANCE_SCHEMA,mysql" # 输出到下游数据库一个事务的 SQL 数量 (default 1) txn-batch = 1 # 同步下游的并发数,该值设置越高同步的吞吐性能越好 (default 1) worker-count = 1 # 是否禁用拆分单个 binlog 的 sqls 的功能,如果设置为 true,则按照每个 binlog # 顺序依次还原成单个事务进行同步(下游服务类型为 mysql, 该项设置为 False) disable-dispatch = false # Drainer 下游服务类型(默认为 mysql) # 参数有效值为 "mysql", "pb" db-type = "mysql" # replicate-do-db prioritizes over replicate-do-table when they have the same db name # and we support regex expressions, # 以 '~' 开始声明使用正则表达式 #replicate-do-db = ["~^b.*","s1"] #[[syncer.replicate-do-table]] #db-name ="test" #tbl-name = "log" #[[syncer.replicate-do-table]] #db-name ="test" #tbl-name = "~^a.*" # db-type 设置为 mysql 时,下游数据库服务器参数 [syncer.to] host = "192.168.0.10" user = "root" password = "" port = 3306 # db-type 设置为 pb 时,存放 binlog 文件的目录 # [syncer.to] # dir = "data.drainer" 启动示例./bin/drainer -config drainer.toml …"}, {"url": "https://pingcap.com/docs-cn/v1.0/tools/tidb-binlog/", "title": "TiDB-Binlog 部署方案", "content": " TiDB-Binlog 部署方案 TiDB-Binlog 简介 TiDB-Binlog 用于收集 TiDB 的 Binlog,并提供实时备份和同步功能的商业工具。TiDB-Binlog 支持以下功能场景: 数据同步: 同步 TiDB 集群数据到其他数据库 实时备份和恢复: 备份 TiDB 集群数据,同时可以用于 TiDB 集群故障时恢复 TiDB-Binlog 架构 首先介绍 TiDB-Binlog 的整体架构。TiDB-Binlog 集群主要分为两个组件:Pump Pump 是一个守护进程,在每个 TiDB 的主机上后台运行。他的主要功能是实时记录 TiDB 产生的 Binlog 并顺序写入磁盘文件Drainer Drainer 从各个 Pump 节点收集 Binlog,并按照在 TiDB 中事务的提交顺序转化为指定数据库兼容的 SQL 语句,最后同步到目的数据库或者写到顺序文件TiDB-Binlog 安装 下载官方 Binary CentOS 7+# 下载压缩包 wget http://download.pingcap.org/tidb-binlog-local-linux-amd64.tar.gz wget http://download.pingcap.org/tidb-binlog-local-linux-amd64.sha256 # 检查文件完整性,返回 ok 则正确 sha256sum -c tidb-binlog-local-linux-amd64.sha256 # 解开压缩包 tar -xzf tidb-binlog-local-linux-amd64.tar.gz cd tidb-binlog-local-linux-amd64 TiDB-Binlog 部署 注意 需要为一个 TiDB 集群中的每台 TiDB server 部署一个 pump,目前 TiDB server 只支持以 unix socket 方式的输出 binlog。 手动部署时, 启动优先级为: PUMP > TiDB ; 停止优先级为 TiDB > PUMP我们设置 TiDB 启动参数 binlog-socket 为对应的 pump 的参数 socket 所指定的 unix socket 文件路径,最终部署结构如下图所示: drainer 不支持对 ignore schemas(在过滤列表中的 schemas) 的 table 进行 rename DDL 操作 在已有的 TiDB 集群中启动 drainer,一般需要全量备份 并且获取 savepoint,然后导入全量备份,最后启动 drainer 从 savepoint 开始同步;为了保证数据的完整性,在 pump 运行 10 分钟左右后按顺序进行下面的操作 以 gen-savepoint model 运行 drainer 生成 drainer savepint 文件,bin/drainer -gen-savepoint --data-dir= ${drainer_savepoint_dir} --pd-urls=${pd_urls} 全量备份,例如 mydumper 备份 tidb 全量导入备份到目标系统 设置 savepoint 文件路径,然后启动 drainer, bin/drainer --config=conf/drainer.toml --data-dir=${drainer_savepoint_dir} drainer 输出的 pb, 需要在配置文件设置下面的参数[syncer] db-type = "pb" disable-dispatch = true [syncer.to] dir = "/path/pb-dir" 使用 tidb-ansible 部署 PUMP (推荐) 搭建全新的 TiDB Cluster,启动顺序 pd-server -> tikv-server -> pump -> tidb-server -> drainer 修改 tidb-ansible inventory.ini 文件 enable_binlog = True 执行 ansible-playbook deploy.yml 执行 ansible-playbook start.yml drainer 目前需要手动部署 对已有的 TiDB Cluster 部署 binlog 修改 tidb-ansible inventory.ini 文件 enable_binlog = True 执行 ansible-playbook rolling_update.yml –tags=tidb drainer 目前需要手动部署 使用 Binary 部署 PUMP PUMP 命令行参数说明Usage of pump: -L string 日志输出信息等级设置: debug, info, warn, error, fatal (默认 "info") -V 打印版本信息 -addr string pump 提供服务的 rpc 地址(默认 "127.0.0.1:8250") -advertise-addr string pump 对外提供服务的 rpc 地址(默认 "127.0.0.1:8250") -config string 配置文件路径,如果你指定了配置文件,pump 会首先读取配置文件的配置 如果对应的配置在命令行参数里面也存在,pump 就会使用命令行参数的配置来覆盖配置文件里面的 -data-dir string pump 数据存储位置路径 -gc int 日志最大保留天数 (默认 7), 设置为 0 可永久保存 -heartbeat-interval uint pump 向 pd 发送心跳间隔 (单位 秒) -log-file string log 文件路径 -log-rotate string log 文件切换频率, hour/day -metrics-addr string prometheus pushgataway 地址,不设置则禁止上报监控信息 -metrics-interval int 监控信息上报频率 (默认 15,单位 秒) -pd-urls string pd 集群节点的地址 (默认 "http://127.0.0.1:2379") -socket string unix socket 模式服务监听地址 (默认 unix:///tmp/pump.sock) PUMP 配置文件 # pump Configuration. # pump 提供服务的 rpc 地址(默认 "127.0.0.1:8250") addr = "127.0.0.1:8250" # pump 对外提供服务的 rpc 地址(默认 "127.0.0.1:8250") advertise-addr = "" # binlog 最大保留天数 (默认 7), 设置为 0 可永久保存 gc = 7 # pump 数据存储位置路径 data-dir = "data.pump" # pump 向 pd 发送心跳间隔 (单位 秒) heartbeat-interval = 3 # pd 集群节点的地址 (默认 "http://127.0.0.1:2379") pd-urls = "http://127.0.0.1:2379" # unix socket 模式服务监听地址 (默认 unix:///tmp/pump.sock) socket = "unix:///tmp/pump.sock" 启动示例./bin/pump -config pump.toml 使用 Binary 部署 Drainer Drainer 命令行参数说明Usage of drainer: -L string 日志输出信息等级设置: debug, info, warn, error, fatal (默认 "info") -V 打印版本信息 -addr string drainer 提供服务的地址(默认 "127.0.0.1:8249") -c int 同步下游的并发数,该值设置越高同步的吞吐性能越好 (default 1) -config string 配置文件路径, drainer 会首先读取配置文件的配置 如果对应的配置在命令行参数里面也存在,drainer 就会使用命令行参数的配置来覆盖配置文件里面的 -data-dir string drainer 数据存储位置路径 (默认 "data.drainer") -dest-db-type string drainer 下游服务类型 (默认为 mysql) -detect-interval int 向 pd 查询在线 pump 的时间间隔 (默认 10,单位 秒) -disable-dispatch 是否禁用拆分单个 binlog 的 sqls 的功能,如果设置为 true,则按照每个 binlog 顺序依次还原成单个事务进行同步( 下游服务类型为 mysql, 该项设置为 False ) -gen-savepoint 如果设置为 true, 则只生成 drainer 的 savepoint meta 文件, 可以配合 mydumper 使用 -ignore-schemas string db 过滤列表 (默认 "INFORMATION_SCHEMA,PERFORMANCE_SCHEMA,mysql,test"), 不支持对 ignore schemas 的 table 进行 rename DDL 操作 -log-file string log 文件路径 -log-rotate string log 文件切换频率, hour/day -metrics-addr string prometheus pushgataway 地址,不设置则禁止上报监控信息 -metrics-interval int 监控信息上报频率 (默认 15,单位 秒) -pd-urls string pd 集群节点的地址 (默认 "http://127.0.0.1:2379") -txn-batch int 输出到下游数据库一个事务的 sql 数量 (default 1) Drainer 配置文件# drainer Configuration. # drainer 提供服务的地址(默认 "127.0.0.1:8249") addr = "127.0.0.1:8249" # 向 pd 查询在线 pump 的时间间隔 (默认 10,单位 秒) detect-interval = 10 # drainer 数据存储位置路径 (默认 "data.drainer") data-dir = "data.drainer" # pd 集群节点的地址 (默认 "http://127.0.0.1:2379") pd-urls = "http://127.0.0.1:2379" # log 文件路径 log-file = "drainer.log" # syncer Configuration. [syncer] ## db 过滤列表 (默认 "INFORMATION_SCHEMA,PERFORMANCE_SCHEMA,mysql,test"), ## 不支持对 ignore schemas 的 table 进行 rename DDL 操作 ignore-schemas = "INFORMATION_SCHEMA,PERFORMANCE_SCHEMA,mysql" # 输出到下游数据库一个事务的 sql 数量 (default 1) txn-batch = 1 # 同步下游的并发数,该值设置越高同步的吞吐性能越好 (default 1) worker-count = 1 # 是否禁用拆分单个 binlog 的 sqls 的功能,如果设置为 true,则按照每个 binlog # 顺序依次还原成单个事务进行同步( 下游服务类型为 mysql, 该项设置为 False ) disable-dispatch = false # drainer 下游服务类型 (默认为 mysql) # 参数有效值为 "mysql", "pb" db-type = "mysql" # replicate-do-db priority over replicate-do-table if have same db name # and we support regex expression , # 以 '~' 开始声明使用正则表达式 #replicate-do-db = ["~^b.*","s1"] #[[syncer.replicate-do-table]] #db-name ="test" #tbl-name = "log" #[[syncer.replicate-do-table]] #db-name ="test" #tbl-name = "~^a.*" # db-type 设置为 mysql 时,下游数据库服务器参数 [syncer.to] host = "127.0.0.1" user = "root" password = "" port = 3306 # db-type 设置为 pb 时,存放 binlog 文件的目录 # [syncer.to] # dir = "data.drainer" 启动示例./bin/drainer -config drainer.toml TiDB-Binlog 监控 这部分主要对 TiDB-Binlog 的状态、性能做监控,通过 Prometheus + Grafana 展现 metrics 数据,pump/drainer 配置 使用 ansible 部署的 pump 服务,已经在启动参数设置 metrics 。drainer 启动时可以设置 --metrics-addr 和 --metrics-interval 两个参数,其中 metrics-addr 设为 Push Gateway 的地址,metrics-interval 为 push 的频率,单位为秒,默认值为15Grafana 配置 进入 Grafana Web 界面(默认地址: http://localhost:3000,默认账号: admin 密码: admin)点击 Grafana Logo -> 点击 Data Sources -> 点击 Add data source -> 填写 data source 信息 ( 注: Type 选 Prometheus,Url 为 Prometheus 地址,根据实际情况 添加/填写 ) 导入 dashboard 配置文件点击 Grafana Logo -> 点击 Dashboards -> 点击 Import -> 选择需要的 dashboard 配置文件上传 -> 选择对应的 data source "}, {"url": "https://pingcap.com/docs-cn/v2.0/tools/tidb-binlog-kafka/", "title": "TiDB-Binlog 部署方案", "content": " TiDB-Binlog 部署方案 本文档介绍如何部署 Kafka 版本的 TiDB-Binlog。如需部署 local 版本的 TiDB-Binlog,可参考 local 版本的 TiDB-Binlog 部署文档。TiDB-Binlog 简介 TiDB-Binlog 用于收集 TiDB 的 Binlog,并提供实时备份和同步功能的商业工具。TiDB-Binlog 支持以下功能场景: 数据同步:同步 TiDB 集群数据到其他数据库 实时备份和恢复:备份 TiDB 集群数据,同时可以用于 TiDB 集群故障时恢复 TiDB-Binlog 架构 首先介绍 TiDB-Binlog 的整体架构。TiDB-Binlog 集群主要分为三个组件:Pump Pump 是一个守护进程,在每个 TiDB 主机的后台运行。其主要功能是实时记录 TiDB 产生的 Binlog 并顺序写入 Kafka 中。Drainer Drainer 从 Kafka 中收集 Binlog,并按照 TiDB 中事务的提交顺序转化为指定数据库兼容的 SQL 语句,最后同步到目的数据库或者写到顺序文件。Kafka & ZooKeeper Kafka 集群用来存储由 Pump 写入的 Binlog 数据,并提供给 Drainer 进行读取。 注:local 版本将 Binlog 存储在文件中,最新版本则使用 Kafka 存储。 TiDB-Binlog 安装 下载官方 Binary CentOS 7+# 下载压缩包 wget http://download.pingcap.org/tidb-binlog-latest-linux-amd64.tar.gz wget http://download.pingcap.org/tidb-binlog-latest-linux-amd64.sha256 # 检查文件完整性,返回 ok 则正确 sha256sum -c tidb-binlog-latest-linux-amd64.sha256 # 解开压缩包 tar -xzf tidb-binlog-latest-linux-amd64.tar.gz cd tidb-binlog-latest-linux-amd64 TiDB-Binlog 部署 注意 需要为一个 TiDB 集群中的每台 TiDB server 部署一个 Pump,目前 TiDB server 只支持以 unix socket 的方式输出 Binlog。 手动部署时,启动优先级为:Pump > TiDB;停止优先级为 TiDB > Pump。设置 TiDB 启动参数 binlog-socket 为对应的 Pump 参数 socket 所指定的 unix socket 文件路径,最终部署结构如下图所示: Drainer 不支持对 ignore schemas(在过滤列表中的 schemas)的 table 进行 rename DDL 操作。 在已有的 TiDB 集群中启动 Drainer,一般需要全量备份并且获取 savepoint,然后导入全量备份,最后启动 Drainer 从 savepoint 开始同步;为了保证数据的完整性,在 Pump 运行 10 分钟左右后按顺序进行如下操作: 使用 tidb-tools 项目中的 generate_binlog_position 工具生成 Drainer 启动需要的 savepoint 文件中,make generate_binlog_position 编译该工具。具体使用参考工具的 README 说明,也可以直接下载获取该工具:generate_binlog_position, 并使用sha256sum验证该文件 sha256。 全量备份,例如 mydumper 备份 TiDB 全量导入备份到目标系统 Kafka 版本 Drainer 启动的 savepoint 默认保存在下游 database tidb_binlog 下的 checkpoint 表中,如果 checkpoint 表中没有效的数据,可以通过设置 initial-commit-ts 启动 Drainer 从指定位置开始消费 - bin/drainer --config=conf/drainer.toml --initial-commit-ts=${commitTS} Drainer 输出的 pb,要在配置文件中设置如下参数:[syncer] db-type = "pb" disable-dispatch = true [syncer.to] dir = "/path/pb-dir" Kafka 和 ZooKeeper 集群需要在部署 TiDB-Binlog 之前部署好。Kafka 需要 0.9 及以上版本。 Kafka 集群配置推荐 名字 数量 内存 CPU 硬盘 Kafka 3+ 16G 8+ 2+ 1TB ZooKeeper 3+ 8G 4+ 2+ 300G Kafka 配置参数推荐 auto.create.topics.enable = true:如果还没有创建 topic,Kafka 会在 broker 上自动创建 topic broker.id:用来标识 Kafka 集群的必备参数,不能重复;如 broker.id = 1 fs.file-max = 1000000:Kafka 会使用大量文件和网络 socket,建议修改成 1000000,通过 vi /etc/sysctl.conf 进行修改 使用 tidb-ansible 部署 Pump 如无 Kafka 集群,可使用 kafka-ansible 部署 Kafka 集群。 使用 tidb-ansible 部署 TiDB 集群时,修改 tidb-ansible/inventory.ini 文件,设置 enable_binlog = True,并配置 zookeeper_addrs 变量为 Kafka 集群的 ZooKeeper 地址,这样部署 TiDB 集群时会部署 Pump。 配置样例:# binlog trigger enable_binlog = True # ZooKeeper address of Kafka cluster, example: # zookeeper_addrs = "192.168.0.11:2181,192.168.0.12:2181,192.168.0.13:2181" zookeeper_addrs = "192.168.0.11:2181,192.168.0.12:2181,192.168.0.13:2181" 使用 Binary 部署 Pump 使用样例:假设我们有三个 PD,三个 ZooKeeper,一个 TiDB,各个节点信息如下:TiDB="192.168.0.10" PD1="192.168.0.16" PD2="192.168.0.15" PD3="192.168.0.14" ZK1="192.168.0.13" ZK2="192.168.0.12" ZK3="192.168.0.11" 在 ip=“192.168.0.10” 的机器上面部署 Drainer/Pump;对应的 PD 集群的 ip=“192.168.0.16,192.168.0.15,192.168.0.14”;对应的 Kafka 集群的 ZooKeeper 的 ip=“192.168.0.13,192.168.0.12,192.168.0.11”。以此为例,说明 Pump/Drainer 的使用。 Pump 命令行参数说明Usage of Pump: -L string 日志输出信息等级设置: debug, info, warn, error, fatal (默认 "info") -V 打印版本信息 -addr string Pump 提供服务的 RPC 地址(-addr="192.168.0.10:8250") -advertise-addr string Pump 对外提供服务的 RPC 地址(-advertise-addr="192.168.0.10:8250") -config string 配置文件路径,如果你指定了配置文件,Pump 会首先读取配置文件的配置; 如果对应的配置在命令行参数里面也存在,Pump 就会使用命令行参数的配置来覆盖配置文件里面的。 -data-dir string Pump 数据存储位置路径 -enable-tolerant 开启 tolerant 后,如果 binlog 写入失败,Pump 不会报错(默认开启) -zookeeper-addrs string (-zookeeper_addrs = "192.168.0.11:2181,192.168.0.12:2181,192.168.0.13:2181") ZooKeeper 地址,该选项从 ZooKeeper 中获取 Kafka 地址 -gc int 日志最大保留天数 (默认 7),设置为 0 可永久保存 -heartbeat-interval int Pump 向 PD 发送心跳间隔 (单位 秒) -log-file string log 文件路径 -log-rotate string log 文件切换频率,hour/day -metrics-addr string Prometheus pushgataway 地址,不设置则禁止上报监控信息 -metrics-interval int 监控信息上报频率 (默认 15,单位 秒) -pd-urls string PD 集群节点的地址 (-pd-urls="http://192.168.0.16:2379,http://192.168.0.15:2379,http://192.168.0.14:2379") -socket string unix socket 模式服务监听地址(默认 unix:///tmp/pump.sock) Pump 配置文件# Pump Configuration. # Pump 提供服务的 RPC 地址("192.168.0.10:8250") addr = "192.168.0.10:8250" # Pump 对外提供服务的 RPC 地址("192.168.0.10:8250") advertise-addr = "" # binlog 最大保留天数 (默认 7),设置为 0 可永久保存 gc = 7 # Pump 数据存储位置路径 data-dir = "data.pump" # ZooKeeper 地址,设置该选项从 ZooKeeper 中获取 Kafka 地址 # ZooKeeper-addrs = "192.168.0.11:2181,192.168.0.12:2181,192.168.0.13:2181" # Pump 向 PD 发送心跳的间隔 (单位 秒) heartbeat-interval = 3 # PD 集群节点的地址 pd-urls = "http://192.168.0.16:2379,http://192.168.0.15:2379,http://192.168.0.14:2379" # unix socket 模式服务监听地址 (默认 unix:///tmp/pump.sock) socket = "unix:///tmp/pump.sock" 启动示例./bin/pump -config pump.toml 使用 Binary 部署 Drainer Drainer 命令行参数说明Usage of Drainer: -L string 日志输出信息等级设置:debug, info, warn, error, fatal (默认 "info") -V 打印版本信息 -addr string Drainer 提供服务的地址(-addr="192.168.0.10:8249") -c int 同步下游的并发数,该值设置越高同步的吞吐性能越好 (default 1) -config string 配置文件路径,Drainer 会首先读取配置文件的配置; 如果对应的配置在命令行参数里面也存在,Drainer 就会使用命令行参数的配置来覆盖配置文件里面的 -data-dir string Drainer 数据存储位置路径 (默认 "data.drainer") -zookeeper-addrs string (-zookeeper-addrs="192.168.0.11:2181,192.168.0.12:2181,192.168.0.13:2181") ZooKeeper 地址,该选项从 ZooKeeper 中获取 Kafka 地址 -dest-db-type string Drainer 下游服务类型 (默认为 mysql) -detect-interval int 向 PD 查询在线 Pump 的时间间隔 (默认 10,单位 秒) -disable-dispatch 是否禁用拆分单个 binlog 的 sqls 的功能,如果设置为 true,则按照每个 binlog 顺序依次还原成单个事务进行同步(下游服务类型为 mysql,该项设置为 False) -ignore-schemas string db 过滤列表 (默认 "INFORMATION_SCHEMA,PERFORMANCE_SCHEMA,mysql,test"), 不支持对 ignore schemas 的 table 进行 rename DDL 操作 -initial-commit-ts (默认为 0) 如果 Drainer 没有相关的断点信息,可以通过该项来设置相关的断点信息 -log-file string log 文件路径 -log-rotate string log 文件切换频率,hour/day -metrics-addr string Prometheus pushgataway 地址,不设置则禁止上报监控信息 -metrics-interval int 监控信息上报频率(默认 15,单位 秒) -pd-urls string PD 集群节点的地址 (-pd-urls="http://192.168.0.16:2379,http://192.168.0.15:2379,http://192.168.0.14:2379") -txn-batch int 输出到下游数据库一个事务的 SQL 数量(默认 1) Drainer 配置文件# Drainer Configuration. # Drainer 提供服务的地址("192.168.0.10:8249") addr = "192.168.0.10:8249" # 向 PD 查询在线 Pump 的时间间隔 (默认 10,单位 秒) detect-interval = 10 # Drainer 数据存储位置路径 (默认 "data.drainer") data-dir = "data.drainer" # ZooKeeper 地址,该选项从 ZooKeeper 中获取 kafka 地址 # zookeeper-addrs = "192.168.0.11:2181,192.168.0.12:2181,192.168.0.13:2181" # PD 集群节点的地址 pd-urls = "http://192.168.0.16:2379,http://192.168.0.15:2379,http://192.168.0.14:2379" # log 文件路径 log-file = "drainer.log" # Syncer Configuration. [syncer] ## db 过滤列表 (默认 "INFORMATION_SCHEMA,PERFORMANCE_SCHEMA,mysql,test"), ## 不支持对 ignore schemas 的 table 进行 rename DDL 操作 ignore-schemas = "INFORMATION_SCHEMA,PERFORMANCE_SCHEMA,mysql" # 输出到下游数据库一个事务的 SQL 数量 (default 1) txn-batch = 1 # 同步下游的并发数,该值设置越高同步的吞吐性能越好 (default 1) worker-count = 1 # 是否禁用拆分单个 binlog 的 sqls 的功能,如果设置为 true,则按照每个 binlog # 顺序依次还原成单个事务进行同步(下游服务类型为 mysql, 该项设置为 False) disable-dispatch = false # Drainer 下游服务类型(默认为 mysql) # 参数有效值为 "mysql", "pb" db-type = "mysql" # replicate-do-db prioritizes over replicate-do-table when they have the same db name # and we support regex expressions, # 以 '~' 开始声明使用正则表达式 #replicate-do-db = ["~^b.*","s1"] #[[syncer.replicate-do-table]] #db-name ="test" #tbl-name = "log" #[[syncer.replicate-do-table]] #db-name ="test" #tbl-name = "~^a.*" # db-type 设置为 mysql 时,下游数据库服务器参数 [syncer.to] host = "192.168.0.10" user = "root" password = "" port = 3306 # db-type 设置为 pb 时,存放 binlog 文件的目录 # [syncer.to] # dir = …"}, {"url": "https://pingcap.com/docs-cn/v2.0/tools/tidb-binlog/", "title": "TiDB-Binlog 部署方案", "content": " TiDB-Binlog 部署方案 TiDB-Binlog 简介 TiDB-Binlog 用于收集 TiDB 的 Binlog,并提供实时备份和同步功能的商业工具。TiDB-Binlog 支持以下功能场景: 数据同步: 同步 TiDB 集群数据到其他数据库 实时备份和恢复: 备份 TiDB 集群数据,同时可以用于 TiDB 集群故障时恢复 TiDB-Binlog 架构 首先介绍 TiDB-Binlog 的整体架构。TiDB-Binlog 集群主要分为两个组件:Pump Pump 是一个守护进程,在每个 TiDB 的主机上后台运行。他的主要功能是实时记录 TiDB 产生的 Binlog 并顺序写入磁盘文件Drainer Drainer 从各个 Pump 节点收集 Binlog,并按照在 TiDB 中事务的提交顺序转化为指定数据库兼容的 SQL 语句,最后同步到目的数据库或者写到顺序文件TiDB-Binlog 安装 下载官方 Binary CentOS 7+# 下载压缩包 wget http://download.pingcap.org/tidb-binlog-local-linux-amd64.tar.gz wget http://download.pingcap.org/tidb-binlog-local-linux-amd64.sha256 # 检查文件完整性,返回 ok 则正确 sha256sum -c tidb-binlog-local-linux-amd64.sha256 # 解开压缩包 tar -xzf tidb-binlog-local-linux-amd64.tar.gz cd tidb-binlog-local-linux-amd64 TiDB-Binlog 部署 注意 需要为一个 TiDB 集群中的每台 TiDB server 部署一个 pump,目前 TiDB server 只支持以 unix socket 方式的输出 binlog。 手动部署时, 启动优先级为: PUMP > TiDB ; 停止优先级为 TiDB > PUMP我们设置 TiDB 启动参数 binlog-socket 为对应的 pump 的参数 socket 所指定的 unix socket 文件路径,最终部署结构如下图所示: drainer 不支持对 ignore schemas(在过滤列表中的 schemas) 的 table 进行 rename DDL 操作 在已有的 TiDB 集群中启动 drainer,一般需要全量备份 并且获取 savepoint,然后导入全量备份,最后启动 drainer 从 savepoint 开始同步;为了保证数据的完整性,在 pump 运行 10 分钟左右后按顺序进行下面的操作 以 gen-savepoint model 运行 drainer 生成 drainer savepint 文件,bin/drainer -gen-savepoint --data-dir= ${drainer_savepoint_dir} --pd-urls=${pd_urls} 全量备份,例如 mydumper 备份 tidb 全量导入备份到目标系统 设置 savepoint 文件路径,然后启动 drainer, bin/drainer --config=conf/drainer.toml --data-dir=${drainer_savepoint_dir} drainer 输出的 pb, 需要在配置文件设置下面的参数[syncer] db-type = "pb" disable-dispatch = true [syncer.to] dir = "/path/pb-dir" 使用 tidb-ansible 部署 PUMP (推荐) 搭建全新的 TiDB Cluster,启动顺序 pd-server -> tikv-server -> pump -> tidb-server -> drainer 修改 tidb-ansible inventory.ini 文件 enable_binlog = True 执行 ansible-playbook deploy.yml 执行 ansible-playbook start.yml drainer 目前需要手动部署 对已有的 TiDB Cluster 部署 binlog 修改 tidb-ansible inventory.ini 文件 enable_binlog = True 执行 ansible-playbook rolling_update.yml –tags=tidb drainer 目前需要手动部署 使用 Binary 部署 PUMP PUMP 命令行参数说明Usage of pump: -L string 日志输出信息等级设置: debug, info, warn, error, fatal (默认 "info") -V 打印版本信息 -addr string pump 提供服务的 rpc 地址(默认 "127.0.0.1:8250") -advertise-addr string pump 对外提供服务的 rpc 地址(默认 "127.0.0.1:8250") -config string 配置文件路径,如果你指定了配置文件,pump 会首先读取配置文件的配置 如果对应的配置在命令行参数里面也存在,pump 就会使用命令行参数的配置来覆盖配置文件里面的 -data-dir string pump 数据存储位置路径 -gc int 日志最大保留天数 (默认 7), 设置为 0 可永久保存 -heartbeat-interval uint pump 向 pd 发送心跳间隔 (单位 秒) -log-file string log 文件路径 -log-rotate string log 文件切换频率, hour/day -metrics-addr string prometheus pushgataway 地址,不设置则禁止上报监控信息 -metrics-interval int 监控信息上报频率 (默认 15,单位 秒) -pd-urls string pd 集群节点的地址 (默认 "http://127.0.0.1:2379") -socket string unix socket 模式服务监听地址 (默认 unix:///tmp/pump.sock) PUMP 配置文件 # pump Configuration. # pump 提供服务的 rpc 地址(默认 "127.0.0.1:8250") addr = "127.0.0.1:8250" # pump 对外提供服务的 rpc 地址(默认 "127.0.0.1:8250") advertise-addr = "" # binlog 最大保留天数 (默认 7), 设置为 0 可永久保存 gc = 7 # pump 数据存储位置路径 data-dir = "data.pump" # pump 向 pd 发送心跳间隔 (单位 秒) heartbeat-interval = 3 # pd 集群节点的地址 (默认 "http://127.0.0.1:2379") pd-urls = "http://127.0.0.1:2379" # unix socket 模式服务监听地址 (默认 unix:///tmp/pump.sock) socket = "unix:///tmp/pump.sock" 启动示例./bin/pump -config pump.toml 使用 Binary 部署 Drainer Drainer 命令行参数说明Usage of drainer: -L string 日志输出信息等级设置: debug, info, warn, error, fatal (默认 "info") -V 打印版本信息 -addr string drainer 提供服务的地址(默认 "127.0.0.1:8249") -c int 同步下游的并发数,该值设置越高同步的吞吐性能越好 (default 1) -config string 配置文件路径, drainer 会首先读取配置文件的配置 如果对应的配置在命令行参数里面也存在,drainer 就会使用命令行参数的配置来覆盖配置文件里面的 -data-dir string drainer 数据存储位置路径 (默认 "data.drainer") -dest-db-type string drainer 下游服务类型 (默认为 mysql) -detect-interval int 向 pd 查询在线 pump 的时间间隔 (默认 10,单位 秒) -disable-dispatch 是否禁用拆分单个 binlog 的 sqls 的功能,如果设置为 true,则按照每个 binlog 顺序依次还原成单个事务进行同步( 下游服务类型为 mysql, 该项设置为 False ) -gen-savepoint 如果设置为 true, 则只生成 drainer 的 savepoint meta 文件, 可以配合 mydumper 使用 -ignore-schemas string db 过滤列表 (默认 "INFORMATION_SCHEMA,PERFORMANCE_SCHEMA,mysql,test"), 不支持对 ignore schemas 的 table 进行 rename DDL 操作 -log-file string log 文件路径 -log-rotate string log 文件切换频率, hour/day -metrics-addr string prometheus pushgataway 地址,不设置则禁止上报监控信息 -metrics-interval int 监控信息上报频率 (默认 15,单位 秒) -pd-urls string pd 集群节点的地址 (默认 "http://127.0.0.1:2379") -txn-batch int 输出到下游数据库一个事务的 sql 数量 (default 1) Drainer 配置文件# drainer Configuration. # drainer 提供服务的地址(默认 "127.0.0.1:8249") addr = "127.0.0.1:8249" # 向 pd 查询在线 pump 的时间间隔 (默认 10,单位 秒) detect-interval = 10 # drainer 数据存储位置路径 (默认 "data.drainer") data-dir = "data.drainer" # pd 集群节点的地址 (默认 "http://127.0.0.1:2379") pd-urls = "http://127.0.0.1:2379" # log 文件路径 log-file = "drainer.log" # syncer Configuration. [syncer] ## db 过滤列表 (默认 "INFORMATION_SCHEMA,PERFORMANCE_SCHEMA,mysql,test"), ## 不支持对 ignore schemas 的 table 进行 rename DDL 操作 ignore-schemas = "INFORMATION_SCHEMA,PERFORMANCE_SCHEMA,mysql" # 输出到下游数据库一个事务的 sql 数量 (default 1) txn-batch = 1 # 同步下游的并发数,该值设置越高同步的吞吐性能越好 (default 1) worker-count = 1 # 是否禁用拆分单个 binlog 的 sqls 的功能,如果设置为 true,则按照每个 binlog # 顺序依次还原成单个事务进行同步( 下游服务类型为 mysql, 该项设置为 False ) disable-dispatch = false # drainer 下游服务类型 (默认为 mysql) # 参数有效值为 "mysql", "pb" db-type = "mysql" # replicate-do-db priority over replicate-do-table if have same db name # and we support regex expression , # 以 '~' 开始声明使用正则表达式 #replicate-do-db = ["~^b.*","s1"] #[[syncer.replicate-do-table]] #db-name ="test" #tbl-name = "log" #[[syncer.replicate-do-table]] #db-name ="test" #tbl-name = "~^a.*" # db-type 设置为 mysql 时,下游数据库服务器参数 [syncer.to] host = "127.0.0.1" user = "root" password = "" port = 3306 # db-type 设置为 pb 时,存放 binlog 文件的目录 # [syncer.to] # dir = "data.drainer" 启动示例./bin/drainer -config drainer.toml TiDB-Binlog 监控 这部分主要对 TiDB-Binlog 的状态、性能做监控,通过 Prometheus + Grafana 展现 metrics 数据,pump/drainer 配置 使用 ansible 部署的 pump 服务,已经在启动参数设置 metrics 。drainer 启动时可以设置 --metrics-addr 和 --metrics-interval 两个参数,其中 metrics-addr 设为 Push Gateway 的地址,metrics-interval 为 push 的频率,单位为秒,默认值为15Grafana 配置 进入 Grafana Web 界面(默认地址: http://localhost:3000,默认账号: admin 密码: admin)点击 Grafana Logo -> 点击 Data Sources -> 点击 Add data source -> 填写 data source 信息 ( 注: Type 选 Prometheus,Url 为 Prometheus 地址,根据实际情况 添加/填写 ) 导入 dashboard 配置文件点击 Grafana Logo -> 点击 Dashboards -> 点击 Import -> 选择需要的 dashboard 配置文件上传 -> 选择对应的 data source "}, {"url": "https://pingcap.com/docs/tools/lightning/checkpoints/", "title": "TiDB-Lightning Checkpoints", "content": " TiDB-Lightning Checkpoints Importing a large database usually takes hours or days, and if such long running processes spuriously crashes, it can be very time-wasting to redo the previously completed tasks. To solve this, Lightning uses checkpoints to store the import progress, so that tidb-lightning continues importing from where it lefts off after restarting.This document describes how to enable, configure, store, and control checkpoints.Enable and configure checkpoints [checkpoint] # Whether to enable checkpoints. # While importing data, Lightning records which tables have been imported, so # even if Lightning or some other component crashes, you can start from a known # good state instead of redoing everything. enable = true # The schema name (database name) to store the checkpoints schema = "tidb_lightning_checkpoint" # Where to store the checkpoints. # - file: store as a local file (requires v2.1.1 or later) # - mysql: store into a remote MySQL-compatible database driver = "file" # The data source name (DSN) indicating the location of the checkpoint storage. # # For the "file" driver, the DSN is a path. If the path is not specified, Lightning would # default to "/tmp/CHECKPOINT_SCHEMA.pb". # # For the "mysql" driver, the DSN is a URL in the form of "USER:PASS@tcp(HOST:PORT)/". # If the URL is not specified, the TiDB server from the [tidb] section is used to # store the checkpoints. You should specify a different MySQL-compatible # database server to reduce the load of the target TiDB cluster. #dsn = "/tmp/tidb_lightning_checkpoint.pb" # Whether to keep the checkpoints after all data are imported. If false, the # checkpoints are deleted. Keeping the checkpoints can aid debugging but # might leak metadata about the data source. #keep-after-success = false Checkpoints storage Lightning supports two kinds of checkpoint storage: a local file or a remote MySQL-compatible database. With driver = "file", checkpoints are stored in a local file at the path given by the dsn setting. Checkpoints are updated rapidly, so we highly recommend placing the checkpoint file on a drive with very high write endurance, such as a RAM disk. With driver = "mysql", checkpoints can be saved in any databases compatible with MySQL 5.7 or later, including MariaDB and TiDB. By default, the checkpoints are saved in the target database. While using the target database as the checkpoints storage, Lightning is importing large amounts of data at the same time. This puts extra stress on the target database and sometimes leads to communication timeout. Therefore, it is strongly recommended to install a temporary MySQL server to store these checkpoints. This server can be installed on the same host as tidb-lightning and can be uninstalled after the importer progress is completed.Checkpoints control If tidb-lightning exits abnormally due to unrecoverable errors (e.g. data corruption), it refuses to reuse the checkpoints until the errors are resolved. This is to prevent worsening the situation. The checkpoint errors can be resolved using the tidb-lightning-ctl program.--checkpoint-error-destroy tidb-lightning-ctl --checkpoint-error-destroy='`schema`.`table` This option allows you to restart importing the table from scratch. The schema and table names must be quoted with backquotes and are case-sensitive. If importing the table `schema`.`table` failed previously, this option executes the following operations: DROPs the table `schema`.`table` from the target database, which means removing all imported data. Resets the checkpoints record of this table to be “not yet started”. If there is no errors involving the table `schema`.`table`, this operation does nothing. It is the same as applying the above on every table. This is the most convenient, safe and conservative solution to fix the checkpoint error problem:tidb-lightning-ctl --checkpoint-error-destroy=all --checkpoint-error-ignore tidb-lightning-ctl --checkpoint-error-ignore='`schema`.`table`' tidb-lightning-ctl --checkpoint-error-ignore=all If importing the table `schema`.`table` failed previously, this clears the error status as if nothing ever happened. The all variant applies this operation to all tables. Note: Use this option only when you are sure that the error can indeed be ignored. If not, some imported data can be lost. The only safety net is the final “checksum” check, and thus you need to keep the “checksum” option always enabled when using --checkpoint-error-ignore. --checkpoint-remove tidb-lightning-ctl --checkpoint-remove='`schema`.`table`' tidb-lightning-ctl --checkpoint-remove=all This option simply removes all checkpoint information about one table or all tables, regardless of their status.--checkpoint-dump tidb-lightning-ctl --checkpoint-dump=output/directory This option dumps the content of the checkpoint into the given directory, which is mainly used for debugging by the technical staff. This option is only enabled when driver = "mysql"."}, {"url": "https://pingcap.com/docs/tools/lightning/deployment/", "title": "TiDB-Lightning Deployment", "content": " TiDB-Lightning Deployment This document describes the hardware requirements of TiDB-Lightning on separate deployment and mixed deployment, and how to deploy it using Ansible or manually.Notes Before starting TiDB-Lightning, note that: During the import process, the cluster cannot provide normal services. If tidb-lightning crashes, the cluster is left in “import mode”. Forgetting to switch back to “normal mode” can lead to a high amount of uncompacted data on the TiKV cluster, and cause abnormally high CPU usage and stall. You can manually switch the cluster back to “normal mode” via the tidb-lightning-ctl tool:bin/tidb-lightning-ctl -switch-mode=normal Hardware requirements tidb-lightning and tikv-importer are both resource-intensive programs. It is recommended to deploy them into two separate machines. If your hardware resources are limited, you can deploy tidb-lightning and tikv-importer on the same machine.Hardware requirements of separate deployment To achieve the best performance, it is recommended to use the following hardware configuration: tidb-lightning: 32+ logical cores CPU 16 GB+ memory 1 TB+ SSD, preferring higher read speed 10 Gigabit network card tidb-lightning fully consumes all CPU cores when running, and deploying on a dedicated machine is highly recommended. If not possible, tidb-lightning could be deployed together with other components like tidb-server, and the CPU usage could be limited via the region-concurrency setting. tikv-importer: 32+ logical cores CPU 32 GB+ memory 1 TB+ SSD, preferring higher IOPS 10 Gigabit network card tikv-importer fully consumes all CPU, disk I/O and network bandwidth when running, and deploying on a dedicated machine is strongly recommended. If not possible, tikv-importer could be deployed together with other components like tikv-server, but the import speed might be affected. If you have sufficient machines, you can deploy multiple Lightning/Importer servers, with each working on a distinct set of tables, to import the data in parallel.Hardware requirements of mixed deployment If your hardware resources are severely under constraint, it is possible to deploy tidb-lightning and tikv-importer and other components on the same machine, but the import performance is affected.It is recommended to use the following configuration of the single machine: 32+ logical cores CPU 32 GB+ memory 1 TB+ SSD, preferring higher IOPS 10 Gigabit network card Notes: tidb-lightning is a CPU intensive program. In an environment with mixed components, the resources allocated to tidb-lightning must be limited. Otherwise, other components might not be able to run. It is recommended to set the region-concurrency to 75% of CPU logical cores. For instance, if the CPU has 32 logical cores, you can set the region-concurrency to 24. Export data Use the mydumper tool to export data from MySQL by using the following command:./bin/mydumper -h 127.0.0.1 -P 3306 -u root -t 16 -F 256 -B test -T t1,t2 --skip-tz-utc -o /data/my_database/ In this command, -B test: means the data is exported from the test database. -T t1,t2: means only the t1 and t2 tables are exported. -t 16: means 16 threads are used to export the data. -F 256: means a table is partitioned into chunks and one chunk is 256 MB. --skip-tz-utc: the purpose of adding this parameter is to ignore the inconsistency of time zone setting between MySQL and the data exporting machine, and to disable automatic conversion. Deploy TiDB-Lightning This section describes two deployment methods of TiDB-Lightning: Deploy TiDB-Lightning using Ansible Deploy TiDB-Lightning manually Deploy TiDB-Lightning using Ansible You can deploy TiDB-Lightning using Ansible together with the deployment of the TiDB cluster itself using Ansible. Edit inventory.ini to add the addresses of the tidb-lightning and tikv-importer servers.... [importer_server] 192.168.20.9 [lightning_server] 192.168.20.10 ... Configure these tools by editing the settings under group_vars/*.yml. group_vars/all.yml... # The listening port of tikv-importer. Should be open to the tidb-lightning server. tikv_importer_port: 20170 ... group_vars/lightning_server.yml--- dummy: # The listening port for metrics gathering. Should be open to the monitoring servers. tidb_lightning_pprof_port: 10089 # The file path that tidb-lightning reads the mydumper SQL dump from. data_source_dir: "{{ deploy_dir }}/mydumper" group_vars/importer_server.yml--- dummy: # The file path to store engine files. Should reside on a partition with a large capacity. import_dir: "{{ deploy_dir }}/data.import" Deploy the cluster.ansible-playbook bootstrap.yml ansible-playbook deploy.yml Mount the data source to the path specified in the data_source_dir setting. Log in to the tikv-importer server, and manually run the following command to start Importer.scripts/start_importer.sh Log in to the tidb-lightning server, and manually run the following command to start Lightning and import the data into the TiDB cluster.scripts/start_lightning.sh After completion, run scripts/stop_importer.sh on the tikv-importer server to stop Importer. Deploy TiDB-Lightning manually Step 1: Deploy a TiDB cluster Before importing data, you need to have a deployed TiDB cluster, with the cluster version 2.0.9 or above. It is highly recommended to use the latest version.You can find deployment instructions in TiDB Quick Start Guide.Step 2: Download the TiDB-Lightning installation package Download the TiDB-Lightning package (choose the same version as that of the TiDB cluster): v2.1.2: https://download.pingcap.org/tidb-lightning-v2.1.2-linux-amd64.tar.gz v2.0.9: https://download.pingcap.org/tidb-lightning-v2.0.9-linux-amd64.tar.gz Latest unstable version: https://download.pingcap.org/tidb-lightning-latest-linux-amd64.tar.gz Step 3: Start tikv-importer Upload bin/tikv-importer from the installation package. Configure tikv-importer.toml.# TiKV Importer configuration file template # Log file log-file = "tikv-importer.log" # Log level: trace, debug, info, warn, error, off. log-level = "info" [server] # The listening address of tikv-importer. tidb-lightning needs to connect to # this address to write data. addr = "0.0.0.0:20170" # Size of the thread pool for the gRPC server. grpc-concurrency = 16 [metric] # The Prometheus client push job name. job = "tikv-importer" # The Prometheus client push interval. interval = "15s" # The Prometheus Pushgateway address. address = "" [rocksdb] # The maximum number of concurrent background jobs. max-background-jobs = 32 [rocksdb.defaultcf] # Amount of data to build up in memory before flushing data to the disk. write-buffer-size = "1GB" # The maximum number of write buffers that are built up in memory. max-write-buffer-number = 8 # The compression algorithms used in different levels. # The algorithm at level-0 is used to compress KV data. # The algorithm at level-6 is used to compress SST files. # The algorithms at level-1 to level-5 are unused for now. compression-per-level = ["lz4", "no", "no", "no", "no", "no", "zstd"] [import] # The directory to store engine files. import-dir = "/tmp/tikv/import" # Number of threads to handle RPC requests. num-threads = 16 # Number of concurrent import jobs. num-import-jobs = 24 # Maximum duration to prepare Regions. #max-prepare-duration = "5m" # Split Regions into this size according to the importing data. #region-split-size = "96MB" # Stream channel window size. The stream will be blocked on channel full. #stream-channel-window = 128 # Maximum number of open engines. max-open-engines = 8 Run tikv-importer.nohup ./tikv-importer -C tikv-importer.toml > nohup.out & Step 4: Start tidb-lightning Upload bin/tidb-lightning and bin/tidb-lightning-ctl from the tool set. Mount the mydumper SQL dump onto the same machine. Configure …"}, {"url": "https://pingcap.com/docs/tools/lightning/faq/", "title": "TiDB-Lightning FAQ", "content": " TiDB-Lightning FAQ What is the minimum TiDB/TiKV/PD cluster version supported by Lightning? The minimum version is 2.0.9.Does Lightning support importing multiple schemas (databases)? Yes.What is the privilege requirements for the target database? Lightning requires the following privileges: SELECT UPDATE ALTER CREATE DROP If the target database is used to store checkpoints, it additionally requires these privileges: INSERT DELETE Lightning encountered an error when importing one table. Will it affect other tables? Will the process be terminated? If only one table has an error encountered, the rest will still be processed normally.How to ensure the integrity of the imported data? Lightning by default performs checksum on the local data source and the imported tables. If there is checksum mismatch, the process would be aborted. These checksum information can be read from the log.You could also execute the ADMIN CHECKSUM TABLE SQL command on the target table to recompute the checksum of the imported data.mysql> ADMIN CHECKSUM TABLE `schema`.`table`; +---------+------------+---------------------+-----------+-------------+ | Db_name | Table_name | Checksum_crc64_xor | Total_kvs | Total_bytes | +---------+------------+---------------------+-----------+-------------+ | schema | table | 5505282386844578743 | 3 | 96 | +---------+------------+---------------------+-----------+-------------+ 1 row in set (0.01 sec) What kind of data source format is supported by Lightning? In version 2.1.0, TiDB-Lightning only supports the SQL dump generated by mydumper stored in the local filesystem.Could Lightning skip creating schema and tables? Yes. If you have already created the tables in the target database, you could set no-schema = true in the [data-source] section in tidb-lightning.toml. This makes Lightning skip the CREATE TABLE invocations and fetch the metadata directly from the target database. Lightning will exit with error if a table is actually missing.Can the Strict SQL Mode be disabled to allow importing invalid data? Yes. By default, the sql_mode used by Lightning is "STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION", which disallows invalid data such as the date 1970-00-00. The mode can be changed by modifying the sql-mode setting in the [tidb] section in tidb-lightning.toml.... [tidb] sql-mode = "" ... Can one tikv-importer serve multiple tidb-lightning instances? Yes, as long as every tidb-lightning instance operates on different tables.How to stop tikv-importer? If it is deployed using TiDB-Ansible, run scripts/stop_importer.sh under the deployed folder.Otherwise, obtain the process ID with ps aux | grep tikv-importer, and then run kill «pid».How to stop tidb-lightning? If it is deployed using TiDB-Ansible, run scripts/stop_lightning.sh under the deployed folder.If tidb-lightning is running in foreground, simply press Ctrl+C to stop it.Otherwise, obtain the process ID with ps aux | grep tidb-importer, then run kill -2 «pid».Why tidb-lightning suddenly quits while running in background? It is potentially caused by starting tidb-lightning incorrectly, which causes the system to send a SIGHUP signal to stop it. If this is the case, there should be a log entry like:2018/08/10 07:29:08.310 main.go:47: [info] Got signal hangup to exit. We do not recommend using nohup directly in the command line. Rather, put the nohup inside a script file and execute the script.Why my TiDB cluster is using lots of CPU resources and running very slowly after using Lightning? If tidb-lightning abnormally exited, the cluster might be stuck in the “import mode”, which is not suitable for production. You can force the cluster back to “normal mode” using the following command:tidb-lightning-ctl --switch-mode=normal"}, {"url": "https://pingcap.com/docs/tools/lightning/monitor/", "title": "TiDB-Lightning Monitoring", "content": " TiDB-Lightning Monitoring Both tidb-lightning and tikv-importer supports metrics collection via Prometheus. This document introduces the monitor configuration and monitoring metrics of TiDB-Lightning.Monitor configuration If TiDB-Lightning is installed using TiDB-Ansible, simply add the servers to the [monitored_servers] section in the inventory.ini. Then the Prometheus server can collect their metrics. If TiDB-Lightning is manually installed, follow the instructions below. tikv-importer tikv-importer v2.1 uses Pushgateway to deliver metrics. Configure tikv-importer.toml to recognize the Pushgateway with the following settings:[metric] # The Prometheus client push job name. job = "tikv-importer" # The Prometheus client push interval. interval = "15s" # The Prometheus Pushgateway address. address = "" tidb-lightning The metrics of tidb-lightning can be gathered directly by Prometheus as long as it is discovered. You can set the metrics port in tidb-lightning.toml:[lightning] # HTTP port for debugging and Prometheus metrics pulling (0 to disable) pprof-port = 10089 ... You need to configure Prometheus to make it discover the tidb-lightning server. For instance, you can directly add the server address to the scrape_configs section:... scrape_configs: - job_name: 'tidb-lightning' static_configs: - targets: ['192.168.20.10:10089'] Monitoring metrics This section explains the monitoring metrics of tikv-importer and tidb-lightning.tikv-importer Metrics provided by tikv-importer are listed under the namespace tikv_import_*. tikv_import_rpc_duration (Histogram)Bucketed histogram of importing RPC duration. Labels: request: RPC name, e.g. open_engine, import_engine, etc. result: ok / error tikv_import_write_chunk_bytes (Histogram)Bucketed histogram of importing write chunk bytes. tikv_import_write_chunk_duration (Histogram)Bucketed histogram of importing write chunk duration. tikv_import_upload_chunk_bytes (Histogram)Bucketed histogram of importing upload chunk bytes. tikv_import_upload_chunk_duration (Histogram)Bucketed histogram of importing upload chunk duration. tidb-lightning Metrics provided by tidb-lightning are listed under the namespace lightning_*. lightning_importer_engine (Counter)Counting open and closed engine files. Labels: type: open / closed lightning_idle_workers (Gauge)Counting idle workers. Values should be less than the table-concurrency/region-concurrency settings and are typically zero. Labels: name: table / region lightning_kv_encoder (Counter)Counting open and closed KV encoders. KV encoders are in-memory TiDB instances that convert SQL INSERT statements into KV pairs. The net values need to be bounded in a healthy situation. Labels: type: open / closed lightning_tables (Counter)Counting number of tables processed and their status. Labels: state: pending / written / closed / imported / altered_auto_inc / checksum / analyzed / completed result: success / failure lightning_chunks (Counter)Counting number of chunks processed and their status. Labels: state: estimated / pending / running / finished / failed lightning_import_seconds (Histogram)Bucketed histogram of the time needed to import a table. lightning_block_read_seconds (Histogram)Bucketed histogram of the time needed to read a block of SQL rows from the data source. lightning_block_read_bytes (Histogram)Bucketed histogram of the size of a block of SQL rows. lightning_block_encode_seconds (Histogram)Bucketed histogram of the time needed to encode a block of SQL rows into KV pairs. lightning_block_deliver_seconds (Histogram)Bucketed histogram of the time needed to deliver a block of KV pairs. lightning_block_deliver_bytes (Histogram)Bucketed histogram of the size of a block of KV pairs. lightning_checksum_seconds (Histogram)Bucketed histogram of the time taken to compute the checksum of a table. "}, {"url": "https://pingcap.com/docs/tools/lightning/overview-architecture/", "title": "TiDB-Lightning Overview", "content": " TiDB-Lightning Overview TiDB-Lightning is a tool used for fast full import of large amounts of data into a TiDB cluster. Currently, TiDB-Lightning supports reading SQL dump exported via mydumper. You can use it in the following two scenarios: Importing large amounts of new data quickly Back up and restore all the data TiDB-Lightning architecture The TiDB-Lightning tool set consists of two components: tidb-lightning (the “front end”) reads the SQL dump and imports the database structure into the TiDB cluster, and also transforms the data into Key-Value (KV) pairs and sends them to tikv-importer. tikv-importer (the “back end”) combines and sorts the KV pairs and then imports these sorted pairs as a whole into the TiKV cluster. The complete import process is as follows: Before importing, tidb-lightning switches the TiKV cluster to “import mode”, which optimizes the cluster for writing and disables automatic compaction. tidb-lightning creates the skeleton of all tables from the data source. For each table, tidb-lightning informs tikv-importer via gRPC to create an engine file to store KV pairs. tidb-lightning then reads the SQL dump in parallel, transforms the data into KV pairs according to the TiDB rules, and sends them to tikv-importer’s engine files. Once a full table of KV pairs are received, tikv-importer divides and schedules these data and imports them into the target TiKV cluster. tidb-lightning then performs a checksum comparison between the local data source and those calculated from the cluster, to ensure there is no data corruption in the process, and tells TiDB to ANALYZE all imported tables, to prepare for optimal query planning. After all tables are imported, tidb-lightning performs a global compaction on the TiKV cluster. Finally, tidb-lightning switches the TiKV cluster back to “normal mode”, so the cluster resumes normal services. "}, {"url": "https://pingcap.com/docs/tools/lightning/filter/", "title": "TiDB-Lightning Table Filter", "content": " TiDB-Lightning Table Filter TiDB-Lightning supports setting up black and white lists to ignore certain databases and tables. This can be used to skip cache tables, or manually partition the data source on a shared storage to allow multiple Lightning instances work together without interfering each other.The filtering rule is similar to MySQL replication-rules-db/replication-rules-table.Filtering databases [black-white-list] do-dbs = ["pattern1", "pattern2", "pattern3"] ignore-dbs = ["pattern4", "pattern5"] If the do-dbs array in the [black-white-list] section is not empty, If the name of a database matches any pattern in the do-dbs array, the database is included. Otherwise, the database is skipped. Otherwise, if the name matches any pattern in the ignore-dbs array, the database is skipped. If a database’s name matches both the do-dbs and ignore-dbs arrays, the database is included. The pattern can either be a simple name, or a regular expression in Go dialect if it starts with a ~ character.Filtering tables [[black-white-list.do-tables]] db-name = "db-pattern-1" table-name = "table-pattern-1" [[black-white-list.do-tables]] db-name = "db-pattern-2" table-name = "table-pattern-2" [[black-white-list.do-tables]] db-name = "db-pattern-3" table-name = "table-pattern-3" [[black-white-list.ignore-tables]] db-name = "db-pattern-4" table-name = "table-pattern-4" [[black-white-list.ignore-tables]] db-name = "db-pattern-5" table-name = "table-pattern-5" If the do-tables array is not empty, If the qualified name of a table matched any pair of patterns in the do-tables array, the table is included. Otherwise, the table is skipped Otherwise, if the qualified name matched any pair of patterns in the ignore-tables array, the table is skipped. If a table’s qualified name matched both the do-tables and ignore-tables arrays, the table is included. Note that the database filtering rules are applied before Lightning considers the table filtering rules. This means if a database is ignored by ignore-dbs, all tables inside this database are not considered even if they matches any do-tables array.Example To illustrate how these rules work, suppose the data source contains the following tables:`logs`.`messages_2016` `logs`.`messages_2017` `logs`.`messages_2018` `forum`.`users` `forum`.`messages` `forum_backup_2016`.`messages` `forum_backup_2017`.`messages` `forum_backup_2018`.`messages` `admin`.`secrets` Using this configuration:[black-white-list] do-dbs = [ "forum_backup_2018", # rule A "~^(logs|forum)$", # rule B ] ignore-dbs = [ "~^forum_backup_", # rule C ] [[black-white-list.do-tables]] # rule D db-name = "logs" table-name = "~_2018$" [[black-white-list.ignore-tables]] # rule E db-name = "~.*" table-name = "~^messages.*" [[black-white-list.do-tables]] # rule F db-name = "~^forum.*" table-name = "messages" First apply the database rules: Database Outcome `logs` Included by rule B `forum` Included by rule B `forum_backup_2016` Skipped by rule C `forum_backup_2017` Skipped by rule C `forum_backup_2018` Included by rule A (rule C will not apply) `admin` Skipped since do-dbs is not empty and this does not match any pattern Then apply the table rules: Table Outcome `logs`.`messages_2016` Skipped by rule E `logs`.`messages_2017` Skipped by rule E `logs`.`messages_2018` Included by rule D (rule E will not apply) `forum`.`users` Skipped, since do-tables is not empty and this does not match any pattern `forum`.`messages` Included by rule F (rule E will not apply) `forum_backup_2016`.`messages` Skipped, since database is already skipped `forum_backup_2017`.`messages` Skipped, since database is already skipped `forum_backup_2018`.`messages` Included by rule F (rule E will not apply) `admin`.`secrets` Skipped, since database is already skipped "}, {"url": "https://pingcap.com/docs/tools/lightning/errors/", "title": "TiDB-Lightning Troubleshooting", "content": " TiDB-Lightning Troubleshooting When Lightning encounters an unrecoverable error, it exits with nonzero exit code and leaves the reason in the log file. Errors are typically printed at the end of the log. You can also search for the string [error] to look for non-fatal errors.This document summarizes some commonly encountered errors in the tidb-lightning log file and their solutions.Import speed is too slow Normally it takes Lightning 2 minutes per thread to import a 256 MB Chunk. It is an error if the speed is much slower than this. The time taken for each chunk can be checked from the log mentioning restore chunk … takes. This can also be observed from metrics on Grafana.There are several reasons why Lightning becomes slow:Cause 1: region-concurrency is too high, which causes thread contention and reduces performance. The setting can be found from the start of the log by searching region-concurrency. If Lightning shares the same machine with other services (e.g. Importer), region-concurrency must be manually set to 75% of the total number of CPU cores If there is a quota on CPU (e.g. limited by K8s settings), Lightning may not be able to read this out. In this case, region-concurrency must also be manually reduced. Cause 2: The table is too complex.Every additional index will introduce a new KV pair for each row. If there are N indices, the actual size to be imported would be approximately (N+1) times the size of the mydumper output. If the indices are negligible, you may first remove them from the schema, and add them back via CREATE INDEX after import is complete.Cause 3: Lightning is too old.Try the latest version! Maybe there is new speed improvement.checksum failed: checksum mismatched remote vs local Cause: The checksum of a table in the local data source and the remote imported database differ. This error has several deeper reasons: The table might already have data before. These old data can affect the final checksum. If the table does not have an integer PRIMARY KEY, some rows might be imported repeatedly between checkpoints. This is a known bug to be fixed in the next release. If the remote checksum is 0, which means nothing is imported, it is possible that the cluster is too hot and fails to take in any data. If the data is mechanically generated, ensure it respects the constrains of the table: AUTO_INCREMENT columns need to be positive, and do not contain the value “0”. The UNIQUE and PRIMARY KEYs must have no duplicated entries. Solutions: Delete the corrupted data with tidb-lightning-ctl --error-checkpoint-destroy=all, and restart Lightning to import the affected tables again. Consider using an external database to store the checkpoints (change [checkpoint] dsn) to reduce the target database’s load. ResourceTemporarilyUnavailable(“Too many open engines …: 8”) Cause: The number of concurrent engine files exceeds the limit imposed by tikv-importer. This could be caused by misconfiguration. Additionally, if tidb-lightning exited abnormally, an engine file might be left at a dangling open state, which could cause this error as well.Solutions: Increase the value of max-open-engine setting in tikv-importer.toml. This value is typically dictated by the available memory. This could be calculated as:Max Memory Usage ≈ max-open-engine × write-buffer-size × max-write-buffer-number Decrease the value of table-concurrency so it is less than max-open-engine. Restart tikv-importer to forcefully remove all engine files. This also removes all partially imported tables, thus it is required to run tidb-lightning-ctl --error-checkpoint-destroy=all. cannot guess encoding for input file, please convert to UTF-8 manually Cause: Lightning only recognizes the UTF-8 and GB-18030 encodings for the table schemas. This error is emitted if the file isn’t in any of these encodings. It is also possible that the file has mixed encoding, such as containing a string in UTF-8 and another string in GB-18030, due to historical ALTER TABLE executions.Solutions: Fix the schema so that the file is entirely in either UTF-8 or GB-18030. Manually CREATE the affected tables in the target database, and then set [mydumper] no-schema = true to skip automatic table creation. Set [mydumper] character-set = "binary" to skip the check. Note that this might introduce mojibake into the target database. [sql2kv] sql encode error = [types:1292]invalid time format: ‘{1970 1 1 0 45 0 0}’ Cause: A table contains a column with the timestamp type, but the time value itself does not exist. This is either because of DST changes or the time value has exceeded the supported range (1970 Jan 1st to 2038 Jan 19th).Solutions: Ensure Lightning and the source database are using the same time zone. Lightning’s time zone can be forced using the $TZ environment variable.# Ansible deployment, and force UTC. TZ=UTC scripts/start_lightning.sh # Manual deployment, and force Asia/Shanghai. TZ='Asia/Shanghai' bin/tidb-lightning -config tidb-lightning.toml When exporting data using mydumper, make sure to include the --skip-tz-utc flag. "}, {"url": "https://pingcap.com/docs-cn/tools/lightning/faq/", "title": "TiDB-Lightning 常见问题", "content": " TiDB-Lightning 常见问题 Lightning 对 TiDB/TiKV/PD 的最低版本要求是多少? 最低版本要求是 2.0.9。Lightning 支持导入多个库吗? 支持。Lightning 对下游数据库的账号权限要求是怎样的? Lightning 需要以下权限: SELECT UPDATE ALTER CREATE DROP 另外,存储断点的数据库额外需要以下权限: INSERT DELETE Lightning 在导数据过程中某个表报错了,会影响其他表吗?进程会马上退出吗? 如果只是个别表报错,不会影响整体。报错的那个表会停止处理,继续处理其他的表。如何校验导入的数据的正确性? Lightning 默认会对导入数据计算校验和 (checksum),如果校验和不一致就会停止导入该表。可以在日志看到相关的信息。TiDB 也支持从 MySQL 命令行运行 ADMIN CHECKSUM TABLE 指令来计算校验和。mysql> ADMIN CHECKSUM TABLE `schema`.`table`; +---------+------------+---------------------+-----------+-------------+ | Db_name | Table_name | Checksum_crc64_xor | Total_kvs | Total_bytes | +---------+------------+---------------------+-----------+-------------+ | schema | table | 5505282386844578743 | 3 | 96 | +---------+------------+---------------------+-----------+-------------+ 1 row in set (0.01 sec) Lightning 支持哪些格式的数据源? 到 v2.1.0 版本为止,只支持本地文档形式的数据源,支持 mydumper 格式。我已经在下游创建好库和表了,Lightning 可以忽略建库建表操作吗? 可以。在配置文档中的 [data-source] 将 no-schema 设置为 true 即可。no-schema=true 会默认下游已经创建好所需的数据库和表,如果没有创建,会报错。有些不合法的数据,能否通过关掉严格 SQL 模式 (Strict SQL MOde) 来导入? 可以。Lightning 默认的 sql_mode 为 "STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION"。这个设置不允许一些非法的数值,例如 1970-00-00 这样的日期。可以修改配置文件 [tidb] 下的 sql-mode 值。... [tidb] sql-mode = "" ... 可以起一个 tikv-importer,同时有多个 tidb-lightning 进程导入数据吗? 只要每个 Lightning 操作的表互不相同就可以。如何正确关闭 tikv-importer 进程? 如使用 TiDB-Ansible 部署,在 Importer 的服务器上运行 scripts/stop_importer.sh 即可。否则,可通过 ps aux | grep tikv-importer 获取进程ID,然后 kill «pid»。如何正确关闭 tidb-lightning 进程? 如使用 TiDB-Ansible 部署,在 Lightning 的服务器上运行 scripts/stop_lightning.sh 即可。如果 tidb-lightning 正在前台运行,可直接按 Ctrl+C 退出。否则,可通过 ps aux | grep tidb-lightning 获取进程 ID,然后 kill -2 «pid»。进程在服务器上运行,进程莫名其妙地就退出了,是怎么回事呢? 这种情况可能是启动方式不正确,导致因为收到 SIGHUP 信号而退出,此时 tidb-lightning.log 通常有这幺一行日志:2018/08/10 07:29:08.310 main.go:47: [info] Got signal hangup to exit. 不推荐直接在命令行中使用 nohup 启动进程,而应该把 nohup 这行命令放到一个脚本中运行。为什么用过 Lightning 之后,TiDB 集群变得又慢又耗 CPU? 如果 tidb-lightning 曾经异常退出,集群可能仍留在“导入模式” (import mode),不适合在生产环境工作。此时需要强制切换回“普通模式” (normal mode):tidb-lightning-ctl --switch-mode=normal"}, {"url": "https://pingcap.com/docs-cn/tools/lightning/checkpoints/", "title": "TiDB-Lightning 断点续传", "content": " TiDB-Lightning 断点续传 大量的数据导入一般耗时数小时至数天,长时间运行的进程会有一定机率发生非正常中断。如果每次重启都从头开始, 就会浪费掉之前已成功导入的数据。为此,Lightning 提供了“断点续传”的功能,即使 tidb-lightning 崩溃,在重启时仍然接着之前的进度继续工作。本文主要介绍 TiDB-Lightning 断点续传的启用与配置、断点的存储,以及断点续传的控制。断点续传的启用与配置 [checkpoint] # 启用断点续传。 # 导入时,Lightning 会记录当前进度。 # 若 Lightning 或其他组件异常退出,在重启时可以避免重复再导入已完成的数据。 enable = true # 存储断点的架构名称(数据库名称) schema = "tidb_lightning_checkpoint" # 存储断点的数据库连接参数 (DSN),格式为“用户:密码@tcp(地址:端口)”。 # 默认会重用 [tidb] 设置目标数据库来存储断点。 # 为避免加重目标集群的压力,建议另外使用一个兼容 MySQL 的数据库服务器。 #dsn = "root@tcp(127.0.0.1:4000)/" # 导入成功后是否保留断点。默认为删除。 # 保留断点可用于调试,但有可能泄漏数据源的元数据。 #keep-after-success = false 断点的存储 Lightning 的断点可以存放在任何兼容 MySQL 5.7 或以上的数据库中,包括 MariaDB 和 TiDB。在没有选择的情况下,默认会存在目标数据库里。目标数据库在导入期间会有大量的操作,若使用目标数据库来存储断点会加重其负担,甚至有可能造成通信超时丢失数据。因此,强烈建议另外部署一台兼容 MySQL 的临时数据库服务器。此数据库也可以安装在 tidb-lightning 的主机上。导入完毕后可以删除。断点续传的控制 若 tidb-lightning 因不可恢复的错误而退出(例如数据出错),重启时不会使用断点,而是直接报错离开。为保证已导入的数据安全,这些错误必须先解决掉才能继续。使用 tidb-lightning-ctl 工具可以标示已经恢复。--checkpoint-error-destroy tidb-lightning-ctl --checkpoint-error-destroy='`schema`.`table` 该命令会让失败的表从头开始整个导入过程。选项中的架构和表名必须以反引号 (`) 包裹,而且区分大小写。 如果导入 `schema`.`table` 这个表曾经出错,这条命令会: 从目标数据库移除 (DROP) 这个表,清除已导入的数据。 将断点重设到“未开始”的状态。 如果 `schema`.`table` 没有出错,则无操作。 传入 “all” 会对所有表进行上述操作。这是最方便、安全但保守的断点错误解决方法:tidb-lightning-ctl --checkpoint-error-destroy=all --checkpoint-error-ignore tidb-lightning-ctl --checkpoint-error-ignore='`schema`.`table`' tidb-lightning-ctl --checkpoint-error-ignore=all 如果导入 `schema`.`table` 这个表曾经出错,这条命令会清除出错状态,如同没事发生过一样。传入 “all” 会对所有表进行上述操作。 注意:除非确定错误可以忽略,否则不要使用这个选项。如果错误是真实的话,可能会导致数据不完全。启用校验和 (CHECKSUM) 可以防止数据出错被忽略。 --checkpoint-remove tidb-lightning-ctl --checkpoint-remove='`schema`.`table`' tidb-lightning-ctl --checkpoint-remove=all 无论是否有出错,把表的断点清除。--checkpoint-dump tidb-lightning-ctl --checkpoint-dump=output/directory 将所有断点备份到传入的文件夹,主要用于技术支持。"}, {"url": "https://pingcap.com/docs-cn/tools/lightning/monitor/", "title": "TiDB-Lightning 监控告警", "content": " TiDB-Lightning 监控告警 TiDB-Lightning 支持给 Prometheus 采集监控指标 (metrics)。本文主要介绍 TiDB-Lightning 的监控配置与监控指标。监控配置 如果是使用 TiDB-Ansible 部署 Lightning,只要将服务器地址加到 inventory.ini 里的 [monitored_servers] 部分即可。 如果是手动部署 Lightning,则参照以下步骤进行配置。 tikv-importer tikv-importer v2.1 使用 Pushgateway 来推送监控指标。需要配置 tikv-importer.toml 来连接 Pushgateway:[metric] # 给 Prometheus 客户端的推送任务名称。 job = "tikv-importer" # 给 Prometheus 客户端的推送间隔。 interval = "15s" # Prometheus Pushgateway 地址。 address = "" tidb-lightning 只要 Prometheus 能发现 tidb-lightning 的监控地址,就能收集监控指标。监控的端口可在 tidb-lightning.toml 中配置:[lightning] # 用于调试和 Prometheus 监控的 HTTP 端口。输入 0 关闭。 pprof-port = 10089 ... 要让 Prometheus 发现 Lightning,可以将地址直接写入其配置文件,例如:... scrape_configs: - job_name: 'tidb-lightning' static_configs: - targets: ['192.168.20.10:10089'] 监控指标 本节详细描述 tikv-importer 和 tidb-lightning 的监控指标。tikv-importer tikv-importer 的监控指标皆以 tikv_import_* 为前缀。 tikv_import_rpc_duration(直方图)导入 RPC 需时的直方图。标签: request:RPC 名称,如 open_engine、import_engine 等 result:ok / error tikv_import_write_chunk_bytes(直方图)从 tidb-lightning 写入每个区块大小的直方图。 tikv_import_write_chunk_duration(直方图)从 tidb-lightning 写入每个区块需时直方图。 tikv_import_upload_chunk_bytes(直方图)上传到 TiKV 的每个区块大小的直方图。 tikv_import_upload_chunk_duration(直方图)上传到 TiKV 的每个区块需时的直方图。 tidb-lightning tidb-lightning 的监控指标皆以 lightning_* 为前缀。 lightning_importer_engine(计数器)计算已开启及关闭的引擎文档数量。标签: type:open / closed lightning_idle_workers(测量仪)计算闲置的工作流程。数值应低于 table-concurrency/region-concurrency,而经常为零。标签: name:table / region lightning_kv_encoder(计数器)计算已开启及关闭的 KV 编码器。KV 编码器是运行于内存的 TiDB 实例,用于将 SQL 的 INSERT 语句转换成 KV 对。此度量的净值(开启减掉关闭)在正常情况下不应持续增长。标签: type:open / closed lightning_tables(计数器)计算处理过的表及其状态。标签: state:pending / written / closed / imported / altered_auto_inc / checksum / completed result:success / failure lightning_chunks(计数器)计算处理过的 Chunks 及其状态。标签: state:estimated / pending / running / finished / failed "}, {"url": "https://pingcap.com/docs-cn/tools/lightning/overview-architecture/", "title": "TiDB-Lightning 简介", "content": " TiDB-Lightning 简介 TiDB-Lightning 是一个将全量数据高速导入到 TiDB 集群的工具,有以下两个主要的使用场景:一是大量新数据的快速导入;二是全量数据的备份恢复。目前,支持 mydumper 输出格式的数据源。TiDB-Lightning 整体架构 TiDB-Lightning 主要包含两个部分: tidb-lightning(“前端”):主要完成适配工作,通过读取 SQL dump,在下游 TiDB 集群建表、将数据转换成键/值对 (KV 对) 发送到 tikv-importer、检查数据完整性等。 tikv-importer(“后端”):主要完成将数据导入 TiKV 集群的工作,把 tidb-lightning 写入的 KV 对缓存、排序、切分并导入到 TiKV 集群。 TiDB-Lightning 整体工作原理如下: 在导数据之前,tidb-lightning 会自动将 TiKV 集群切换为“导入模式” (import mode),优化写入效率并停止自动压缩 (compaction)。 tidb-lightning 会在目标数据库建立架构和表,并获取其元数据。 tidb-lightning 会通过 gRPC 让 tikv-importer 为每一张表准备一个“引擎文件 (engine file)”来处理 KV 对。tidb-lightning 会并发读取 SQL dump,将数据源转换成与 TiDB 相同编码的 KV 对,然后发送到 tikv-importer 里对应的引擎文件。 当一整个表完全导入到 tikv-importer,它便开始对目标 TiKV 集群数据进行分裂和调度,然后导入数据到 TiKV 集群。 之后,tidb-lightning 会对比本地数据源及下游集群的校验和 (checksum),确保导入的数据无损。 整个数据库完成导入后,tidb-lightning 便会让 TiKV 集群进行一次全局压缩,以及让 TiDB 分析 (ANALYZE) 这些新增的数据,以优化日后的操作。 在所有步骤完毕后,tidb-lightning 自动将 TiKV 切换回“普通模式” (normal mode),此后 TiDB 集群可以正常对外提供服务。 "}, {"url": "https://pingcap.com/docs-cn/tools/lightning/deployment/", "title": "TiDB-Lightning 部署与执行", "content": " TiDB-Lightning 部署与执行 本文主要介绍 TiDB-Lightning 单独部署与混合部署的硬件需求,Ansible 部署与手动部署这两种部署方式,以及启动与执行。注意事项 在使用 TiDB-Lightning 前,需注意以下事项: TiDB-Lightning 运行后,TiDB 集群将无法正常对外提供服务。 若 tidb-lightning 崩溃,集群会留在“导入模式”。若忘记转回“普通模式”,集群会产生大量未压缩的文件,继而消耗 CPU 并导致迟延 (stall)。此时,需要使用 tidb-lightning-ctl 手动将集群转回“普通模式”:bin/tidb-lightning-ctl -switch-mode=normal 硬件需求 tidb-lightning 和 tikv-importer 这两个组件皆为资源密集程序,建议各自单独部署。如果资源有限,可以将 tidb-lightning 和 tikv-importer 混合部署在同一台机器上。单独部署的硬件配置 为了优化效能,使用单独部署建议的硬件配置如下: tidb-lightning 32+ 逻辑核 CPU 16 GB+ 内存 1 TB+ SSD 硬盘,读取速度越快越好 使用万兆网卡 运行过程默认会打满 CPU,建议单独部署。条件不允许的情况下可以和其他组件 (比如 tidb-server) 部署在同一台机器上,然后通过配置 region-concurrency 限制 tidb-lightning 的 CPU 使用。 tikv-importer 32+ 逻辑核 CPU 32 GB+ 内存 1 TB+ SSD 硬盘,IOPS 越高越好 使用万兆网卡 运行过程中 CPU、I/O 和网络带宽都可能打满,建议单独部署。条件不允许的情况下可以和其他组件(比如 tikv-server)部署在同一台机器上,但可能会影响导入速度。 如果机器充裕的话,可以部署多套 tidb-lightning + tikv-importer,然后将源数据以表为粒度进行切分,并发导入。混合部署的硬件配置 如果条件有限,可以将 tidb-lightning 和 tikv-importer(也可以是其他程序)混合部署在同一台机器上,但这样会影响导入速度。使用混合部署建议的硬件配置如下: 32+ 逻辑核 CPU 32 GB+ 内存 1 TB+ SSD 硬盘,IOPS 越高越好 使用万兆网卡 注意:tidb-lightning 是 CPU 密集型程序,如果和其它程序混合部署,需要通过 region-concurrency 限制 tidb-lightning 的 CPU 实际占用核数,否则会影响其他程序的正常运行。建议将混合部署机器上 75% 的 CPU 分配给 tidb-lightning。例如,机器为 32 核,则 tidb-lightning 的 region-concurrency 可设为 24。 部署 TiDB-Lightning 本节介绍 TiDB-Lightning 的两种部署方式:使用 Ansible 部署和手动部署。使用 Ansible 部署 TiDB-Lightning TiDB-Lightning 可随 TiDB 集群一起用 Ansible 部署。 编辑 inventory.ini,分别配置一个 IP 来部署 tidb-lightning 和 tikv-importer。... [importer_server] 192.168.20.9 [lightning_server] 192.168.20.10 ... 修改 group_vars/*.yml 的变量配置这两个工具。 group_vars/all.yml... # tikv-importer 的监听端口。需对 tidb-lightning 服务器开放。 tikv_importer_port: 20170 ... group_vars/lightning_server.yml--- dummy: # 提供监控告警的端口。需对监控服务器 (monitoring_server) 开放。 tidb_lightning_pprof_port: 10089 # 获取 mydumper SQL dump 的路径。 data_source_dir: "{{ deploy_dir }}/mydumper" group_vars/importer_server.yml--- dummy: # 储存引擎文件的路径。需存放在空间足够大的分区。 import_dir: "{{ deploy_dir }}/data.import" 开始部署。ansible-playbook bootstrap.yml ansible-playbook deploy.yml 将数据源写入 data_source_dir 指定的路径。 登录 tikv-importer 的服务器,并执行以下命令来启动 Importer。scripts/start_importer.sh 登录 tidb-lightning 的服务器,并执行以下命令来启动 Lightning,开始导入过程。scripts/start_lightning.sh 完成后,在 tikv-importer 的服务器执行 scripts/stop_importer.sh 来关闭 Importer。 手动部署 TiDB-Lightning 第 1 步:部署 TiDB 集群 在开始数据导入之前,需先部署一套要进行导入的 TiDB 集群 (版本要求 2.0.9 以上),建议使用最新版。部署方法可参考 TiDB 快速入门指南。第 2 步:下载 TiDB-Lightning 安装包 通过以下链接获取 TiDB-Lightning 安装包(需选择与集群相同的版本): v2.1: https://download.pingcap.org/tidb-lightning-release-2.1-linux-amd64.tar.gz v2.0: https://download.pingcap.org/tidb-lightning-release-2.0-linux-amd64.tar.gz 第 3 步:启动 tikv-importer 从安装包上传 bin/tikv-importer。 配置 tikv-importer.toml。# TiKV Importer 配置文件模版 # 日志文件。 log-file = "tikv-importer.log" # 日志等级:trace、debug、info、warn、error、off。 log-level = "info" [server] # tikv-importer 监听的地址,tidb-lightning 需要连到这个地址进行数据写入。 addr = "0.0.0.0:20170" # gRPC 服务器的线程池大小。 grpc-concurrency = 16 [metric] # 给 Prometheus 客户端的推送任务名称。 job = "tikv-importer" # 给 Prometheus 客户端的推送间隔。 interval = "15s" # Prometheus Pushgateway 地址。 address = "" [rocksdb] # 最大的背景任务并发数。 max-background-jobs = 32 [rocksdb.defaultcf] # 数据在刷新到硬盘前能存于内存的容量上限。 write-buffer-size = "1GB" # 存于内存的写入缓冲最大数量。 max-write-buffer-number = 8 # 各个压缩层级使用的算法。 # 第 0 层的算法用于压缩 KV 数据。 # 第 6 层的算法用于压缩 SST 文件。 # 第 1 至 5 层的算法目前忽略。 compression-per-level = ["lz4", "no", "no", "no", "no", "no", "zstd"] [import] # 存储引擎文档 (engine file) 的文件夹路径。 import-dir = "/tmp/tikv/import" # 处理 gRPC 请求的线程数量。 num-threads = 16 # 导入任务并发数。 num-import-jobs = 24 # 预处理 Region 最长时间。 #max-prepare-duration = "5m" # 把要导入的数据切分为这个大小的 Region。 #region-split-size = "96MB" # 流管道窗口大小,管道满时会阻塞流。 #stream-channel-window = 128 # 引擎文档同时打开的最大数量。 max-open-engines = 8 运行 tikv-importer。nohup ./tikv-importer -C tikv-importer.toml > nohup.out & 第 4 步:启动 tidb-lightning 从安装包上传 bin/tidb-lightning 及 bin/tidb-lightning-ctl。 将 mydumper SQL dump 数据源写入到同样的机器。 配置 tidb-lightning.toml。# TiDB-Lightning 配置文件模版 [lightning] # 用于调试和 Prometheus 监控的 HTTP 端口。输入 0 关闭。 pprof-port = 10089 # 开始导入前先检查集群版本是否支持。 #check-requirements = true # 控制同时处理的表的数量。这个值会影响 tikv-importer 的内存使用量。 # 不能超过 tikv-importer 中 max-open-engines 的值。 table-concurrency = 8 # 转换数据的并发数,默认为逻辑 CPU 数量,不需要配置。 # 混合部署的情况下可以配置为逻辑 CPU 的 75% 大小。 #region-concurrency = # 日志 level = "info" file = "tidb-lightning.log" max-size = 128 # MB max-days = 28 max-backups = 14 [checkpoint] # 启用断点续传。 # 导入时,Lightning 会记录当前进度。 # 若 Lightning 或其他组件异常退出,在重启时可以避免重复再导入已完成的数据。 enable = true # 存储断点的数据库名称。 schema = "tidb_lightning_checkpoint" # 存储断点的数据库连接参数 (DSN),格式为“用户:密码@tcp(地址:端口)”。 # 默认会重用 [tidb] 设置目标数据库来存储断点。 # 为避免加重目标集群的压力,建议另外使用一个兼容 MySQL 协议的数据库服务器。 # dsn = "root@tcp(127.0.0.1:4000)/" # 导入成功后是否保留断点。默认为删除。 # 保留断点可用于调试,但有可能泄漏数据源的元数据。 # keep-after-success = false [tikv-importer] # tikv-importer 的监听地址,需改成 tikv-importer 服务器的实际地址。 addr = "172.16.31.10:20170" [mydumper] # 文件读取区块大小。 read-block-size = 4096 # 字节 (默认 = 4 KB) # 每个文档在转换时会切分为多个 Chunk 并发处理,此为每个 Chunk 的大小。 region-min-size = 268435456 # 字节 (默认 = 256 MB) # mydumper 源数据目录。 data-source-dir = "/data/my_database" # 如果 no-schema 设置为 true,tidb-lightning 将直接去 tidb-server 获取表结构信息, # 而不是根据 data-source-dir 的 schema 文件来创建库/表, # 适用于手动创建表或者 TiDB 本来就有表结构的情况。 no-schema = false [tidb] # 目标集群的信息。tidb-server 的监听地址,填一个即可。 host = "172.16.31.1" port = 4000 user = "root" password = "" # 表架构信息在从 TiDB 的“状态端口”获取。 status-port = 10080 # pd-server 的监听地址,填一个即可。 pd-addr = "172.16.31.4:2379" # tidb-lightning 引用了 TiDB 库,而它自己会产生一些日志。此设置控制 TiDB 库的日志等级。 log-level = "error" # 设置 TiDB 会话变量,提升 CHECKSUM 和 ANALYZE 的速度。 distsql-scan-concurrency = 16 # 导完数据以后可以自动进行校验和 (CHECKSUM)、压缩 (Compact) 和分析 (ANALYZE) 的操作。 # 生产环境建议都设为 true # 执行顺序是: CHECKSUM -> Compact -> ANALYZE。 [post-restore] # 如果设置为 true,会对每个表逐个做 `ADMIN CHECKSUM TABLE <table>` 操作。 checksum = true # 如果设置为 true,会对所有数据做一次全量 Compact。 compact = true # 如果设置为 true,会对每个表逐个做 `ANALYZE TABLE <table>` 操作。 analyze = true 运行 tidb-lightning。如果直接在命令行中用 nohup 启动程序,可能会因为 SIGHUP 信号而退出,建议把 nohup 放到脚本里面,如:#!/bin/bash nohup ./tidb-lightning -config tidb-lightning.toml > nohup.out & "}, {"url": "https://pingcap.com/docs-cn/tools/lightning/errors/", "title": "TiDB-Lightning 错误排解", "content": " TiDB-Lightning 错误排解 当 Lightning 遇到不可恢复的错误时便会异常退出,并在日志中记下错误原因。一般可在日志底部找到,也可以搜索 [error] 字符串找出中间发生的错误。本文主要描述一些常见的错误及其解决方法。导入速度太慢 Lightning 的正常速度为每条线程每 5 分钟导入一个 256 MB 的 Chunk,如果速度远慢于这个数值就是有问题。导入的速度可以检查日志提及 restore chunk … takes 的记录,或者观察 Grafana 的监控讯息。导入速度太慢一般有几个原因:原因 1:region-concurrency 设定太高,线程间争用资源反而减低了效率。 从日志的开头搜寻 region-concurrency 能知道 Lightning 读到的参数是多少。 如果 Lightning 与其他服务(如 Importer)共用一台服务器,必需手动将 region-concurrency 设为该服务器 CPU 数量的 75%。 如果 CPU 设有限额(例如从 K8s 指定的上限),Lightning 可能无法自动判断出来,此时亦需要手动调整 region-concurrency。 原因 2:表结构太复杂。每条索引都会额外增加 KV 对。如果有 N 条索引,实际导入的大小就差不多是 mydumper 文件的 N+1 倍。如果索引不太重要,可以考虑先从 schema 去掉,待导入完成后再使用 CREATE INDEX 加回去。原因 3:Lightning 版本太旧。试试最新的版本吧!可能会有改善。checksum failed: checksum mismatched remote vs local 原因:本地数据源跟目标数据库某个表的校验和不一致。这通常有更深层的原因: 这张表可能本身已有数据,影响最终结果。 如果表没有整数型主键 (integer PRIMARY KEY),在断点续传后有些行可能会被重复导入。这是已知的问题,计划在下个版本中修正。 如果目标数据库的校验和全是 0,表示什么也没导进去,有可能是集群太忙无法接收导入的指令。 如果数据源是由机器生成而不是从 mydumper 备份的,需确保数据符合表的限制,例如: 自增 (AUTO_INCREMENT) 的列需要为正数,不能为 0。 单一键和主键 (UNIQUE and PRIMARY KEYs) 不能有重复的值。 解决办法: 使用 tidb-lightning-ctl --error-checkpoint-destroy=all 把出错的表删除,然后重启 Lightning 重新导入那些表。 把断点存放在外部数据库(修改 [checkpoint] dsn),减轻目标集群压力。 ResourceTemporarilyUnavailable(“Too many open engines …: 8”) 原因:并行打开的引擎文件 (engine files) 超出 tikv-importer 里的限制。这可能由配置错误引起。即使配置没问题,如果 tidb-lightning 曾经异常退出,也有可能令引擎文件残留在打开的状态,占据可用的数量。解决办法: 提高 tikv-importer.toml 内 max-open-engine 的值。这个设置主要由内存决定,计算公式为:最大内存使用量 ≈ max-open-engine × write-buffer-size × max-write-buffer-number 降低 table-concurrency,使之低于 max-open-engine。 重启 tikv-importer 来强制移除所有引擎文件。这样也会丢弃导入了一半的表,所以启动 Lightning 前必须使用 tidb-lightning-ctl --error-checkpoint-destroy=all。 cannot guess encoding for input file, please convert to UTF-8 manually 原因:Lightning 只支持 UTF-8 和 GB-18030 编码的表架构。此错误代表数据源不是这里任一个编码。也有可能是文件中混合了不同的编码,例如,因为在不同的环境运行过 ALTER TABLE,使表架构同时出现 UTF-8 和 GB-18030 的字符。解决办法: 编辑数据源,保存为纯 UTF-8 或 GB-18030 的文件。 自行在目标数量库创建所有的表,然后设置 [mydumper] no-schema = true 跳过创建表的步骤。 "}, {"url": "https://pingcap.com/docs/tools/tikv-control/", "title": "TiKV Control User Guide", "content": " TiKV Control User Guide TiKV Control (tikv-ctl) is a command line tool of TiKV, used to manage the cluster.When you compile TiKV, the tikv-ctl command is also compiled at the same time. If the cluster is deployed using Ansible, the tikv-ctl binary file exists in the corresponding tidb-ansible/resources/bin directory. If the cluster is deployed using the binary, the tikv-ctl file is in the bin directory together with other files such as tidb-server, pd-server, tikv-server, etc.General options tikv-ctl provides two operation modes: Remote mode: use the --host option to accept the service address of TiKV as the argumentFor this mode, if SSL is enabled in TiKV, tikv-ctl also needs to specify the related certificate file. For example:$ tikv-ctl --ca-path ca.pem --cert-path client.pem --key-path client-key.pem --host 127.0.0.1:20160 <subcommands> However, sometimes tikv-ctl communicates with PD instead of TiKV. In this case, you need to use the --pd option instead of --host. Here is an example:$ tikv-ctl --pd 127.0.0.1:2379 compact-cluster store:"127.0.0.1:20160" compact db:KV cf:default range:([], []) success! Local mode: use the --db option to specify the local TiKV data directory path Unless otherwise noted, all commands supports both the remote mode and the local mode.Additionally, tikv-ctl has two simple commands --to-hex and --to-escaped, which are used to make simple changes to the form of the key.Generally, use the escaped form of the key. For example:$ tikv-ctl --to-escaped 0xaaff 252377 $ tikv-ctl --to-hex "252377" AAFF Note: When you specify the escaped form of the key in a command line, it is required to enclose it in double quotes. Otherwise, bash eats the backslash and a wrong result is returned. Subcommands, some options and flags This section describes the subcommands that tikv-ctl supports in detail. Some subcommands support a lot of options. For all details, run tikv-ctl --help <subcommand>.View information of the Raft state machine Use the raft subcommand to view the status of the Raft state machine at a specific moment. The status information includes two parts: three structs (RegionLocalState, RaftLocalState, and RegionApplyState) and the corresponding Entries of a certain piece of log.Use the region and log subcommands to obtain the above information respectively. The two subcommands both support the remote mode and the local mode at the same time. Their usage and output are as follows:$ tikv-ctl --host 127.0.0.1:20160 raft region -r 2 region id: 2 region state key: 001003000000000000000000000002001 region state: Some(region {id: 2 region_epoch {conf_ver: 3 version: 1} peers {id: 3 store_id: 1} peers {id: 5 store_id: 4} peers {id: 7 store_id: 6}}) raft state key: 001002000000000000000000000002002 raft state: Some(hard_state {term: 307 vote: 5 commit: 314617} last_index: 314617) apply state key: 001002000000000000000000000002003 apply state: Some(applied_index: 314617 truncated_state {index: 313474 term: 151}) View the Region size Use the size command to view the Region size:$ tikv-ctl --db /path/to/tikv/db size -r 2 region id: 2 cf default region size: 799.703 MB cf write region size: 41.250 MB cf lock region size: 27616 Scan to view MVCC of a specific range The --from and --to options of the scan command accept two escaped forms of raw key, and use the --show-cf flag to specify the column families that you need to view.$ tikv-ctl --db /path/to/tikv/db scan --from 'zm' --limit 2 --show-cf lock,default,write key: zmBootstr377a377pKey000000377000000373000000000000000377000000s000000000000000372 write cf value: start_ts: 399650102814441473 commit_ts: 399650102814441475 short_value: "20" key: zmDB:29000000377000374000000000000000000377000H000000000000000000371 write cf value: start_ts: 399650105239273474 commit_ts: 399650105239273475 short_value: "000000000000000000000002" write cf value: start_ts: 399650105199951882 commit_ts: 399650105213059076 short_value: "000000000000000000000001" View MVCC of a given key Similar to the scan command, the mvcc command can be used to view MVCC of a given key.$ tikv-ctl --db /path/to/tikv/db mvcc -k "zmDB:29000000377000374000000000000000000377000H000000000000000000371" --show-cf=lock,write,default key: zmDB:29000000377000374000000000000000000377000H000000000000000000371 write cf value: start_ts: 399650105239273474 commit_ts: 399650105239273475 short_value: "000000000000000000000002" write cf value: start_ts: 399650105199951882 commit_ts: 399650105213059076 short_value: "000000000000000000000001" In this command, the key is also the escaped form of raw key.Print a specific key value To print the value of a key, use the print command.Print some properties about Region In order to record Region state details, TiKV writes some statistics into the SST files of Regions. To view these properties, run tikv-ctl with the region-properties sub-command:$ tikv-ctl --host localhost:20160 region-properties -r 2 num_files: 0 num_entries: 0 num_deletes: 0 mvcc.min_ts: 18446744073709551615 mvcc.max_ts: 0 mvcc.num_rows: 0 mvcc.num_puts: 0 mvcc.num_versions: 0 mvcc.max_row_versions: 0 middle_key_by_approximate_size: The properties can be used to check whether the Region is healthy or not. If not, you can use them to fix the Region. For example, splitting the Region manually by middle_key_approximate_size.Compact data of each TiKV manually Use the compact command to manually compact data of each TiKV. If you specify the --from and --to options, then their flags are also in the form of escaped raw key. You can use the --db option to specify the RocksDB that you need to compact. The optional values are kv and raft. Also, the --threads option allows you to specify the concurrency that you compact and its default value is 8. Generally, a higher concurrency comes with a faster compact speed, which might yet affect the service. You need to choose an appropriate concurrency based on the scenario.$ tikv-ctl --db /path/to/tikv/db compact -d kv success! Compact data of the whole TiKV cluster manually Use the compact-cluster command to manually compact data of the whole TiKV cluster. The flags of this command have the same meanings and usage as those of the compact command.Set a Region to tombstone The tombstone command is usually used in circumstances where the sync-log is not enabled, and some data written in the Raft state machine is lost caused by power down.In a TiKV instance, you can use this command to set the status of some Regions to Tombstone. Then when you restart the instance, those Regions are skipped. Those Regions need to have enough healthy replicas in other TiKV instances to be able to continue writing and reading through the Raft mechanism.pd-ctl>> operator add remove-peer <region_id> <peer_id> $ tikv-ctl --db /path/to/tikv/db tombstone -p 127.0.0.1:2379 -r 2 success! Note: This command only supports the local mode. The argument of the -p option specifies the PD endpoints without the http prefix. Specifying the PD endpoints is to query whether PD can securely switch to Tombstone. Therefore, before setting a PD instance to Tombstone, you need to take off the corresponding Peer of this Region on the machine in pd-ctl. Send a consistency-check request to TiKV Use the consistency-check command to execute a consistency check among replicas in the corresponding Raft of a specific Region. If the check fails, TiKV itself panics. If the TiKV instance specified by --host is not the Region leader, an error is reported.$ tikv-ctl --host 127.0.0.1:20160 consistency-check -r 2 success! $ tikv-ctl --host 127.0.0.1:21061 consistency-check -r 2 DebugClient::check_region_consistency: RpcFailure(RpcStatus { status: Unknown, details: Some("StringError("Leader is on store 1")") }) Note: This command only supports the remote mode. Even if this command returns success!, you need to check whether TiKV panics. This …"}, {"url": "https://pingcap.com/docs/v2.0/tools/tikv-control/", "title": "TiKV Control User Guide", "content": " TiKV Control User Guide TiKV Control (tikv-ctl) is a command line tool of TiKV, used to manage the cluster.When you compile TiKV, the tikv-ctl command is also compiled at the same time. If the cluster is deployed using Ansible, the tikv-ctl binary file exists in the corresponding tidb-ansible/resources/bin directory. If the cluster is deployed using the binary, the tikv-ctl file is in the bin directory together with other files such as tidb-server, pd-server, tikv-server, etc.General options tikv-ctl provides two operation modes: Remote mode: use the --host option to accept the service address of TiKV as the argumentFor this mode, if SSL is enabled in TiKV, tikv-ctl also needs to specify the related certificate file. For example:$ tikv-ctl --ca-path ca.pem --cert-path client.pem --key-path client-key.pem --host 127.0.0.1:21060 <subcommands> However, sometimes tikv-ctl communicates with PD instead of TiKV. In this case, you need to use the --pd option instead of --host. Here is an example:$ tikv-ctl --pd 127.0.0.1:2379 compact-cluster store:"127.0.0.1:20160" compact db:KV cf:default range:([], []) success! Local mode: use the --db option to specify the local TiKV data directory path Unless otherwise noted, all commands supports both the remote mode and the local mode.Additionally, tikv-ctl has two simple commands --to-hex and --to-escaped, which are used to make simple changes to the form of the key.Generally, use the escaped form of the key. For example:$ tikv-ctl --to-escaped 0xaaff 252377 $ tikv-ctl --to-hex "252377" AAFF Note: When you specify the escaped form of the key in a command line, it is required to enclose it in double quotes. Otherwise, bash eats the backslash and a wrong result is returned. Subcommands, some options and flags This section describes the subcommands that tikv-ctl supports in detail. Some subcommands support a lot of options. For all details, run tikv-ctl --help <subcommand>.View information of the Raft state machine Use the raft subcommand to view the status of the Raft state machine at a specific moment. The status information includes two parts: three structs (RegionLocalState, RaftLocalState, and RegionApplyState) and the corresponding Entries of a certain piece of log.Use the region and log subcommands to obtain the above information respectively. The two subcommands both support the remote mode and the local mode at the same time. Their usage and output are as follows:$ tikv-ctl --host 127.0.0.1:21060 raft region -r 2 region id: 2 region state key: 001003000000000000000000000002001 region state: Some(region {id: 2 region_epoch {conf_ver: 3 version: 1} peers {id: 3 store_id: 1} peers {id: 5 store_id: 4} peers {id: 7 store_id: 6}}) raft state key: 001002000000000000000000000002002 raft state: Some(hard_state {term: 307 vote: 5 commit: 314617} last_index: 314617) apply state key: 001002000000000000000000000002003 apply state: Some(applied_index: 314617 truncated_state {index: 313474 term: 151}) View the Region size Use the size command to view the Region size:$ tikv-ctl --db /path/to/tikv/db size -r 2 region id: 2 cf default region size: 799.703 MB cf write region size: 41.250 MB cf lock region size: 27616 Scan to view MVCC of a specific range The --from and --to options of the scan command accept two escaped forms of raw key, and use the --show-cf flag to specify the column families that you need to view.$ tikv-ctl --db /path/to/tikv/db scan --from 'zm' --limit 2 --show-cf lock,default,write key: zmBootstr377a377pKey000000377000000373000000000000000377000000s000000000000000372 write cf value: start_ts: 399650102814441473 commit_ts: 399650102814441475 short_value: "20" key: zmDB:29000000377000374000000000000000000377000H000000000000000000371 write cf value: start_ts: 399650105239273474 commit_ts: 399650105239273475 short_value: "000000000000000000000002" write cf value: start_ts: 399650105199951882 commit_ts: 399650105213059076 short_value: "000000000000000000000001" View MVCC of a given key Similar to the scan command, the mvcc command can be used to view MVCC of a given key.$ tikv-ctl --db /path/to/tikv/db mvcc -k "zmDB:29000000377000374000000000000000000377000H000000000000000000371" --show-cf=lock,write,default key: zmDB:29000000377000374000000000000000000377000H000000000000000000371 write cf value: start_ts: 399650105239273474 commit_ts: 399650105239273475 short_value: "000000000000000000000002" write cf value: start_ts: 399650105199951882 commit_ts: 399650105213059076 short_value: "000000000000000000000001" In this command, the key is also the escaped form of raw key.Print a specific key value To print the value of a key, use the print command.Print some properties about Region In order to record Region state details, TiKV writes some statistics into the SST files of Regions. To view these properties, run tikv-ctl with the region-properties sub-command:$ tikv-ctl --host localhost:20160 region-properties -r 2 num_files: 0 num_entries: 0 num_deletes: 0 mvcc.min_ts: 18446744073709551615 mvcc.max_ts: 0 mvcc.num_rows: 0 mvcc.num_puts: 0 mvcc.num_versions: 0 mvcc.max_row_versions: 0 middle_key_by_approximate_size: The properties can be used to check whether the Region is healthy or not. If not, you can use them to fix the Region. For example, splitting the Region manually by middle_key_approximate_size.Compact data of each TiKV manually Use the compact command to manually compact data of each TiKV. If you specify the --from and --to options, then their flags are also in the form of escaped raw key. You can use the --db option to specify the RocksDB that you need to compact. The optional values are kv and raft. Also, the --threads option allows you to specify the concurrency that you compact and its default value is 8. Generally, a higher concurrency comes with a faster compact speed, which might yet affect the service. You need to choose an appropriate concurrency based on the scenario.$ tikv-ctl --db /path/to/tikv/db compact -d kv success! Compact data of the whole TiKV cluster manually Use the compact-cluster command to manually compact data of the whole TiKV cluster. The flags of this command have the same meanings and usage as those of the compact command.Set a Region to tombstone The tombstone command is usually used in circumstances where the sync-log is not enabled, and some data written in the Raft state machine is lost caused by power down.In a TiKV instance, you can use this command to set the status of some Regions to Tombstone. Then when you restart the instance, those Regions are skipped. Those Regions need to have enough healthy replicas in other TiKV instances to be able to continue writing and reading through the Raft mechanism.pd-ctl>> operator add remove-peer <region_id> <peer_id> $ tikv-ctl --db /path/to/tikv/db tombstone -p 127.0.0.1:2379 -r 2 success! Note: This command only supports the local mode. The argument of the --pd/-p option specifies the PD endpoints without the http prefix. Specifying the PD endpoints is to query whether PD can securely switch to Tombstone. Therefore, before setting a PD instance to Tombstone, you need to take off the corresponding Peer of this Region on the machine in pd-ctl. Send a consistency-check request to TiKV Use the consistency-check command to execute a consistency check among replicas in the corresponding Raft of a specific Region. If the check fails, TiKV itself panics. If the TiKV instance specified by --host is not the Region leader, an error is reported.$ tikv-ctl --host 127.0.0.1:21060 consistency-check -r 2 success! $ tikv-ctl --host 127.0.0.1:21061 consistency-check -r 2 DebugClient::check_region_consistency: RpcFailure(RpcStatus { status: Unknown, details: Some("StringError("Leader is on store 1")") }) Note: This command only supports the remote mode. Even if this command returns success!, you need to check whether TiKV panics. …"}, {"url": "https://pingcap.com/docs-cn/tools/tikv-control/", "title": "TiKV Control 使用说明", "content": " TiKV Control 使用说明 TiKV Control (tikv-ctl) 是随 TiKV 附带的一个简单的管理工具,以下简称 tikv-ctl。在编译 TiKV 时,tikv-ctl 命令也会同时被编译出来,而通过 Ansible 部署的集群,在对应的 tidb-ansible/resources/bin 目录下也会有这个二进制文件。通用参数 tikv-ctl 有两种运行模式:远程模式和本地模式。前者通过 --host 选项接受 TiKV 的服务地址作为参数,后者则需要 --db 选项来指定本地 TiKV 数据目录路径。以下如无特殊说明,所有命令都同时支持这两种模式。对于远程模式,如果 TiKV 启用了 SSL,则 tikv-ctl 也需要指定相关的证书文件,例如:$ tikv-ctl --ca-path ca.pem --cert-path client.pem --key-path client-key.pem --host 127.0.0.1:20160 <subcommands> 某些情况下,tikv-ctl 与 PD 进行通信,而不与 TiKV 通信。此时你需要使用 --pd 选项而非 --host 选项,例如:$ tikv-ctl --pd 127.0.0.1:2379 compact-cluster store:"127.0.0.1:20160" compact db:KV cf:default range:([], []) success! 除此之外,tikv-ctl 还有两个简单的命令 --to-hex 和 --to-escaped,用于对 key 的形式作简单的变换。一般使用 escaped 形式,示例如下:$ tikv-ctl --to-escaped 0xaaff 252377 $ tikv-ctl --to-hex "252377" AAFF 注意:在命令行上指定 escaped 形式的 key 时,需要用双引号引起来,否则 bash 会将反斜杠吃掉,导致结果错误。 各项子命令及部分参数、选项 下面逐一对 tikv-ctl 支持的子命令进行举例说明。有的子命令支持很多可选参数,要查看全部细节,可运行 tikv-ctl --help <subcommand>。查看 Raft 状态机的信息 raft 子命令可以查看 Raft 状态机在某一时刻的状态,包括 RegionLocalState,RaftLocalState,RegionApplyState 三个结构体,及某一条 log 对应的 Entries。它有 region 和 log 两个子命令分别做这两件事。两个子命令都同时支持远程模式和本地模式。它们的用法及输出内容如下所示:$ tikv-ctl --host 127.0.0.1:20160 raft region -r 2 region id: 2 region state key: 001003000000000000000000000002001 region state: Some(region {id: 2 region_epoch {conf_ver: 3 version: 1} peers {id: 3 store_id: 1} peers {id: 5 store_id: 4} peers {id: 7 store_id: 6}}) raft state key: 001002000000000000000000000002002 raft state: Some(hard_state {term: 307 vote: 5 commit: 314617} last_index: 314617) apply state key: 001002000000000000000000000002003 apply state: Some(applied_index: 314617 truncated_state {index: 313474 term: 151}) 查看 Region 的大小 size 命令可以查看 Region 的大小:$ tikv-ctl --db /path/to/tikv/db size -r 2 region id: 2 cf default region size: 799.703 MB cf write region size: 41.250 MB cf lock region size: 27616 扫描查看给定范围的 MVCC scan 命令的 --from 和 --to 参数接受两个 escaped 形式的 raw key,并用 --show-cf 参数指定只需要查看哪些列族。$ tikv-ctl --db /path/to/tikv/db scan --from 'zm' --limit 2 --show-cf lock,default,write key: zmBootstr377a377pKey000000377000000373000000000000000377000000s000000000000000372 write cf value: start_ts: 399650102814441473 commit_ts: 399650102814441475 short_value: "20" key: zmDB:29000000377000374000000000000000000377000H000000000000000000371 write cf value: start_ts: 399650105239273474 commit_ts: 399650105239273475 short_value: "000000000000000000000002" write cf value: start_ts: 399650105199951882 commit_ts: 399650105213059076 short_value: "000000000000000000000001" 查看给定 key 的 MVCC 与上个命令类似,mvcc 命令可以查看给定 key 的 MVCC:$ tikv-ctl --db /path/to/tikv/db mvcc -k "zmDB:29000000377000374000000000000000000377000H000000000000000000371" --show-cf=lock,write,default key: zmDB:29000000377000374000000000000000000377000H000000000000000000371 write cf value: start_ts: 399650105239273474 commit_ts: 399650105239273475 short_value: "000000000000000000000002" write cf value: start_ts: 399650105199951882 commit_ts: 399650105213059076 short_value: "000000000000000000000001" 注意:该命令中,key 同样需要是 escaped 形式的 raw key。 打印某个 key 的值 打印某个 key 的值需要用到 print 命令。示例从略。打印 Region 的 properties 信息 为了记录 Region 的状态信息,TiKV 将一些数据写入 Region 的 SST 文件中。你可以用子命令 region-properties 运行 tikv-ctl 来查看这些 properties 信息。例如:$ tikv-ctl --host localhost:20160 region-properties -r 2 num_files: 0 num_entries: 0 num_deletes: 0 mvcc.min_ts: 18446744073709551615 mvcc.max_ts: 0 mvcc.num_rows: 0 mvcc.num_puts: 0 mvcc.num_versions: 0 mvcc.max_row_versions: 0 middle_key_by_approximate_size: 这些 properties 信息可以用于检查某个 Region 是否健康或者修复不健康的 Region。例如,使用 middle_key_approximate_size 可以手动分裂 Region。手动 compact 单个 TiKV 的数据 compact 命令可以对单个 TiKV 进行手动 compact。如果指定 --from 和 --to 选项,那么它们的参数也是 escaped raw key 形式的。--db 参数可以指定要 compact 的 RocksDB,有 kv 和 raft 参数值可以选。--threads 参数可以指定 compact 的并发数,默认值是 8。一般来说,并发数越大, compact 的速度越快,但是也会对服务造成影响,所以需要根据情况选择合适的并发数。$ tikv-ctl --db /path/to/tikv/db compact -d kv success! 手动 compact 整个 TiKV 集群的数据 compact-cluster 命令可以对整个 TiKV 集群进行手动 compact。该命令参数的含义和使用与 compact 命令一样。设置一个 Region 为 tombstone tombstone 命令常用于没有开启 sync-log,因为机器掉电导致 Raft 状态机丢失部分写入的情况。它可以在一个 TiKV 实例上将一些 Region 设置为 Tombstone 状态,从而在重启时跳过那些 Region。而那些 Region 应该在其他 TiKV 上有足够多的健康的副本以便能够继续通过 Raft 机制进行读写。pd-ctl>> operator add remove-peer <region_id> <peer_id> $ tikv-ctl --db /path/to/tikv/db tombstone -p 127.0.0.1:2379 -r 2 success! 注意: -p 选项的参数指定 PD 的 endpoints,它没有 http 前缀。 这个命令只支持本地模式。需要指定 PD 的 endpoints 的原因是需要询问 PD 是否可以安全地 tombstone。因此,在 tombstone 之前往往还需要在 pd-ctl 中把该 Region 在这台机器上的对应 Peer 拿掉。 向 TiKV 发出 consistency-check 请求 这个命令只支持远程模式,它可以让某个 Region 对应的 Raft 进行一次副本之间的一致性检查。如果检查失败,TiKV 自身会 panic。如果 --host 指定的 TiKV 不是这个 Region 的 Leader,则会报告错误。$ tikv-ctl --host 127.0.0.1:20160 consistency-check -r 2 success! $ tikv-ctl --host 127.0.0.1:21061 consistency-check -r 2 DebugClient::check_region_consistency: RpcFailure(RpcStatus { status: Unknown, details: Some("StringError("Leader is on store 1")") }) 需要注意的是,即使这个命令返回了成功,也需要去检查是否有 TiKV panic 了,因为这个命令只是给 Leader 发起一个 Consistency-check 的 propose,至于整个检查流程成功与否并不能在客户端知道。Dump snapshot meta 这条子命令可以用于解析指定路径下的 Snapshot 元文件并打印结果。打印 Raft 状态机出错的 Region 前面 tombstone 命令可以将 Raft 状态机出错的 Region 设置为 Tombstone 状态,避免 TiKV 启动时对它们进行检查。在运行那个命令之前,bad-regions 命令可以找出这些出错了的 Region,以便将多个工具组合起来进行自动化的处理。$ tikv-ctl --db /path/to/tikv/db bad-regions all regions are healthy 命令执行成功会打印上面的信息,否则会打印出有错误的 Region 列表。目前可以检出的错误包括 last index、commit index 和 apply index 之间的不匹配,以及 Raft log 的丢失。其他一些情况,比如 Snapshot 文件损坏等仍然需要后续的支持。查看 Region 的 properties 信息 本地查看部署在 /path/to/tikv 的 tikv 上面 Region 2 的 properties 信息:$ tikv-ctl --db /path/to/tikv/data/db region-properties -r 2 在线查看运行在 127.0.0.1:20160 的 tikv 上面 Region 2 的 properties 信息:$ tikv-ctl --host 127.0.0.1:20160 region-properties -r 2 动态修改 TiKV 的 RocksDB 相关配置 使用 modify-tikv-config 命令可以动态修改配置参数,暂时仅支持对于 RocksDB 相关参数的动态更改。 -m 可以指定要修改的 RocksDB,有 kvdb 和 raftdb 两个值可以选择。 -n 用于指定配置名。配置名可以参考 TiKV 配置模版中 [rocksdb] 和 [raftdb] 下的参数,分别对应 kvdb 和 raftdb。同时,还可以通过 default|write|lock + . + 参数名 的形式来指定的不同 CF 的配置(对于 kvdb 有 default|write|lock 可以选择,对于 raftdb 仅有 default 可以选择。 -v 用于指定配置值。 $ tikv-ctl modify-tikv-config -m kvdb -n max_background_jobs -v 8 success! $ tikv-ctl modify-tikv-config -m kvdb -n write.block-cache-size -v 256MB success! $ tikv-ctl modify-tikv-config -m raftdb -n default.disable_auto_compactions -v true success! 强制 Region 从多副本失败状态恢复服务 unsafe-recover remove-fail-stores 命令可以将一些失败掉的机器从指定 Region 的 peers 列表中移除。这个命令只有 local 模式,而且需要目标 TiKV 先停掉服务以便释放文件锁。-s 选项接受多个以逗号分隔的 store_id,并使用 -r 参数来指定包含的 Region。如果要对某一个 store 上的全部 Region 都执行这个操作,则可以简单地指定 --all-regions。$ tikv-ctl --db /path/to/tikv/db unsafe-recover remove-fail-stores -s 3 -r 1001,1002 success! $ tikv-ctl --db /path/to/tikv/db unsafe-recover remove-fail-stores -s 4,5 --all-regions 之后启动 TiKV,这些 Region 便可以以剩下的健康的副本继续提供服务了。这个命令常用于多个 TiKV store 损坏或被删除的情况。 注意: 这个命令只支持本地模式。在运行成功后,会打印 success!。 一般来说,需要使用这个命令的地方,对于指定 Region 的 peers 所在的每个 store,均须运行这个命令。 如果使用 --all-regions,通常需要在集群剩余所有健康的 store 上执行这个命令。 恢复损坏的 MVCC 数据 recover-mvcc 命令用于 MVCC 数据损坏导致 TiKV 无法正常运行的情况。为了从不同种类的不一致情况中恢复,该命令会反复检查 3 个 CF (“default”, “write”, “lock”)。-r 选项可以通过 region_id 指定包含的 Region,-p 选项可以指定 PD 的 endpoint。$ tikv-ctl --db /path/to/tikv/db recover-mvcc -r 1001,1002 -p 127.0.0.1:2379 success! 注意: 这个命令只支持本地模式。在运行成功后,会打印 success!。 -p 选项指定 PD 的 endpoint,不使用 http 前缀,用于查询指定的 region_id 是否有效。 对于指定 Region 的 peers 所在的每个 store,均须执行这个命令。 "}, {"url": "https://pingcap.com/docs-cn/op-guide/tune-tikv/", "title": "TiKV 性能参数调优", "content": " TiKV 性能参数调优 本文档用于描述如何根据机器配置情况来调整 TiKV 的参数,使 TiKV 的性能达到最优。TiKV 最底层使用的是 RocksDB 做为持久化存储,所以 TiKV 的很多性能相关的参数都是与 RocksDB 相关的。TiKV 使用了两个 RocksDB 实例,默认 RocksDB 实例存储 KV 数据,Raft RocksDB 实例(简称 RaftDB)存储 Raft 数据。TiKV 使用了 RocksDB 的 Column Families (CF) 特性。 默认 RocksDB 实例将 KV 数据存储在内部的 default、write 和 lock 3 个 CF 内。 default CF 存储的是真正的数据,与其对应的参数位于 [rocksdb.defaultcf] 项中; write CF 存储的是数据的版本信息 (MVCC) 以及索引相关的数据,相关的参数位于 [rocksdb.writecf] 项中; lock CF 存储的是锁信息,系统使用默认参数。 Raft RocksDB 实例存储 Raft log。 default CF 主要存储的是 Raft log,与其对应的参数位于 [raftdb.defaultcf] 项中。 每个 CF 都有单独的 block-cache,用于缓存数据块,加速 RocksDB 的读取速度,block-cache 的大小通过参数 block-cache-size 控制,block-cache-size 越大,能够缓存的热点数据越多,对读取操作越有利,同时占用的系统内存也会越多。每个 CF 有各自的 write-buffer,大小通过 write-buffer-size 控制。参数说明 # 日志级别,可选值为:trace,debug,info,warn,error,off log-level = "info" [server] # 监听地址 # addr = "127.0.0.1:20160" # gRPC 线程池大小 # grpc-concurrency = 4 # TiKV 每个实例之间的 gRPC 连接数 # grpc-raft-conn-num = 10 # TiDB 过来的大部分读请求都会发送到 TiKV 的 Coprocessor 进行处理,该参数用于设置 # coprocessor 线程的个数,如果业务是读请求比较多,增加 coprocessor 的线程数,但应比系统的 # CPU 核数小。例如:TiKV 所在的机器有 32 core,在重读的场景下甚至可以将该参数设置为 30。在没有 # 设置该参数的情况下,TiKV 会自动将该值设置为 CPU 总核数乘以 0.8。 # end-point-concurrency = 8 # 可以给 TiKV 实例打标签,用于副本的调度 # labels = {zone = "cn-east-1", host = "118", disk = "ssd"} [storage] # 数据目录 # data-dir = "/tmp/tikv/store" # 通常情况下使用默认值就可以了。在导数据的情况下建议将该参数设置为 1024000。 # scheduler-concurrency = 102400 # 该参数控制写入线程的个数,当写入操作比较频繁的时候,需要把该参数调大。使用 top -H -p tikv-pid # 发现名称为 sched-worker-pool 的线程都特别忙,这个时候就需要将 scheduler-worker-pool-size # 参数调大,增加写线程的个数。 # scheduler-worker-pool-size = 4 [pd] # pd 的地址 # endpoints = ["127.0.0.1:2379","127.0.0.2:2379","127.0.0.3:2379"] [metric] # 将 metrics 推送给 Prometheus pushgateway 的时间间隔 interval = "15s" # Prometheus pushgateway 的地址 address = "" job = "tikv" [raftstore] # 默认为 true,表示强制将数据刷到磁盘上。如果是非金融安全级别的业务场景,建议设置成 false, # 以便获得更高的性能。 sync-log = true # Raft RocksDB 目录。默认值是 [storage.data-dir] 的 raft 子目录。 # 如果机器上有多块磁盘,可以将 Raft RocksDB 的数据放在不同的盘上,提高 TiKV 的性能。 # raftdb-dir = "/tmp/tikv/store/raft" region-max-size = "384MB" # Region 分裂阈值 region-split-size = "256MB" # 当 Region 写入的数据量超过该阈值的时候,TiKV 会检查该 Region 是否需要分裂。为了减少检查过程 # 中扫描数据的成本,数据过程中可以将该值设置为32MB,正常运行状态下使用默认值即可。 region-split-check-diff = "32MB" [rocksdb] # RocksDB 进行后台任务的最大线程数,后台任务包括 compaction 和 flush。具体 RocksDB 为什么需要进行 compaction, # 请参考 RocksDB 的相关资料。在写流量比较大的时候(例如导数据),建议开启更多的线程, # 但应小于 CPU 的核数。例如在导数据的时候,32 核 CPU 的机器,可以设置成 28。 # max-background-jobs = 8 # RocksDB 能够打开的最大文件句柄数。 # max-open-files = 40960 # RocksDB MANIFEST 文件的大小限制.
# 更详细的信息请参考:https://github.com/facebook/rocksdb/wiki/MANIFEST max-manifest-file-size = "20MB" # RocksDB write-ahead logs 目录。如果机器上有两块盘,可以将 RocksDB 的数据和 WAL 日志放在 # 不同的盘上,提高 TiKV 的性能。 # wal-dir = "/tmp/tikv/store" # 下面两个参数用于怎样处理 RocksDB 归档 WAL。 # 更多详细信息请参考:https://github.com/facebook/rocksdb/wiki/How-to-persist-in-memory-RocksDB-database%3F # wal-ttl-seconds = 0 # wal-size-limit = 0 # RocksDB WAL 日志的最大总大小,通常情况下使用默认值就可以了。 # max-total-wal-size = "4GB" # 可以通过该参数打开或者关闭 RocksDB 的统计信息。 # enable-statistics = true # 开启 RocksDB compaction 过程中的预读功能,如果使用的是机械磁盘,建议该值至少为2MB。 # compaction-readahead-size = "2MB" [rocksdb.defaultcf] # 数据块大小。RocksDB 是按照 block 为单元对数据进行压缩的,同时 block 也是缓存在 block-cache # 中的最小单元(类似其他数据库的 page 概念)。 block-size = "64KB" # RocksDB 每一层数据的压缩方式,可选的值为:no,snappy,zlib,bzip2,lz4,lz4hc,zstd。 # no:no:lz4:lz4:lz4:zstd:zstd 表示 level0 和 level1 不压缩,level2 到 level4 采用 lz4 压缩算法, # level5 和 level6 采用 zstd 压缩算法,。 # no 表示没有压缩,lz4 是速度和压缩比较为中庸的压缩算法,zlib 的压缩比很高,对存储空间比较友 # 好,但是压缩速度比较慢,压缩的时候需要占用较多的 CPU 资源。不同的机器需要根据 CPU 以及 I/O 资 # 源情况来配置怎样的压缩方式。例如:如果采用的压缩方式为"no:no:lz4:lz4:lz4:zstd:zstd",在大量 # 写入数据的情况下(导数据),发现系统的 I/O 压力很大(使用 iostat 发现 %util 持续 100% 或者使 # 用 top 命令发现 iowait 特别多),而 CPU 的资源还比较充裕,这个时候可以考虑将 level0 和 # level1 开启压缩,用 CPU 资源换取 I/O 资源。如果采用的压缩方式 # 为"no:no:lz4:lz4:lz4:zstd:zstd",在大量写入数据的情况下,发现系统的 I/O 压力不大,但是 CPU # 资源已经吃光了,top -H 发现有大量的 bg 开头的线程(RocksDB 的 compaction 线程)在运行,这 # 个时候可以考虑用 I/O 资源换取 CPU 资源,将压缩方式改成"no:no:no:lz4:lz4:zstd:zstd"。总之,目 # 的是为了最大限度地利用系统的现有资源,使 TiKV 的性能在现有的资源情况下充分发挥。 compression-per-level = ["no", "no", "lz4", "lz4", "lz4", "zstd", "zstd"] # RocksDB memtable 的大小。 write-buffer-size = "128MB" # 最多允许几个 memtable 存在。写入到 RocksDB 的数据首先会记录到 WAL 日志里面,然后会插入到 # memtable 里面,当 memtable 的大小到达了 write-buffer-size 限定的大小的时候,当前的 # memtable 会变成只读的,然后生成一个新的 memtable 接收新的写入。只读的 memtable 会被 # RocksDB 的 flush 线程(max-background-flushes 参数能够控制 flush 线程的最大个数) # flush 到磁盘,成为 level0 的一个 sst 文件。当 flush 线程忙不过来,导致等待 flush 到磁盘的 # memtable 的数量到达 max-write-buffer-number 限定的个数的时候,RocksDB 会将新的写入 # stall 住,stall 是 RocksDB 的一种流控机制。在导数据的时候可以将 max-write-buffer-number # 的值设置的更大一点,例如 10。 max-write-buffer-number = 5 # 当 level0 的 sst 文件个数到达 level0-slowdown-writes-trigger 指定的限度的时候, # RocksDB 会尝试减慢写入的速度。因为 level0 的 sst 太多会导致 RocksDB 的读放大上升。 # level0-slowdown-writes-trigger 和 level0-stop-writes-trigger 是 RocksDB 进行流控的 # 另一个表现。当 level0 的 sst 的文件个数到达 4(默认值),level0 的 sst 文件会和 level1 中 # 有 overlap 的 sst 文件进行 compaction,缓解读放大的问题。 level0-slowdown-writes-trigger = 20 # 当 level0 的 sst 文件个数到达 level0-stop-writes-trigger 指定的限度的时候,RocksDB 会 # stall 住新的写入。 level0-stop-writes-trigger = 36 # 当 level1 的数据量大小达到 max-bytes-for-level-base 限定的值的时候,会触发 level1 的 # sst 和 level2 种有 overlap 的 sst 进行 compaction。 # 黄金定律:max-bytes-for-level-base 的设置的第一参考原则就是保证和 level0 的数据量大致相 # 等,这样能够减少不必要的 compaction。例如压缩方式为"no:no:lz4:lz4:lz4:lz4:lz4",那么 # max-bytes-for-level-base 的值应该是 write-buffer-size 的大小乘以 4,因为 level0 和 # level1 都没有压缩,而且 level0 触发 compaction 的条件是 sst 的个数到达 4(默认值)。在 # level0 和 level1 都采取了压缩的情况下,就需要分析下 RocksDB 的日志,看一个 memtable 的压 # 缩成一个 sst 文件的大小大概是多少,例如 32MB,那么 max-bytes-for-level-base 的建议值就应 # 该是 32MB * 4 = 128MB。 max-bytes-for-level-base = "512MB" # sst 文件的大小。level0 的 sst 文件的大小受 write-buffer-size 和 level0 采用的压缩算法的 # 影响,target-file-size-base 参数用于控制 level1-level6 单个 sst 文件的大小。 target-file-size-base = "32MB" # 在不配置该参数的情况下,TiKV 会将该值设置为系统总内存量的 40%。如果需要在单个物理机上部署多个 # TiKV 节点,需要显式配置该参数,否则 TiKV 容易出现 OOM 的问题。 # block-cache-size = "1GB" [rocksdb.writecf] # 保持和 rocksdb.defaultcf.compression-per-level 一致。 compression-per-level = ["no", "no", "lz4", "lz4", "lz4", "zstd", "zstd"] # 保持和 rocksdb.defaultcf.write-buffer-size 一致。 write-buffer-size = "128MB" max-write-buffer-number = 5 min-write-buffer-number-to-merge = 1 # 保持和 rocksdb.defaultcf.max-bytes-for-level-base 一致。 max-bytes-for-level-base = "512MB" target-file-size-base = "32MB" # 在不配置该参数的情况下,TiKV 会将该值设置为系统总内存量的 15%。如果需要在单个物理机上部署多个 # TiKV 节点,需要显式配置该参数。版本信息(MVCC)相关的数据以及索引相关的数据都记录在 write 这 # 个 CF 里面,如果业务的场景下单表索引较多,可以将该参数设置的更大一点。 # block-cache-size = "256MB" [raftdb] # RaftDB 能够打开的最大文件句柄数。 # max-open-files = 40960 # 可以通过该参数打开或者关闭 RaftDB 的统计信息。 # enable-statistics = true # 开启 RaftDB compaction 过程中的预读功能,如果使用的是机械磁盘,建议该值至少为2MB。 # compaction-readahead-size = "2MB" [raftdb.defaultcf] # 保持和 rocksdb.defaultcf.compression-per-level 一致。 compression-per-level = ["no", "no", "lz4", "lz4", "lz4", "zstd", "zstd"] # 保持和 rocksdb.defaultcf.write-buffer-size 一致。 write-buffer-size = "128MB" max-write-buffer-number = 5 min-write-buffer-number-to-merge = 1 # 保持和 rocksdb.defaultcf.max-bytes-for-level-base 一致。 max-bytes-for-level-base = "512MB" target-file-size-base = "32MB" # 通常配置在 256MB 到 2GB 之间,通常情况下使用默认值就可以了,但如果系统资源比较充足可以适当调大点。 block-cache-size = "256MB" TiKV 内存使用情况 除了以上列出的 block-cache 以及 write-buffer 会占用系统内存外: 需预留一些内存作为系统的 page cache TiKV 在处理大的查询的时候(例如 select * from ...)会读取数据然后在内存中生成对应的数据结构返回给 TiDB,这个过程中 TiKV 会占用一部分内存 TiKV 机器配置推荐 生产环境中,不建议将 TiKV 部署在 CPU 核数小于 8 或内存低于 32GB 的机器上 如果对写入吞吐要求比较高,建议使用吞吐能力比较好的磁盘 如果对读写的延迟要求非常高,建议使用 IOPS 比较高的 SSD 盘 "}, {"url": "https://pingcap.com/docs-cn/v1.0/op-guide/tune-tikv/", "title": "TiKV 性能参数调优", "content": " TiKV 性能参数调优 本文档用于描述如何根据机器配置情况来调整 TiKV 的参数,使 TiKV 的性能达到最优。TiKV 最底层使用的是 RocksDB 做为持久化存储,所以 TiKV 的很多性能相关的参数都是与 RocksDB 相关的。TiKV 使用了两个 RocksDB 实例,默认 RocksDB 实例存储 KV 数据,Raft RocksDB 实例(简称 RaftDB)存储 Raft 数据。TiKV 使用了 RocksDB 的 Column Falimies 特性。默认 RocksDB 实例将 KV 数据存储在内部的 default、write 和 lock 3 个 CF 内。 default CF 存储的是真正的数据,与其对应的参数位于 [rocksdb.defaultcf] 项中; write CF 存储的是数据的版本信息(MVCC)以及索引相关的数据,相关的参数位于 [rocksdb.writecf] 项中; lock CF 存储的是锁信息,系统使用默认参数。 Raft RocksDB 实例存储 Raft log。 default CF 主要存储的是 raft log,与其对应的参数位于 [raftdb.defaultcf] 项中。 每个 CF 都有单独的 block-cache,用于缓存数据块,加速 RocksDB 的读取速度,block-cache 的大小通过参数 block-cache-size 控制,block-cache-size 越大,能够缓存的热点数据越多,对读取操作越有利,同时占用的系统内存也会越多。每个 CF 有各自的 write-buffer,大小通过 write-buffer-size 控制。参数说明 # 日志级别,可选值为:trace,debug,info,warn,error,off log-level = "info" [server] # 监听地址 # addr = "127.0.0.1:20160" # 建议使用默认值 # notify-capacity = 40960 # messages-per-tick = 4096 # gRPC 线程池大小 # grpc-concurrency = 4 # TiKV 每个实例之间的 gRPC 连接数 # grpc-raft-conn-num = 10 # TiDB 过来的大部分读请求都会发送到 TiKV 的 coprocessor 进行处理,该参数用于设置 # coprocessor 线程的个数,如果业务是读请求比较多,增加 coprocessor 的线程数,但应比系统的 # CPU 核数小。例如:TiKV 所在的机器有 32 core,在重读的场景下甚至可以将该参数设置为 30。在没有 # 设置该参数的情况下,TiKV 会自动将该值设置为 CPU 总核数乘以 0.8。 # end-point-concurrency = 8 # 可以给 TiKV 实例打标签,用于副本的调度 # labels = {zone = "cn-east-1", host = "118", disk = "ssd"} [storage] # 数据目录 # data-dir = "/tmp/tikv/store" # 通常情况下使用默认值就可以了。在导数据的情况下建议将该参数设置为 1024000。 # scheduler-concurrency = 102400 # 该参数控制写入线程的个数,当写入操作比较频繁的时候,需要把该参数调大。使用 top -H -p tikv-pid # 发现名称为 sched-worker-pool 的线程都特别忙,这个时候就需要将 scheduler-worker-pool-size # 参数调大,增加写线程的个数。 # scheduler-worker-pool-size = 4 [pd] # pd 的地址 # endpoints = ["127.0.0.1:2379","127.0.0.2:2379","127.0.0.3:2379"] [metric] # 将 metrics 推送给 Prometheus pushgateway 的时间间隔 interval = "15s" # Prometheus pushgateway 的地址 address = "" job = "tikv" [raftstore] # 默认为 true,表示强制将数据刷到磁盘上。如果是非金融安全级别的业务场景,建议设置成 false, # 以便获得更高的性能。 sync-log = true # Raft RocksDB 目录。默认值是 [storage.data-dir] 的 raft 子目录。 # 如果机器上有多块磁盘,可以将 Raft RocksDB 的数据放在不同的盘上,提高 TiKV 的性能。 # raftdb-dir = "/tmp/tikv/store/raft" region-max-size = "384MB" # region 分裂阈值 region-split-size = "256MB" # 当 region 写入的数据量超过该阈值的时候,TiKV 会检查该 region 是否需要分裂。为了减少检查过程 # 中扫描数据的成本,数据过程中可以将该值设置为32MB,正常运行状态下使用默认值即可。 region-split-check-diff = "32MB" [rocksdb] # RocksDB 进行后台任务的最大线程数,后台任务包括 compaction 和 flush。具体 RocksDB 为什么需要进行 compaction, # 请参考 RocksDB 的相关资料。在写流量比较大的时候(例如导数据),建议开启更多的线程, # 但应小于 CPU 的核数。例如在导数据的时候,32 核 CPU 的机器,可以设置成 28。 # max-background-jobs = 8 # RocksDB 能够打开的最大文件句柄数。 # max-open-files = 40960 # RocksDB MANIFEST 文件的大小限制.
# 更详细的信息请参考:https://github.com/facebook/rocksdb/wiki/MANIFEST max-manifest-file-size = "20MB" # RocksDB write-ahead logs 目录。如果机器上有两块盘,可以将 RocksDB 的数据和 WAL 日志放在 # 不同的盘上,提高 TiKV 的性能。 # wal-dir = "/tmp/tikv/store" # 下面两个参数用于怎样处理 RocksDB 归档 WAL。 # 更多详细信息请参考:https://github.com/facebook/rocksdb/wiki/How-to-persist-in-memory-RocksDB-database%3F # wal-ttl-seconds = 0 # wal-size-limit = 0 # RocksDB WAL 日志的最大总大小,通常情况下使用默认值就可以了。 # max-total-wal-size = "4GB" # 可以通过该参数打开或者关闭 RocksDB 的统计信息。 # enable-statistics = true # 开启 RocksDB compaction 过程中的预读功能,如果使用的是机械磁盘,建议该值至少为2MB。 # compaction-readahead-size = "2MB" [rocksdb.defaultcf] # 数据块大小。RocksDB 是按照 block 为单元对数据进行压缩的,同时 block 也是缓存在 block-cache # 中的最小单元(类似其他数据库的 page 概念)。 block-size = "64KB" # RocksDB 每一层数据的压缩方式,可选的值为:no,snappy,zlib,bzip2,lz4,lz4hc,zstd。 # no:no:lz4:lz4:lz4:zstd:zstd 表示 level0 和 level1 不压缩,level2 到 level4 采用 lz4 压缩算法, # level5 和 level6 采用 zstd 压缩算法,。 # no 表示没有压缩,lz4 是速度和压缩比较为中庸的压缩算法,zlib 的压缩比很高,对存储空间比较友 # 好,但是压缩速度比较慢,压缩的时候需要占用较多的 CPU 资源。不同的机器需要根据 CPU 以及 I/O 资 # 源情况来配置怎样的压缩方式。例如:如果采用的压缩方式为"no:no:lz4:lz4:lz4:zstd:zstd",在大量 # 写入数据的情况下(导数据),发现系统的 I/O 压力很大(使用 iostat 发现 %util 持续 100% 或者使 # 用 top 命令发现 iowait 特别多),而 CPU 的资源还比较充裕,这个时候可以考虑将 level0 和 # level1 开启压缩,用 CPU 资源换取 I/O 资源。如果采用的压缩方式 # 为"no:no:lz4:lz4:lz4:zstd:zstd",在大量写入数据的情况下,发现系统的 I/O 压力不大,但是 CPU # 资源已经吃光了,top -H 发现有大量的 bg 开头的线程(RocksDB 的 compaction 线程)在运行,这 # 个时候可以考虑用 I/O 资源换取 CPU 资源,将压缩方式改成"no:no:no:lz4:lz4:zstd:zstd"。总之,目 # 的是为了最大限度地利用系统的现有资源,使 TiKV 的性能在现有的资源情况下充分发挥。 compression-per-level = ["no", "no", "lz4", "lz4", "lz4", "zstd", "zstd"] # RocksDB memtable 的大小。 write-buffer-size = "128MB" # 最多允许几个 memtable 存在。写入到 RocksDB 的数据首先会记录到 WAL 日志里面,然后会插入到 # memtable 里面,当 memtable 的大小到达了 write-buffer-size 限定的大小的时候,当前的 # memtable 会变成只读的,然后生成一个新的 memtable 接收新的写入。只读的 memtable 会被 # RocksDB 的 flush 线程(max-background-flushes 参数能够控制 flush 线程的最大个数) # flush 到磁盘,成为 level0 的一个 sst 文件。当 flush 线程忙不过来,导致等待 flush 到磁盘的 # memtable 的数量到达 max-write-buffer-number 限定的个数的时候,RocksDB 会将新的写入 # stall 住,stall 是 RocksDB 的一种流控机制。在导数据的时候可以将 max-write-buffer-number # 的值设置的更大一点,例如 10。 max-write-buffer-number = 5 # 当 level0 的 sst 文件个数到达 level0-slowdown-writes-trigger 指定的限度的时候, # RocksDB 会尝试减慢写入的速度。因为 level0 的 sst 太多会导致 RocksDB 的读放大上升。 # level0-slowdown-writes-trigger 和 level0-stop-writes-trigger 是 RocksDB 进行流控的 # 另一个表现。当 level0 的 sst 的文件个数到达 4(默认值),level0 的 sst 文件会和 level1 中 # 有 overlap 的 sst 文件进行 compaction,缓解读放大的问题。 level0-slowdown-writes-trigger = 20 # 当 level0 的 sst 文件个数到达 level0-stop-writes-trigger 指定的限度的时候,RocksDB 会 # stall 住新的写入。 level0-stop-writes-trigger = 36 # 当 level1 的数据量大小达到 max-bytes-for-level-base 限定的值的时候,会触发 level1 的 # sst 和 level2 种有 overlap 的 sst 进行 compaction。 # 黄金定律:max-bytes-for-level-base 的设置的第一参考原则就是保证和 level0 的数据量大致相 # 等,这样能够减少不必要的 compaction。例如压缩方式为"no:no:lz4:lz4:lz4:lz4:lz4",那么 # max-bytes-for-level-base 的值应该是 write-buffer-size 的大小乘以 4,因为 level0 和 # level1 都没有压缩,而且 level0 触发 compaction 的条件是 sst 的个数到达 4(默认值)。在 # level0 和 level1 都采取了压缩的情况下,就需要分析下 RocksDB 的日志,看一个 memtable 的压 # 缩成一个 sst 文件的大小大概是多少,例如 32MB,那么 max-bytes-for-level-base 的建议值就应 # 该是 32MB * 4 = 128MB。 max-bytes-for-level-base = "512MB" # sst 文件的大小。level0 的 sst 文件的大小受 write-buffer-size 和 level0 采用的压缩算法的 # 影响,target-file-size-base 参数用于控制 level1-level6 单个 sst 文件的大小。 target-file-size-base = "32MB" # 在不配置该参数的情况下,TiKV 会将该值设置为系统总内存量的 40%。如果需要在单个物理机上部署多个 # TiKV 节点,需要显式配置该参数,否则 TiKV 容易出现 OOM 的问题。 # block-cache-size = "1GB" [rocksdb.writecf] # 保持和 rocksdb.defaultcf.compression-per-level 一致。 compression-per-level = ["no", "no", "lz4", "lz4", "lz4", "zstd", "zstd"] # 保持和 rocksdb.defaultcf.write-buffer-size 一致。 write-buffer-size = "128MB" max-write-buffer-number = 5 min-write-buffer-number-to-merge = 1 # 保持和 rocksdb.defaultcf.max-bytes-for-level-base 一致。 max-bytes-for-level-base = "512MB" target-file-size-base = "32MB" # 在不配置该参数的情况下,TiKV 会将该值设置为系统总内存量的 15%。如果需要在单个物理机上部署多个 # TiKV 节点,需要显式配置该参数。版本信息(MVCC)相关的数据以及索引相关的数据都记录在 write 这 # 个 cf 里面,如果业务的场景下单表索引较多,可以将该参数设置的更大一点。 # block-cache-size = "256MB" [raftdb] # RaftDB 能够打开的最大文件句柄数。 # max-open-files = 40960 # 可以通过该参数打开或者关闭 RaftDB 的统计信息。 # enable-statistics = true # 开启 RaftDB compaction 过程中的预读功能,如果使用的是机械磁盘,建议该值至少为2MB。 # compaction-readahead-size = "2MB" [raftdb.defaultcf] # 保持和 rocksdb.defaultcf.compression-per-level 一致。 compression-per-level = ["no", "no", "lz4", "lz4", "lz4", "zstd", "zstd"] # 保持和 rocksdb.defaultcf.write-buffer-size 一致。 write-buffer-size = "128MB" max-write-buffer-number = 5 min-write-buffer-number-to-merge = 1 # 保持和 rocksdb.defaultcf.max-bytes-for-level-base 一致。 max-bytes-for-level-base = "512MB" target-file-size-base = "32MB" # 通常配置在 256MB 到 2GB 之间,通常情况下使用默认值就可以了,但如果系统资源比较充足可以适当调大点。 block-cache-size = "256MB" TiKV 内存使用情况 除了以上列出的 block-cache 以及 write-buffer 会占用系统内存外: 需预留一些内存作为系统的 page cache TiKV 在处理大的查询的时候(例如 select * from ...)会读取数据然后在内存中生成对应的数据结构返回给 TiDB,这个过程中 TiKV 会占用一部分内存 TiKV 机器配置推荐 生产环境中,不建议将 TiKV 部署在 CPU 核数小于 8 或内存低于 32GB 的机器上 如果对写入吞吐要求比较高,建议使用吞吐能力比较好的磁盘 如果对读写的延迟要求非常高,建议使 …"}, {"url": "https://pingcap.com/docs-cn/v2.0/op-guide/tune-tikv/", "title": "TiKV 性能参数调优", "content": " TiKV 性能参数调优 本文档用于描述如何根据机器配置情况来调整 TiKV 的参数,使 TiKV 的性能达到最优。TiKV 最底层使用的是 RocksDB 做为持久化存储,所以 TiKV 的很多性能相关的参数都是与 RocksDB 相关的。TiKV 使用了两个 RocksDB 实例,默认 RocksDB 实例存储 KV 数据,Raft RocksDB 实例(简称 RaftDB)存储 Raft 数据。TiKV 使用了 RocksDB 的 Column Falimies 特性。默认 RocksDB 实例将 KV 数据存储在内部的 default、write 和 lock 3 个 CF 内。 default CF 存储的是真正的数据,与其对应的参数位于 [rocksdb.defaultcf] 项中; write CF 存储的是数据的版本信息(MVCC)以及索引相关的数据,相关的参数位于 [rocksdb.writecf] 项中; lock CF 存储的是锁信息,系统使用默认参数。 Raft RocksDB 实例存储 Raft log。 default CF 主要存储的是 raft log,与其对应的参数位于 [raftdb.defaultcf] 项中。 每个 CF 都有单独的 block-cache,用于缓存数据块,加速 RocksDB 的读取速度,block-cache 的大小通过参数 block-cache-size 控制,block-cache-size 越大,能够缓存的热点数据越多,对读取操作越有利,同时占用的系统内存也会越多。每个 CF 有各自的 write-buffer,大小通过 write-buffer-size 控制。参数说明 # 日志级别,可选值为:trace,debug,info,warn,error,off log-level = "info" [server] # 监听地址 # addr = "127.0.0.1:20160" # 建议使用默认值 # notify-capacity = 40960 # messages-per-tick = 4096 # gRPC 线程池大小 # grpc-concurrency = 4 # TiKV 每个实例之间的 gRPC 连接数 # grpc-raft-conn-num = 10 # TiDB 过来的大部分读请求都会发送到 TiKV 的 coprocessor 进行处理,该参数用于设置 # coprocessor 线程的个数,如果业务是读请求比较多,增加 coprocessor 的线程数,但应比系统的 # CPU 核数小。例如:TiKV 所在的机器有 32 core,在重读的场景下甚至可以将该参数设置为 30。在没有 # 设置该参数的情况下,TiKV 会自动将该值设置为 CPU 总核数乘以 0.8。 # end-point-concurrency = 8 # 可以给 TiKV 实例打标签,用于副本的调度 # labels = {zone = "cn-east-1", host = "118", disk = "ssd"} [storage] # 数据目录 # data-dir = "/tmp/tikv/store" # 通常情况下使用默认值就可以了。在导数据的情况下建议将该参数设置为 1024000。 # scheduler-concurrency = 102400 # 该参数控制写入线程的个数,当写入操作比较频繁的时候,需要把该参数调大。使用 top -H -p tikv-pid # 发现名称为 sched-worker-pool 的线程都特别忙,这个时候就需要将 scheduler-worker-pool-size # 参数调大,增加写线程的个数。 # scheduler-worker-pool-size = 4 [pd] # pd 的地址 # endpoints = ["127.0.0.1:2379","127.0.0.2:2379","127.0.0.3:2379"] [metric] # 将 metrics 推送给 Prometheus pushgateway 的时间间隔 interval = "15s" # Prometheus pushgateway 的地址 address = "" job = "tikv" [raftstore] # 默认为 true,表示强制将数据刷到磁盘上。如果是非金融安全级别的业务场景,建议设置成 false, # 以便获得更高的性能。 sync-log = true # Raft RocksDB 目录。默认值是 [storage.data-dir] 的 raft 子目录。 # 如果机器上有多块磁盘,可以将 Raft RocksDB 的数据放在不同的盘上,提高 TiKV 的性能。 # raftdb-dir = "/tmp/tikv/store/raft" region-max-size = "384MB" # region 分裂阈值 region-split-size = "256MB" # 当 region 写入的数据量超过该阈值的时候,TiKV 会检查该 region 是否需要分裂。为了减少检查过程 # 中扫描数据的成本,数据过程中可以将该值设置为32MB,正常运行状态下使用默认值即可。 region-split-check-diff = "32MB" [rocksdb] # RocksDB 进行后台任务的最大线程数,后台任务包括 compaction 和 flush。具体 RocksDB 为什么需要进行 compaction, # 请参考 RocksDB 的相关资料。在写流量比较大的时候(例如导数据),建议开启更多的线程, # 但应小于 CPU 的核数。例如在导数据的时候,32 核 CPU 的机器,可以设置成 28。 # max-background-jobs = 8 # RocksDB 能够打开的最大文件句柄数。 # max-open-files = 40960 # RocksDB MANIFEST 文件的大小限制.
# 更详细的信息请参考:https://github.com/facebook/rocksdb/wiki/MANIFEST max-manifest-file-size = "20MB" # RocksDB write-ahead logs 目录。如果机器上有两块盘,可以将 RocksDB 的数据和 WAL 日志放在 # 不同的盘上,提高 TiKV 的性能。 # wal-dir = "/tmp/tikv/store" # 下面两个参数用于怎样处理 RocksDB 归档 WAL。 # 更多详细信息请参考:https://github.com/facebook/rocksdb/wiki/How-to-persist-in-memory-RocksDB-database%3F # wal-ttl-seconds = 0 # wal-size-limit = 0 # RocksDB WAL 日志的最大总大小,通常情况下使用默认值就可以了。 # max-total-wal-size = "4GB" # 可以通过该参数打开或者关闭 RocksDB 的统计信息。 # enable-statistics = true # 开启 RocksDB compaction 过程中的预读功能,如果使用的是机械磁盘,建议该值至少为2MB。 # compaction-readahead-size = "2MB" [rocksdb.defaultcf] # 数据块大小。RocksDB 是按照 block 为单元对数据进行压缩的,同时 block 也是缓存在 block-cache # 中的最小单元(类似其他数据库的 page 概念)。 block-size = "64KB" # RocksDB 每一层数据的压缩方式,可选的值为:no,snappy,zlib,bzip2,lz4,lz4hc,zstd。 # no:no:lz4:lz4:lz4:zstd:zstd 表示 level0 和 level1 不压缩,level2 到 level4 采用 lz4 压缩算法, # level5 和 level6 采用 zstd 压缩算法,。 # no 表示没有压缩,lz4 是速度和压缩比较为中庸的压缩算法,zlib 的压缩比很高,对存储空间比较友 # 好,但是压缩速度比较慢,压缩的时候需要占用较多的 CPU 资源。不同的机器需要根据 CPU 以及 I/O 资 # 源情况来配置怎样的压缩方式。例如:如果采用的压缩方式为"no:no:lz4:lz4:lz4:zstd:zstd",在大量 # 写入数据的情况下(导数据),发现系统的 I/O 压力很大(使用 iostat 发现 %util 持续 100% 或者使 # 用 top 命令发现 iowait 特别多),而 CPU 的资源还比较充裕,这个时候可以考虑将 level0 和 # level1 开启压缩,用 CPU 资源换取 I/O 资源。如果采用的压缩方式 # 为"no:no:lz4:lz4:lz4:zstd:zstd",在大量写入数据的情况下,发现系统的 I/O 压力不大,但是 CPU # 资源已经吃光了,top -H 发现有大量的 bg 开头的线程(RocksDB 的 compaction 线程)在运行,这 # 个时候可以考虑用 I/O 资源换取 CPU 资源,将压缩方式改成"no:no:no:lz4:lz4:zstd:zstd"。总之,目 # 的是为了最大限度地利用系统的现有资源,使 TiKV 的性能在现有的资源情况下充分发挥。 compression-per-level = ["no", "no", "lz4", "lz4", "lz4", "zstd", "zstd"] # RocksDB memtable 的大小。 write-buffer-size = "128MB" # 最多允许几个 memtable 存在。写入到 RocksDB 的数据首先会记录到 WAL 日志里面,然后会插入到 # memtable 里面,当 memtable 的大小到达了 write-buffer-size 限定的大小的时候,当前的 # memtable 会变成只读的,然后生成一个新的 memtable 接收新的写入。只读的 memtable 会被 # RocksDB 的 flush 线程(max-background-flushes 参数能够控制 flush 线程的最大个数) # flush 到磁盘,成为 level0 的一个 sst 文件。当 flush 线程忙不过来,导致等待 flush 到磁盘的 # memtable 的数量到达 max-write-buffer-number 限定的个数的时候,RocksDB 会将新的写入 # stall 住,stall 是 RocksDB 的一种流控机制。在导数据的时候可以将 max-write-buffer-number # 的值设置的更大一点,例如 10。 max-write-buffer-number = 5 # 当 level0 的 sst 文件个数到达 level0-slowdown-writes-trigger 指定的限度的时候, # RocksDB 会尝试减慢写入的速度。因为 level0 的 sst 太多会导致 RocksDB 的读放大上升。 # level0-slowdown-writes-trigger 和 level0-stop-writes-trigger 是 RocksDB 进行流控的 # 另一个表现。当 level0 的 sst 的文件个数到达 4(默认值),level0 的 sst 文件会和 level1 中 # 有 overlap 的 sst 文件进行 compaction,缓解读放大的问题。 level0-slowdown-writes-trigger = 20 # 当 level0 的 sst 文件个数到达 level0-stop-writes-trigger 指定的限度的时候,RocksDB 会 # stall 住新的写入。 level0-stop-writes-trigger = 36 # 当 level1 的数据量大小达到 max-bytes-for-level-base 限定的值的时候,会触发 level1 的 # sst 和 level2 种有 overlap 的 sst 进行 compaction。 # 黄金定律:max-bytes-for-level-base 的设置的第一参考原则就是保证和 level0 的数据量大致相 # 等,这样能够减少不必要的 compaction。例如压缩方式为"no:no:lz4:lz4:lz4:lz4:lz4",那么 # max-bytes-for-level-base 的值应该是 write-buffer-size 的大小乘以 4,因为 level0 和 # level1 都没有压缩,而且 level0 触发 compaction 的条件是 sst 的个数到达 4(默认值)。在 # level0 和 level1 都采取了压缩的情况下,就需要分析下 RocksDB 的日志,看一个 memtable 的压 # 缩成一个 sst 文件的大小大概是多少,例如 32MB,那么 max-bytes-for-level-base 的建议值就应 # 该是 32MB * 4 = 128MB。 max-bytes-for-level-base = "512MB" # sst 文件的大小。level0 的 sst 文件的大小受 write-buffer-size 和 level0 采用的压缩算法的 # 影响,target-file-size-base 参数用于控制 level1-level6 单个 sst 文件的大小。 target-file-size-base = "32MB" # 在不配置该参数的情况下,TiKV 会将该值设置为系统总内存量的 40%。如果需要在单个物理机上部署多个 # TiKV 节点,需要显式配置该参数,否则 TiKV 容易出现 OOM 的问题。 # block-cache-size = "1GB" [rocksdb.writecf] # 保持和 rocksdb.defaultcf.compression-per-level 一致。 compression-per-level = ["no", "no", "lz4", "lz4", "lz4", "zstd", "zstd"] # 保持和 rocksdb.defaultcf.write-buffer-size 一致。 write-buffer-size = "128MB" max-write-buffer-number = 5 min-write-buffer-number-to-merge = 1 # 保持和 rocksdb.defaultcf.max-bytes-for-level-base 一致。 max-bytes-for-level-base = "512MB" target-file-size-base = "32MB" # 在不配置该参数的情况下,TiKV 会将该值设置为系统总内存量的 15%。如果需要在单个物理机上部署多个 # TiKV 节点,需要显式配置该参数。版本信息(MVCC)相关的数据以及索引相关的数据都记录在 write 这 # 个 cf 里面,如果业务的场景下单表索引较多,可以将该参数设置的更大一点。 # block-cache-size = "256MB" [raftdb] # RaftDB 能够打开的最大文件句柄数。 # max-open-files = 40960 # 可以通过该参数打开或者关闭 RaftDB 的统计信息。 # enable-statistics = true # 开启 RaftDB compaction 过程中的预读功能,如果使用的是机械磁盘,建议该值至少为2MB。 # compaction-readahead-size = "2MB" [raftdb.defaultcf] # 保持和 rocksdb.defaultcf.compression-per-level 一致。 compression-per-level = ["no", "no", "lz4", "lz4", "lz4", "zstd", "zstd"] # 保持和 rocksdb.defaultcf.write-buffer-size 一致。 write-buffer-size = "128MB" max-write-buffer-number = 5 min-write-buffer-number-to-merge = 1 # 保持和 rocksdb.defaultcf.max-bytes-for-level-base 一致。 max-bytes-for-level-base = "512MB" target-file-size-base = "32MB" # 通常配置在 256MB 到 2GB 之间,通常情况下使用默认值就可以了,但如果系统资源比较充足可以适当调大点。 block-cache-size = "256MB" TiKV 内存使用情况 除了以上列出的 block-cache 以及 write-buffer 会占用系统内存外: 需预留一些内存作为系统的 page cache TiKV 在处理大的查询的时候(例如 select * from ...)会读取数据然后在内存中生成对应的数据结构返回给 TiDB,这个过程中 TiKV 会占用一部分内存 TiKV 机器配置推荐 生产环境中,不建议将 TiKV 部署在 CPU 核数小于 8 或内存低于 32GB 的机器上 如果对写入吞吐要求比较高,建议使用吞吐能力比较好的磁盘 如果对读写的延迟要求非常高,建议使 …"}, {"url": "https://pingcap.com/recruit-cn/engineering/tikv-engineer/", "title": "TiKV 研发工程师", "content": " TiKV 研发工程师 岗位职责: 负责分布式数据库 TiKV 相关的设计,开发; 负责构建分布式压力测试框架,稳定性测试框架。 任职要求: 三年以上相关领域开发经验,扎实的编程能力,精通 C/C++/Go/Rust 中的一种; 对分布式系统的架构和原理有比较深入的了解; 优秀的发现和解决问题能力,良好的沟通能力,具备团队合作精神。 加分项: 拥抱开源,对前沿技术有浓厚的热情和探索欲望,有开源项目经历; 熟悉 Paxos/Raft 等分布式一致性算法; 熟悉分布式事务模型; 熟悉操作系统底层知识,有 TCP/IP、IO 等系统调优经验。 待遇:25K - 50K + 期权,13薪 + 奖金,优秀者可面议工作地点:北京,上海,广州,杭州,成都,特别优秀可 Remote"}, {"url": "https://pingcap.com/docs-cn/op-guide/dashboard-tikv-info/", "title": "TiKV 重要监控指标详解", "content": " TiKV 重要监控指标详解 使用 Ansible 部署 TiDB 集群时,一键部署监控系统 (Prometheus/Grafana),监控架构请看 TiDB 监控框架概述。目前 Grafana Dashboard 整体分为 PD、TiDB、TiKV、Node_exporter、Overview 等。对于日常运维,我们通过观察 TiKV 面板上的 Metrics,可以了解 TiKV 当前的状态。以下为 TiKV Dashboard 监控说明:Cluster Store size:每个 TiKV 实例的使用的存储空间的大小 Available size:每个 TiKV 实例的可用的存储空间的大小 Capacity size:每个 TiKV 实例的存储容量的大小 CPU:每个 TiKV 实例 CPU 的使用率 Memory:每个 TiKV 实例内存的使用情况 IO utilization:每个 TiKV 实例 IO 的使用率 MBps:每个 TiKV 实例写入和读取的数据量大小 QPS:每个 TiKV 实例上各种命令的 QPS Errps:每个 TiKV 实例上 gRPC 消息失败的个数 leader:每个 TiKV 实例 leader 的个数 Region:每个 TiKV 实例 Region 的个数 Errors Server is busy:各种会导致 server 繁忙的事件个数,如 write stall,channel full 等,正常情况下应当为 0 Server report failures:server 报错的消息个数,正常情况下应当为 0 Raftstore error:每个 TiKV 实例上 raftstore 发生错误的个数 Scheduler error:每个 TiKV 实例上 scheduler 发生错误的个数 Coprocessor error:每个 TiKV 实例上 coprocessor 发生错误的个数 gRPC message error:每个 TiKV 实例上 gRPC 消息发生错误的个数 Leader drop:每个 TiKV 实例上 drop leader 的个数 Leader missing:每个 TiKV 实例上 missing leader 的个数 Server Leader:每个 TiKV 实例 leader 的个数 Region:每个 TiKV 实例 Region 的个数 CF size:每个 CF 的大小 Store size:每个 TiKV 实例的使用的存储空间的大小 Channel full:每个 TiKV 实例上 channel full 错误的数量,正常情况下应当为 0 Server report failures:server 报错的消息个数,正常情况下应当为 0 Region average written keys:每个 TiKV 实例上所有 Region 的平均 key 写入个数 Region average written bytes:每个 TiKV 实例上所有 Region 的平均写入大小 Active written leaders:每个 TiKV 实例上有效的 leader 个数 Approximate Region size:每个 Region 近似的大小 Raft IO Apply log duration:Raft apply 日志所花费的时间 Apply log duration per server:每个 TiKV 实例上 Raft apply 日志所花费的时间 Append log duration:Raft append 日志所花费的时间 Append log duration per server:每个 TiKV 实例上 Raft append 日志所花费的时间 Raft process Ready handled:Raft 中不同 ready 类型的个数 Process ready duration per server:每个 TiKV 实例处理 ready 所花费的时间,99.99% 的情况下,应该小于 2s Process tick duration per server:每个 TiKV 实例处理 tick 所花费的时间 0.99 Duration of Raft store events:99% 的 raftstore 事件所花费的时间 Raft message Sent messages per server:每个 TiKV 实例发送 Raft 消息的个数 Flush messages per server:每个 TiKV 实例持久化 Raft 消息的个数 Receive messages per server:每个 TiKV 实例接受 Raft 消息的个数 Messages:发送不同类型的 Raft 消息的个数 Vote:Raft 投票消息发送的个数 Raft dropped messages:丢弃不同类型的 Raft 消息的个数 Raft propose Raft proposals per ready:在一个 mio tick 内,所有 Region proposal 的个数 Raft read/write proposals:不同类型的 proposal 的个数 Raft read proposals per server:每个 TiKV 实例发起读 proposal 的个数 Raft write proposals per server:每个 TiKV 实例发起写 proposal 的个数 Propose wait duration:每个 proposal 的等待时间 Propose wait duration per server:每个 TiKV 实例上每个 proposal 的等待时间 Raft log speed:peer propose 日志的速度 Raft admin Admin proposals:admin proposal 的个数 Admin apply:apply 命令的个数 Check split:split check 命令的个数 99.99% Check split duration:99.99% 的情况下,split check 所需花费的时间 Local reader Local reader requests:所有请求的总数以及 local read 线程拒绝的请求数量 Local read requests duration:local read 请求的等待时间 Local read requests batch size:local read 请求的批量大小 Storage Storage command total:收到不同命令的个数 Storage async request error:异步请求出错的个数 Storage async snapshot duration:异步处理 snapshot 所花费的时间,99% 的情况下,应该小于 1s Storage async write duration:异步写所花费的时间,99% 的情况下,应该小于 1s Scheduler Scheduler stage total:每种命令不同阶段的个数,正常情况下,不会在短时间内出现大量的错误 Scheduler priority commands:不同优先级命令的个数 Scheduler pending commands:每个 TiKV 实例上 pending 命令的个数 Scheduler - batch_get Scheduler stage total:batch_get 中每个命令所处不同阶段的个数,正常情况下,不会在短时间内出现大量的错误 Scheduler command duration:执行 batch_get 命令所需花费的时间,正常情况下,应该小于 1s Scheduler latch wait duration:由于 latch wait 造成的时间开销,正常情况下,应该小于 1s Scheduler keys read:batch_get 命令读取 key 的个数 Scheduler keys written:batch_get 命令写入 key 的个数 Scheduler scan details:执行 batch_get 命令时,扫描每个 CF 中 key 的详细情况 Scheduler scan details:执行 batch_get 命令时,扫描每个 lock CF 中 key 的详细情况 Scheduler scan details [write]:执行 batch_get 命令时,扫描每个 write CF 中 key 的详细情况 Scheduler scan details [default]:执行 batch_get 命令时,扫描每个 default CF 中 key 的详细情况 Scheduler - cleanup Scheduler stage total:cleanup 中每个命令所处不同阶段的个数,正常情况下,不会在短时间内出现大量的错误 Scheduler command duration:执行 cleanup 命令所需花费的时间,正常情况下,应该小于 1s Scheduler latch wait duration:由于 latch wait 造成的时间开销,正常情况下,应该小于 1s Scheduler keys read:cleanup 命令读取 key 的个数 Scheduler keys written:cleanup 命令写入 key 的个数 Scheduler scan details:执行 cleanup 命令时,扫描每个 CF 中 key 的详细情况 Scheduler scan details [lock]:执行 cleanup 命令时,扫描每个 lock CF 中 key 的详细情况 Scheduler scan details [write]:执行 cleanup 命令时,扫描每个 write CF 中 key 的详细情况 Scheduler scan details [default]:执行 cleanup 命令时,扫描每个 default CF 中 key 的详细情况 Scheduler - commit Scheduler stage total:commit 中每个命令所处不同阶段的个数,正常情况下,不会在短时间内出现大量的错误 Scheduler command duration:执行 commit 命令所需花费的时间,正常情况下,应该小于 1s Scheduler latch wait duration:由于 latch wait 造成的时间开销,正常情况下,应该小于 1s Scheduler keys read:commit 命令读取 key 的个数 Scheduler keys written:commit 命令写入 key 的个数 Scheduler scan details:执行 commit 命令时,扫描每个 CF 中 key 的详细情况 Scheduler scan details [lock]:执行 commit 命令时,扫描每个 lock CF 中 key 的详细情况 Scheduler scan details [write]:执行 commit 命令时,扫描每个 write CF 中 key 的详细情况 Scheduler scan details [default]:执行 commit 命令时,扫描每个 default CF 中 key 的详细情况 Scheduler - gc Scheduler stage total:gc 中每个命令所处不同阶段的个数,正常情况下,不会在短时间内出现大量的错误 Scheduler command duration:执行 gc 命令所需花费的时间,正常情况下,应该小于 1s Scheduler latch wait duration:由于 latch wait 造成的时间开销,正常情况下,应该小于 1s Scheduler keys read:gc 命令读取 key 的个数 Scheduler keys written:gc 命令写入 key 的个数 Scheduler scan details:执行 gc 命令时,扫描每个 CF 中 key 的详细情况 Scheduler scan details [lock]:执行 gc 命令时,扫描每个 lock CF 中 key 的详细情况 Scheduler scan details [write]:执行 gc 命令时,扫描每个 write CF 中 key 的详细情况 Scheduler scan details [default]:执行 gc 命令时,扫描每个 default CF 中 key 的详细情况 Scheduler - get Scheduler stage total:get 中每个命令所处不同阶段的个数,正常情况下,不会在短时间内出现大量的错误 Scheduler command duration:执行 get 命令所需花费的时间,正常情况下,应该小于 1s Scheduler latch wait duration:由于 latch wait 造成的时间开销,正常情况下,应该小于 1s Scheduler keys read:get 命令读取 key 的个数 Scheduler keys written:get 命令写入 key 的个数 Scheduler scan details:执行 get 命令时,扫描每个 CF 中 key 的详细情况 Scheduler scan details [lock]:执行 get 命令时,扫描每个 lock CF 中 key 的详细情况 Scheduler scan details [write]:执行 get 命令时,扫描每个 write CF 中 key 的详细情况 Scheduler scan details [default]:执行 get 命令时,扫描每个 default CF 中 key 的详细情况 Scheduler - key_mvcc Scheduler stage total:key_mvcc 中每个命令所处不同阶段的个数,正常情况下,不会在短时间内出现大量的错误 Scheduler command duration:执行 key_mvcc 命令所需花费的时间,正常情况下,应该小于 1s Scheduler latch wait duration:由于 latch wait 造成的时间开销,正常情况下,应该小于 1s Scheduler keys read:key_mvcc 命令读取 key 的个数 Scheduler keys written:key_mvcc 命令写入 key 的个数 Scheduler scan details:执行 key_mvcc 命令时,扫描每个 CF 中 key 的详细情况 Scheduler scan details [lock]:执行 key_mvcc 命令时,扫描每个 lock CF 中 key 的详细情况 Scheduler scan details [write]:执行 key_mvcc 命令时,扫描每个 write CF 中 key 的详细情况 Scheduler scan details [default]:执行 key_mvcc 命令时,扫描每个 default CF 中 key 的详细情况 Scheduler - prewrite Scheduler stage total:prewrite 中每个命令所处不同阶段的个数,正常情况下,不会在短时间内出现大量的错误 Scheduler command duration:执行 prewrite 命令所需花费的时间,正常情况下,应该小于 1s Scheduler latch wait duration:由于 latch wait 造成的时间开销,正常情况下,应该小于 1s Scheduler keys read:prewrite 命令读取 key 的个数 Scheduler keys written:prewrite 命令写入 key 的个数 Scheduler scan details:执行 prewrite 命令时,扫描每个 CF 中 key 的详细情况 Scheduler scan details [lock]:执行 prewrite 命令时,扫描每个 lock CF 中 key 的详细情况 Scheduler scan details [write]:执行 prewrite 命令时,扫描每个 write CF 中 key 的详细情况 Scheduler scan details [default]:执行 prewrite 命令时,扫描每个 default CF 中 key 的详细情况 Scheduler - resolve_lock Scheduler stage total:resolve_lock 中每个命令所处不同阶段的个数,正常情况下,不会在短时间内出现大量的错误 Scheduler command duration:执行 resolve_lock 命令所需花费的时间,正常情况下,应该小于 1s Scheduler latch wait duration:由于 latch wait 造成的时间开销,正常情况下,应该小于 1s Scheduler keys read:resolve_lock 命令读取 key 的个数 Scheduler keys written:resolve_lock 命令写入 key 的个数 Scheduler scan details:执行 resolve_lock 命令时,扫描每个 CF 中 key 的详细情况 Scheduler scan details [lock]:执行 resolve_lock 命令时,扫描每个 lock CF 中 key 的详细情况 Scheduler scan details [write]:执行 resolve_lock 命令时,扫描每个 write CF 中 key 的详细情况 Scheduler scan details [default]:执行 resolve_lock 命令时,扫描每个 default CF 中 key 的详细情况 Scheduler - scan Scheduler stage total:scan 中每个命令所处不同阶段的个数,正常情况下,不会在短时间内出现大量的错误 Scheduler command duration:执行 scan 命令所需花费的时间,正常情况下,应该小于 1s Scheduler latch wait duration:由于 latch wait 造成的时间开销,正常情况下,应该小于 1s …"}, {"url": "https://pingcap.com/docs/tispark/tispark-quick-start-guide/", "title": "TiSpark Quick Start Guide", "content": " TiSpark Quick Start Guide To make it easy to try TiSpark, the TiDB cluster installed using TiDB-Ansible integrates Spark, TiSpark jar package and TiSpark sample data by default.Deployment information Spark is deployed by default in the spark folder in the TiDB instance deployment directory. The TiSpark jar package is deployed by default in the jars folder in the Spark deployment directory.spark/jars/tispark-SNAPSHOT-jar-with-dependencies.jar TiSpark sample data and import scripts are deployed by default in the TiDB-Ansible directory.tidb-ansible/resources/bin/tispark-sample-data Prepare the environment Install JDK on the TiDB instance Download the latest version of JDK 1.8 from Oracle JDK official download page. The version used in the following example is jdk-8u141-linux-x64.tar.gz.Extract the package and set the environment variables based on your JDK deployment directory.Edit the ~/.bashrc file. For example:export JAVA_HOME=/home/pingcap/jdk1.8.0_144 export PATH=$JAVA_HOME/bin:$PATH Verify the validity of JDK:$ java -version java version "1.8.0_144" Java(TM) SE Runtime Environment (build 1.8.0_144-b01) Java HotSpot(TM) 64-Bit Server VM (build 25.144-b01, mixed mode) Import the sample data Assume that the TiDB cluster is started. The service IP of one TiDB instance is 192.168.0.2, the port is 4000, the user name is root, and the password is null.cd tidb-ansible/resources/bin/tispark-sample-data Edit the TiDB login information in sample_data.sh. For example:mysql -h 192.168.0.2 -P 4000 -u root < dss.ddl Run the script:./sample_data.sh Note: You need to install the MySQL client on the machine that runs the script. If you are a CentOS user, you can install it through the command yum -y install mysql. Log into TiDB and verify that the TPCH_001 database and the following tables are included.$ mysql -uroot -P4000 -h192.168.0.2 MySQL [(none)]> show databases; +--------------------+ | Database | +--------------------+ | INFORMATION_SCHEMA | | PERFORMANCE_SCHEMA | | TPCH_001 | | mysql | | test | +--------------------+ 5 rows in set (0.00 sec) MySQL [(none)]> use TPCH_001 Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed MySQL [TPCH_001]> show tables; +--------------------+ | Tables_in_TPCH_001 | +--------------------+ | CUSTOMER | | LINEITEM | | NATION | | ORDERS | | PART | | PARTSUPP | | REGION | | SUPPLIER | +--------------------+ 8 rows in set (0.00 sec) Use example First start the spark-shell in the spark deployment directory:$ cd spark $ bin/spark-shellimport org.apache.spark.sql.TiContext val ti = new TiContext(spark) // Mapping all TiDB tables from `TPCH_001` database as Spark SQL tables ti.tidbMapDatabase("TPCH_001") Then you can call Spark SQL directly:scala> spark.sql("select count(*) from lineitem").show The result is:+--------+ |count(1)| +--------+ | 60175| +--------+ Now run a more complex Spark SQL:scala> spark.sql( """select | l_returnflag, | l_linestatus, | sum(l_quantity) as sum_qty, | sum(l_extendedprice) as sum_base_price, | sum(l_extendedprice * (1 - l_discount)) as sum_disc_price, | sum(l_extendedprice * (1 - l_discount) * (1 + l_tax)) as sum_charge, | avg(l_quantity) as avg_qty, | avg(l_extendedprice) as avg_price, | avg(l_discount) as avg_disc, | count(*) as count_order |from | lineitem |where | l_shipdate <= date '1998-12-01' - interval '90' day |group by | l_returnflag, | l_linestatus |order by | l_returnflag, | l_linestatus """.stripMargin).show The result is:+------------+------------+---------+--------------+--------------+ |l_returnflag|l_linestatus| sum_qty|sum_base_price|sum_disc_price| +------------+------------+---------+--------------+--------------+ | A| F|380456.00| 532348211.65|505822441.4861| | N| F| 8971.00| 12384801.37| 11798257.2080| | N| O|742802.00| 1041502841.45|989737518.6346| | R| F|381449.00| 534594445.35|507996454.4067| +------------+------------+---------+--------------+--------------+ (Continued) -----------------+---------+------------+--------+-----------+ sum_charge| avg_qty| avg_price|avg_disc|count_order| -----------------+---------+------------+--------+-----------+ 526165934.000839|25.575155|35785.709307|0.050081| 14876| 12282485.056933|25.778736|35588.509684|0.047759| 348| 1029418531.523350|25.454988|35691.129209|0.049931| 29181| 528524219.358903|25.597168|35874.006533|0.049828| 14902| -----------------+---------+------------+--------+-----------+ See more examples."}, {"url": "https://pingcap.com/docs/v1.0/tispark/tispark-quick-start-guide/", "title": "TiSpark Quick Start Guide", "content": " Quick Start Guide for the TiDB Connector for Spark To make it easy to try the TiDB Connector for Spark, TiDB cluster integrates Spark, TiSpark jar package and TiSpark sample data by default, in both the Pre-GA and master versions installed using TiDB-Ansible.Deployment information Spark is deployed by default in the spark folder in the TiDB instance deployment directory. The TiSpark jar package is deployed by default in the jars folder in the Spark deployment directory.spark/jars/tispark-0.1.0-beta-SNAPSHOT-jar-with-dependencies.jar TiSpark sample data and import scripts are deployed by default in the TiDB-Ansible directory.tidb-ansible/resources/bin/tispark-sample-data Prepare the environment Install JDK on the TiDB instance Download the latest version of JDK 1.8 from Oracle JDK official download page. The version used in the following example is jdk-8u141-linux-x64.tar.gz.Extract the package and set the environment variables based on your JDK deployment directory.Edit the ~/.bashrc file. For example:export JAVA_HOME=/home/pingcap/jdk1.8.0_144 export PATH=$JAVA_HOME/bin:$PATH Verify the validity of JDK:$ java -version java version "1.8.0_144" Java(TM) SE Runtime Environment (build 1.8.0_144-b01) Java HotSpot(TM) 64-Bit Server VM (build 25.144-b01, mixed mode) Import the sample data Assume that the TiDB cluster is started. The service IP of one TiDB instance is 192.168.0.2, the port is 4000, the user name is root, and the password is null.cd tidb-ansible/resources/bin/tispark-sample-data Edit the TiDB login information in sample_data.sh. For example:mysql -h 192.168.0.2 -P 4000 -u root < dss.ddl Run the script:./sample_data.sh Note: You need to install the MySQL client on the machine that runs the script. If you are a CentOS user, you can install it through the command yum -y install mysql. Log into TiDB and verify that the TPCH_001 database and the following tables are included.$ mysql -uroot -P4000 -h192.168.0.2 MySQL [(none)]> show databases; +--------------------+ | Database | +--------------------+ | INFORMATION_SCHEMA | | PERFORMANCE_SCHEMA | | TPCH_001 | | mysql | | test | +--------------------+ 5 rows in set (0.00 sec) MySQL [(none)]> use TPCH_001 Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed MySQL [TPCH_001]> show tables; +--------------------+ | Tables_in_TPCH_001 | +--------------------+ | CUSTOMER | | LINEITEM | | NATION | | ORDERS | | PART | | PARTSUPP | | REGION | | SUPPLIER | +--------------------+ 8 rows in set (0.00 sec) Use example Assume that the IP of your PD node is 192.168.0.2, and the port is 2379.First start the spark-shell in the spark deployment directory:$ cd spark $ bin/spark-shellimport org.apache.spark.sql.TiContext val ti = new TiContext(spark) // Mapping all TiDB tables from `TPCH_001` database as Spark SQL tables ti.tidbMapDatabase("TPCH_001") Then you can call Spark SQL directly:scala> spark.sql("select count(*) from lineitem").show The result is:+--------+ |count(1)| +--------+ | 60175| +--------+ Now run a more complex Spark SQL:scala> spark.sql( """select | l_returnflag, | l_linestatus, | sum(l_quantity) as sum_qty, | sum(l_extendedprice) as sum_base_price, | sum(l_extendedprice * (1 - l_discount)) as sum_disc_price, | sum(l_extendedprice * (1 - l_discount) * (1 + l_tax)) as sum_charge, | avg(l_quantity) as avg_qty, | avg(l_extendedprice) as avg_price, | avg(l_discount) as avg_disc, | count(*) as count_order |from | lineitem |where | l_shipdate <= date '1998-12-01' - interval '90' day |group by | l_returnflag, | l_linestatus |order by | l_returnflag, | l_linestatus """.stripMargin).show The result is:+------------+------------+---------+--------------+--------------+ |l_returnflag|l_linestatus| sum_qty|sum_base_price|sum_disc_price| +------------+------------+---------+--------------+--------------+ | A| F|380456.00| 532348211.65|505822441.4861| | N| F| 8971.00| 12384801.37| 11798257.2080| | N| O|742802.00| 1041502841.45|989737518.6346| | R| F|381449.00| 534594445.35|507996454.4067| +------------+------------+---------+--------------+--------------+ (Continued) -----------------+---------+------------+--------+-----------+ sum_charge| avg_qty| avg_price|avg_disc|count_order| -----------------+---------+------------+--------+-----------+ 526165934.000839|25.575155|35785.709307|0.050081| 14876| 12282485.056933|25.778736|35588.509684|0.047759| 348| 1029418531.523350|25.454988|35691.129209|0.049931| 29181| 528524219.358903|25.597168|35874.006533|0.049828| 14902| -----------------+---------+------------+--------+-----------+ See more examples."}, {"url": "https://pingcap.com/docs/v2.0/tispark/tispark-quick-start-guide/", "title": "TiSpark Quick Start Guide", "content": " TiSpark Quick Start Guide To make it easy to try TiSpark, the TiDB cluster installed using TiDB-Ansible integrates Spark, TiSpark jar package and TiSpark sample data by default.Deployment information Spark is deployed by default in the spark folder in the TiDB instance deployment directory. The TiSpark jar package is deployed by default in the jars folder in the Spark deployment directory.spark/jars/tispark-SNAPSHOT-jar-with-dependencies.jar TiSpark sample data and import scripts are deployed by default in the TiDB-Ansible directory.tidb-ansible/resources/bin/tispark-sample-data Prepare the environment Install JDK on the TiDB instance Download the latest version of JDK 1.8 from Oracle JDK official download page. The version used in the following example is jdk-8u141-linux-x64.tar.gz.Extract the package and set the environment variables based on your JDK deployment directory.Edit the ~/.bashrc file. For example:export JAVA_HOME=/home/pingcap/jdk1.8.0_144 export PATH=$JAVA_HOME/bin:$PATH Verify the validity of JDK:$ java -version java version "1.8.0_144" Java(TM) SE Runtime Environment (build 1.8.0_144-b01) Java HotSpot(TM) 64-Bit Server VM (build 25.144-b01, mixed mode) Import the sample data Assume that the TiDB cluster is started. The service IP of one TiDB instance is 192.168.0.2, the port is 4000, the user name is root, and the password is null.cd tidb-ansible/resources/bin/tispark-sample-data Edit the TiDB login information in sample_data.sh. For example:mysql -h 192.168.0.2 -P 4000 -u root < dss.ddl Run the script:./sample_data.sh Note: You need to install the MySQL client on the machine that runs the script. If you are a CentOS user, you can install it through the command yum -y install mysql. Log into TiDB and verify that the TPCH_001 database and the following tables are included.$ mysql -uroot -P4000 -h192.168.0.2 MySQL [(none)]> show databases; +--------------------+ | Database | +--------------------+ | INFORMATION_SCHEMA | | PERFORMANCE_SCHEMA | | TPCH_001 | | mysql | | test | +--------------------+ 5 rows in set (0.00 sec) MySQL [(none)]> use TPCH_001 Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed MySQL [TPCH_001]> show tables; +--------------------+ | Tables_in_TPCH_001 | +--------------------+ | CUSTOMER | | LINEITEM | | NATION | | ORDERS | | PART | | PARTSUPP | | REGION | | SUPPLIER | +--------------------+ 8 rows in set (0.00 sec) Use example First start the spark-shell in the spark deployment directory:$ cd spark $ bin/spark-shellimport org.apache.spark.sql.TiContext val ti = new TiContext(spark) // Mapping all TiDB tables from `TPCH_001` database as Spark SQL tables ti.tidbMapDatabase("TPCH_001") Then you can call Spark SQL directly:scala> spark.sql("select count(*) from lineitem").show The result is:+--------+ |count(1)| +--------+ | 60175| +--------+ Now run a more complex Spark SQL:scala> spark.sql( """select | l_returnflag, | l_linestatus, | sum(l_quantity) as sum_qty, | sum(l_extendedprice) as sum_base_price, | sum(l_extendedprice * (1 - l_discount)) as sum_disc_price, | sum(l_extendedprice * (1 - l_discount) * (1 + l_tax)) as sum_charge, | avg(l_quantity) as avg_qty, | avg(l_extendedprice) as avg_price, | avg(l_discount) as avg_disc, | count(*) as count_order |from | lineitem |where | l_shipdate <= date '1998-12-01' - interval '90' day |group by | l_returnflag, | l_linestatus |order by | l_returnflag, | l_linestatus """.stripMargin).show The result is:+------------+------------+---------+--------------+--------------+ |l_returnflag|l_linestatus| sum_qty|sum_base_price|sum_disc_price| +------------+------------+---------+--------------+--------------+ | A| F|380456.00| 532348211.65|505822441.4861| | N| F| 8971.00| 12384801.37| 11798257.2080| | N| O|742802.00| 1041502841.45|989737518.6346| | R| F|381449.00| 534594445.35|507996454.4067| +------------+------------+---------+--------------+--------------+ (Continued) -----------------+---------+------------+--------+-----------+ sum_charge| avg_qty| avg_price|avg_disc|count_order| -----------------+---------+------------+--------+-----------+ 526165934.000839|25.575155|35785.709307|0.050081| 14876| 12282485.056933|25.778736|35588.509684|0.047759| 348| 1029418531.523350|25.454988|35691.129209|0.049931| 29181| 528524219.358903|25.597168|35874.006533|0.049828| 14902| -----------------+---------+------------+--------+-----------+ See more examples."}, {"url": "https://pingcap.com/docs/tispark/tispark-user-guide/", "title": "TiSpark User Guide", "content": " TiSpark User Guide TiSpark is a thin layer built for running Apache Spark on top of TiDB/TiKV to answer the complex OLAP queries. It takes advantages of both the Spark platform and the distributed TiKV cluster and seamlessly glues to TiDB, the distributed OLTP database, to provide a Hybrid Transactional/Analytical Processing (HTAP) solution to serve as a one-stop solution for both online transactions and analysis.TiSpark depends on the TiKV cluster and the PD cluster. You also need to set up a Spark cluster. This document provides a brief introduction to how to setup and use TiSpark. It requires some basic knowledge of Apache Spark. For more information, see Spark website.Overview TiSpark is an OLAP solution that runs Spark SQL directly on TiKV, the distributed storage engine. TiSpark integrates with Spark Catalyst Engine deeply. It provides precise control of the computing, which allows Spark read data from TiKV efficiently. It also supports index seek, which improves the performance of the point query execution significantly. It utilizes several strategies to push down the computing to reduce the size of dataset handling by Spark SQL, which accelerates the query execution. It also uses the TiDB built-in statistical information for the query plan optimization. From the data integration point of view, TiSpark and TiDB serve as a solution for running both transaction and analysis directly on the same platform without building and maintaining any ETLs. It simplifies the system architecture and reduces the cost of maintenance. also, you can deploy and utilize tools from the Spark ecosystem for further data processing and manipulation on TiDB. For example, using TiSpark for data analysis and ETL; retrieving data from TiKV as a machine learning data source; generating reports from the scheduling system and so on. Environment setup The current version of TiSpark supports Spark 2.1. For Spark 2.0 and Spark 2.2, it has not been fully tested yet. It does not support any versions earlier than 2.0. TiSpark requires JDK 1.8+ and Scala 2.11 (Spark2.0 + default Scala version). TiSpark runs in any Spark mode such as YARN, Mesos, and Standalone. Recommended configuration This section describes the configuration of independent deployment of TiKV and TiSpark, independent deployment of Spark and TiSpark, and hybrid deployment of TiKV and TiSpark.Configuration of independent deployment of TiKV and TiSpark For independent deployment of TiKV and TiSpark, it is recommended to refer to the following recommendations: Hardware configuration For general purposes, please refer to the TiDB and TiKV hardware configuration recommendations. If the usage is more focused on the analysis scenarios, you can increase the memory of the TiKV nodes to at least 64G. TiKV parameters (default)[server] end-point-concurrency = 8 # For OLAP scenarios, consider increasing this parameter [raftstore] sync-log = false [rocksdb] max-background-compactions = 6 max-background-flushes = 2 [rocksdb.defaultcf] block-cache-size = "10GB" [rocksdb.writecf] block-cache-size = "4GB" [rocksdb.raftcf] block-cache-size = "1GB" [rocksdb.lockcf] block-cache-size = "1GB" [storage] scheduler-worker-pool-size = 4 Configuration of independent deployment of Spark and TiSpark See the Spark official website for the detail hardware recommendations.The following is a short overview of TiSpark configuration.It is recommended to allocate 32G memory for Spark. Please reserve at least 25% of the memory for the operating system and buffer cache.It is recommended to provision at least 8 to 16 cores on per machine for Spark. Initially, you can assign all the CPU cores to Spark.See the official configuration on the Spark website. The following is an example based on the spark-env.sh configuration:SPARK_EXECUTOR_MEMORY = 32g SPARK_WORKER_MEMORY = 32g SPARK_WORKER_CORES = 8 Configuration of hybrid deployment of TiKV and TiSpark For the hybrid deployment of TiKV and TiSpark, add TiSpark required resources to the TiKV reserved resources, and allocate 25% of the memory for the system.Deploy the TiSpark cluster Download TiSpark’s jar package here.Deploy TiSpark on the existing Spark cluster Running TiSpark on an existing Spark cluster does not require a reboot of the cluster. You can use Spark’s --jars parameter to introduce TiSpark as a dependency:spark-shell --jars $PATH/tispark-0.1.0.jar If you want to deploy TiSpark as a default component, simply place the TiSpark jar package into the jars path for each node of the Spark cluster and restart the Spark cluster:${SPARK_INSTALL_PATH}/jars In this way, you can use either Spark-Submit or Spark-Shell to use TiSpark directly.Deploy TiSpark without the Spark cluster If you do not have a Spark cluster, we recommend using the standalone mode. To use the Spark Standalone model, you can simply place a compiled version of Spark on each node of the cluster. If you encounter problems, see its official website. And you are welcome to file an issue on our GitHub.Download and install You can download Apache SparkFor the Standalone mode without Hadoop support, use Spark 2.1.x and any version of Pre-build with Apache Hadoop 2.x with Hadoop dependencies. If you need to use the Hadoop cluster, please choose the corresponding Hadoop version. You can also choose to build from the source code to match the previous version of the official Hadoop 2.6. Please note that TiSpark currently only supports Spark 2.1.x version.Suppose you already have a Spark binaries, and the current PATH is SPARKPATH, please copy the TiSpark jar package to the ${SPARKPATH}/jars directory.Start a Master node Execute the following command on the selected Spark Master node:cd $SPARKPATH ./sbin/start-master.sh After the above step is completed, a log file will be printed on the screen. Check the log file to confirm whether the Spark-Master is started successfully. You can open the http://spark-master-hostname:8080 to view the cluster information (if you does not change the Spark-Master default port number). When you start Spark-Slave, you can also use this panel to confirm whether the Slave is joined to the cluster.Start a Slave node Similarly, you can start a Spark-Slave node with the following command:./sbin/start-slave.sh spark://spark-master-hostname:7077 After the command returns, you can see if the Slave node is joined to the Spark cluster correctly from the panel as well. Repeat the above command at all Slave nodes. After all Slaves are connected to the master, you have a Standalone mode Spark cluster.Spark SQL shell and JDBC server If you want to use JDBC server and interactive SQL shell, please copy start-tithriftserver.sh stop-tithriftserver.sh to your Spark’s sbin folder and tispark-sql to the bin folder.To start interactive shell:./bin/tispark-sql To use Thrift Server, you can start it similar way as default Spark Thrift Server:./sbin/start-tithriftserver.sh And stop it like below:./sbin/stop-tithriftserver.sh Demo Assuming that you have successfully started the TiSpark cluster as described above, here’s a quick introduction to how to use Spark SQL for OLAP analysis. Here we use a table named lineitem in the tpch database as an example.Assuming that your PD node is located at 192.168.1.100, port 2379, add the following command to $SPARK_HOME/conf/spark-defaults.conf:spark.tispark.pd.addresses 192.168.1.100:2379 And then enter the following command in the Spark-Shell:import org.apache.spark.sql.TiContext val ti = new TiContext(spark) ti.tidbMapDatabase ("tpch") After that you can call Spark SQL directly:spark.sql("select count(*)from lineitem").show The result is:+-------------+ | Count (1) | +-------------+ | 600000000 | +-------------+ TiSpark’s SQL Interactive shell is almost the same as the spark-SQL shell.tispark-sql> use tpch; Time taken: 0.015 seconds tispark-sql> select count(*) from lineitem; 2000 Time taken: 0.673 seconds, …"}, {"url": "https://pingcap.com/docs/v2.0/tispark/tispark-user-guide/", "title": "TiSpark User Guide", "content": " TiSpark User Guide TiSpark is a thin layer built for running Apache Spark on top of TiDB/TiKV to answer the complex OLAP queries. It takes advantages of both the Spark platform and the distributed TiKV cluster and seamlessly glues to TiDB, the distributed OLTP database, to provide a Hybrid Transactional/Analytical Processing (HTAP) solution to serve as a one-stop solution for both online transactions and analysis.TiSpark depends on the TiKV cluster and the PD cluster. You also need to set up a Spark cluster. This document provides a brief introduction to how to setup and use TiSpark. It requires some basic knowledge of Apache Spark. For more information, see Spark website.Overview TiSpark is an OLAP solution that runs Spark SQL directly on TiKV, the distributed storage engine. TiSpark integrates with Spark Catalyst Engine deeply. It provides precise control of the computing, which allows Spark read data from TiKV efficiently. It also supports index seek, which improves the performance of the point query execution significantly. It utilizes several strategies to push down the computing to reduce the size of dataset handling by Spark SQL, which accelerates the query execution. It also uses the TiDB built-in statistical information for the query plan optimization. From the data integration point of view, TiSpark and TiDB serve as a solution runs both transaction and analysis directly on the same platform without building and maintaining any ETLs. It simplifies the system architecture and reduces the cost of maintenance. also, you can deploy and utilize tools from the Spark ecosystem for further data processing and manipulation on TiDB. For example, using TiSpark for data analysis and ETL; retrieving data from TiKV as a machine learning data source; generating reports from the scheduling system and so on. Environment setup The current version of TiSpark supports Spark 2.1. For Spark 2.0 and Spark 2.2, it has not been fully tested yet. It does not support any versions earlier than 2.0. TiSpark requires JDK 1.8+ and Scala 2.11 (Spark2.0 + default Scala version). TiSpark runs in any Spark mode such as YARN, Mesos, and Standalone. Recommended configuration This section describes the configuration of independent deployment of TiKV and TiSpark, independent deployment of Spark and TiSpark, and hybrid deployment of TiKV and TiSpark.Configuration of independent deployment of TiKV and TiSpark For independent deployment of TiKV and TiSpark, it is recommended to refer to the following recommendations: Hardware configuration For general purposes, please refer to the TiDB and TiKV hardware configuration recommendations. If the usage is more focused on the analysis scenarios, you can increase the memory of the TiKV nodes to at least 64G. TiKV parameters (default)[server] end-point-concurrency = 8 # For OLAP scenarios, consider increasing this parameter [raftstore] sync-log = false [rocksdb] max-background-compactions = 6 max-background-flushes = 2 [rocksdb.defaultcf] block-cache-size = "10GB" [rocksdb.writecf] block-cache-size = "4GB" [rocksdb.raftcf] block-cache-size = "1GB" [rocksdb.lockcf] block-cache-size = "1GB" [storage] scheduler-worker-pool-size = 4 Configuration of independent deployment of Spark and TiSpark See the Spark official website for the detail hardware recommendations.The following is a short overview of TiSpark configuration.It is recommended to allocate 32G memory for Spark. Please reserve at least 25% of the memory for the operating system and buffer cache.It is recommended to provision at least 8 to 16 cores on per machine for Spark. Initially, you can assign all the CPU cores to Spark.See the official configuration on the Spark website. The following is an example based on the spark-env.sh configuration:SPARK_EXECUTOR_MEMORY = 32g SPARK_WORKER_MEMORY = 32g SPARK_WORKER_CORES = 8 Configuration of hybrid deployment of TiKV and TiSpark For the hybrid deployment of TiKV and TiSpark, add TiSpark required resources to the TiKV reserved resources, and allocate 25% of the memory for the system.Deploy the TiSpark cluster Download TiSpark’s jar package here.Deploy TiSpark on the existing Spark cluster Running TiSpark on an existing Spark cluster does not require a reboot of the cluster. You can use Spark’s --jars parameter to introduce TiSpark as a dependency:spark-shell --jars $PATH/tispark-0.1.0.jar If you want to deploy TiSpark as a default component, simply place the TiSpark jar package into the jars path for each node of the Spark cluster and restart the Spark cluster:${SPARK_INSTALL_PATH}/jars In this way, you can use either Spark-Submit or Spark-Shell to use TiSpark directly.Deploy TiSpark without the Spark cluster If you do not have a Spark cluster, we recommend using the standalone mode. To use the Spark Standalone model, you can simply place a compiled version of Spark on each node of the cluster. If you encounter problems, see its official website. And you are welcome to file an issue on our GitHub.Download and install You can download Apache SparkFor the Standalone mode without Hadoop support, use Spark 2.1.x and any version of Pre-build with Apache Hadoop 2.x with Hadoop dependencies. If you need to use the Hadoop cluster, please choose the corresponding Hadoop version. You can also choose to build from the source code to match the previous version of the official Hadoop 2.6. Please note that TiSpark currently only supports Spark 2.1.x version.Suppose you already have a Spark binaries, and the current PATH is SPARKPATH, please copy the TiSpark jar package to the ${SPARKPATH}/jars directory.Start a Master node Execute the following command on the selected Spark Master node:cd $SPARKPATH ./sbin/start-master.sh After the above step is completed, a log file will be printed on the screen. Check the log file to confirm whether the Spark-Master is started successfully. You can open the http://spark-master-hostname:8080 to view the cluster information (if you does not change the Spark-Master default port number). When you start Spark-Slave, you can also use this panel to confirm whether the Slave is joined to the cluster.Start a Slave node Similarly, you can start a Spark-Slave node with the following command:./sbin/start-slave.sh spark://spark-master-hostname:7077 After the command returns, you can see if the Slave node is joined to the Spark cluster correctly from the panel as well. Repeat the above command at all Slave nodes. After all Slaves are connected to the master, you have a Standalone mode Spark cluster.Spark SQL shell and JDBC server If you want to use JDBC server and interactive SQL shell, please copy start-tithriftserver.sh stop-tithriftserver.sh to your Spark’s sbin folder and tispark-sql to the bin folder.To start interactive shell:./bin/tispark-sql To use Thrift Server, you can start it similar way as default Spark Thrift Server:./sbin/start-tithriftserver.sh And stop it like below:./sbin/stop-tithriftserver.sh Demo Assuming that you have successfully started the TiSpark cluster as described above, here’s a quick introduction to how to use Spark SQL for OLAP analysis. Here we use a table named lineitem in the tpch database as an example.Assuming that your PD node is located at 192.168.1.100, port 2379, add the following command to $SPARK_HOME/conf/spark-defaults.conf:spark.tispark.pd.addresses 192.168.1.100:2379 And then enter the following command in the Spark-Shell:import org.apache.spark.sql.TiContext val ti = new TiContext(spark) ti.tidbMapDatabase ("tpch") After that you can call Spark SQL directly:spark.sql("select count(*)from lineitem").show The result is:+-------------+ | Count (1) | +-------------+ | 600000000 | +-------------+ TiSpark’s SQL Interactive shell is almost the same as the spark-SQL shell.tispark-sql> use tpch; Time taken: 0.015 seconds tispark-sql> select count(*) from lineitem; 2000 Time taken: 0.673 seconds, Fetched 1 …"}, {"url": "https://pingcap.com/docs-cn/tispark/tispark-quick-start-guide/", "title": "TiSpark 快速入门指南", "content": " TiSpark 快速入门指南 为了让大家快速体验 TiSpark,通过 TiDB-Ansible 安装的 TiDB 集群中默认已集成 Spark、TiSpark jar 包及 TiSpark sample data。部署信息 Spark 默认部署在 TiDB 实例部署目录下 spark 目录中 TiSpark jar 包默认部署在 Spark 部署目录 jars 文件夹下:spark/jars/tispark-SNAPSHOT-jar-with-dependencies.jar TiSpark sample data 及导入脚本默认部署在 TiDB-Ansible 目录下:tidb-ansible/resources/bin/tispark-sample-data 环境准备 在 TiDB 实例上安装 JDK 在 Oracle JDK 官方下载页面 下载 JDK 1.8 当前最新版,本示例中下载的版本为 jdk-8u141-linux-x64.tar.gz。解压并根据您的 JDK 部署目录设置环境变量, 编辑 ~/.bashrc 文件,比如:export JAVA_HOME=/home/pingcap/jdk1.8.0_144 export PATH=$JAVA_HOME/bin:$PATH 验证 JDK 有效性:$ java -version java version "1.8.0_144" Java(TM) SE Runtime Environment (build 1.8.0_144-b01) Java HotSpot(TM) 64-Bit Server VM (build 25.144-b01, mixed mode) 导入样例数据 假设 TiDB 集群已启动,其中一台 TiDB 实例服务 IP 为 192.168.0.2,端口为 4000,用户名为 root, 密码为空。cd tidb-ansible/resources/bin/tispark-sample-data 修改 sample_data.sh 中 TiDB 登录信息,比如:mysql -h 192.168.0.2 -P 4000 -u root < dss.ddl 执行脚本./sample_data.sh 执行脚本的机器上需要安装 MySQL client,CentOS 用户可通过 yum -y install mysql来安装。 登录 TiDB 并验证数据包含 TPCH_001 库及以下表:$ mysql -uroot -P4000 -h192.168.0.2 MySQL [(none)]> show databases; +--------------------+ | Database | +--------------------+ | INFORMATION_SCHEMA | | PERFORMANCE_SCHEMA | | TPCH_001 | | mysql | | test | +--------------------+ 5 rows in set (0.00 sec) MySQL [(none)]> use TPCH_001 Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed MySQL [TPCH_001]> show tables; +--------------------+ | Tables_in_TPCH_001 | +--------------------+ | CUSTOMER | | LINEITEM | | NATION | | ORDERS | | PART | | PARTSUPP | | REGION | | SUPPLIER | +--------------------+ 8 rows in set (0.00 sec) 使用范例 进入 spark 部署目录启动 spark-shell:$ cd spark $ bin/spark-shellscala> import org.apache.spark.sql.TiContext scala> val ti = new TiContext(spark) // Mapping all TiDB tables from `TPCH_001` database as Spark SQL tables scala> ti.tidbMapDatabase("TPCH_001") 之后您可以直接调用 Spark SQL:scala> spark.sql("select count(*) from lineitem").show 结果为+--------+ |count(1)| +--------+ | 60175| +--------+ 下面执行另一个复杂一点的 Spark SQL:scala> spark.sql( """select | l_returnflag, | l_linestatus, | sum(l_quantity) as sum_qty, | sum(l_extendedprice) as sum_base_price, | sum(l_extendedprice * (1 - l_discount)) as sum_disc_price, | sum(l_extendedprice * (1 - l_discount) * (1 + l_tax)) as sum_charge, | avg(l_quantity) as avg_qty, | avg(l_extendedprice) as avg_price, | avg(l_discount) as avg_disc, | count(*) as count_order |from | lineitem |where | l_shipdate <= date '1998-12-01' - interval '90' day |group by | l_returnflag, | l_linestatus |order by | l_returnflag, | l_linestatus """.stripMargin).show 结果为:+------------+------------+---------+--------------+--------------+ |l_returnflag|l_linestatus| sum_qty|sum_base_price|sum_disc_price| +------------+------------+---------+--------------+--------------+ | A| F|380456.00| 532348211.65|505822441.4861| | N| F| 8971.00| 12384801.37| 11798257.2080| | N| O|742802.00| 1041502841.45|989737518.6346| | R| F|381449.00| 534594445.35|507996454.4067| +------------+------------+---------+--------------+--------------+ (续) -----------------+---------+------------+--------+-----------+ sum_charge| avg_qty| avg_price|avg_disc|count_order| -----------------+---------+------------+--------+-----------+ 526165934.000839|25.575155|35785.709307|0.050081| 14876| 12282485.056933|25.778736|35588.509684|0.047759| 348| 1029418531.523350|25.454988|35691.129209|0.049931| 29181| 528524219.358903|25.597168|35874.006533|0.049828| 14902| -----------------+---------+------------+--------+-----------+ 更多样例请参考 https://github.com/ilovesoup/tpch/tree/master/sparksql"}, {"url": "https://pingcap.com/docs-cn/v1.0/tispark/tispark-quick-start-guide/", "title": "TiSpark 快速入门指南", "content": " TiSpark 快速入门指南 为了让大家快速体验 TiSpark, 通过 TiDB-Ansible 安装的 Pre-GA 或 master 版本 TiDB 集群中默认已集成 Spark、TiSpark jar 包及 TiSpark sample data。部署信息 Spark 默认部署在 TiDB 实例部署目录下 spark 目录中 TiSpark jar 包默认部署在 Spark 部署目录 jars 文件夹下:spark/jars/tispark-0.1.0-beta-SNAPSHOT-jar-with-dependencies.jar TiSpark sample data 及导入脚本默认部署在 TiDB-Ansible 目录下:tidb-ansible/resources/bin/tispark-sample-data 环境准备 在 TiDB 实例上安装 JDK 在 Oracle JDK 官方下载页面 下载 JDK 1.8 当前最新版,本示例中下载的版本为 jdk-8u141-linux-x64.tar.gz。解压并根据您的 JDK 部署目录设置环境变量, 编辑 ~/.bashrc 文件,比如:export JAVA_HOME=/home/pingcap/jdk1.8.0_144 export PATH=$JAVA_HOME/bin:$PATH 验证 JDK 有效性:$ java -version java version "1.8.0_144" Java(TM) SE Runtime Environment (build 1.8.0_144-b01) Java HotSpot(TM) 64-Bit Server VM (build 25.144-b01, mixed mode) 导入样例数据 假设 TiDB 集群已启动,其中一台 TiDB 实例服务 IP 为 192.168.0.2,端口为 4000,用户名为 root, 密码为空。cd tidb-ansible/resources/bin/tispark-sample-data 修改 sample_data.sh 中 TiDB 登录信息,比如:mysql -h 192.168.0.2 -P 4000 -u root < dss.ddl 执行脚本./sample_data.sh 执行脚本的机器上需要安装 MySQL client,CentOS 用户可通过 yum -y install mysql来安装。 登录 TiDB 并验证数据包含 TPCH_001 库及以下表:$ mysql -uroot -P4000 -h192.168.0.2 MySQL [(none)]> show databases; +--------------------+ | Database | +--------------------+ | INFORMATION_SCHEMA | | PERFORMANCE_SCHEMA | | TPCH_001 | | mysql | | test | +--------------------+ 5 rows in set (0.00 sec) MySQL [(none)]> use TPCH_001 Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed MySQL [TPCH_001]> show tables; +--------------------+ | Tables_in_TPCH_001 | +--------------------+ | CUSTOMER | | LINEITEM | | NATION | | ORDERS | | PART | | PARTSUPP | | REGION | | SUPPLIER | +--------------------+ 8 rows in set (0.00 sec) 使用范例 假设您的 PD 节点 IP 为 192.168.0.2,端口 2379, 先进入 spark 部署目录启动 spark-shell:$ cd spark $ bin/spark-shellscala> import org.apache.spark.sql.TiContext scala> val ti = new TiContext(spark) // Mapping all TiDB tables from `TPCH_001` database as Spark SQL tables scala> ti.tidbMapDatabase("TPCH_001") 之后您可以直接调用 Spark SQL:scala> spark.sql("select count(*) from lineitem").show 结果为+--------+ |count(1)| +--------+ | 60175| +--------+ 下面执行另一个复杂一点的 Spark SQL:scala> spark.sql( """select | l_returnflag, | l_linestatus, | sum(l_quantity) as sum_qty, | sum(l_extendedprice) as sum_base_price, | sum(l_extendedprice * (1 - l_discount)) as sum_disc_price, | sum(l_extendedprice * (1 - l_discount) * (1 + l_tax)) as sum_charge, | avg(l_quantity) as avg_qty, | avg(l_extendedprice) as avg_price, | avg(l_discount) as avg_disc, | count(*) as count_order |from | lineitem |where | l_shipdate <= date '1998-12-01' - interval '90' day |group by | l_returnflag, | l_linestatus |order by | l_returnflag, | l_linestatus """.stripMargin).show 结果为:+------------+------------+---------+--------------+--------------+ |l_returnflag|l_linestatus| sum_qty|sum_base_price|sum_disc_price| +------------+------------+---------+--------------+--------------+ | A| F|380456.00| 532348211.65|505822441.4861| | N| F| 8971.00| 12384801.37| 11798257.2080| | N| O|742802.00| 1041502841.45|989737518.6346| | R| F|381449.00| 534594445.35|507996454.4067| +------------+------------+---------+--------------+--------------+ (续) -----------------+---------+------------+--------+-----------+ sum_charge| avg_qty| avg_price|avg_disc|count_order| -----------------+---------+------------+--------+-----------+ 526165934.000839|25.575155|35785.709307|0.050081| 14876| 12282485.056933|25.778736|35588.509684|0.047759| 348| 1029418531.523350|25.454988|35691.129209|0.049931| 29181| 528524219.358903|25.597168|35874.006533|0.049828| 14902| -----------------+---------+------------+--------+-----------+ 更多样例请参考 https://github.com/ilovesoup/tpch/tree/master/sparksql 。"}, {"url": "https://pingcap.com/docs-cn/v2.0/tispark/tispark-quick-start-guide/", "title": "TiSpark 快速入门指南", "content": " TiSpark 快速入门指南 为了让大家快速体验 TiSpark,通过 TiDB-Ansible 安装的 Pre-GA 或 master 版本 TiDB 集群中默认已集成 Spark、TiSpark jar 包及 TiSpark sample data。部署信息 Spark 默认部署在 TiDB 实例部署目录下 spark 目录中 TiSpark jar 包默认部署在 Spark 部署目录 jars 文件夹下:spark/jars/tispark-0.1.0-beta-SNAPSHOT-jar-with-dependencies.jar TiSpark sample data 及导入脚本默认部署在 TiDB-Ansible 目录下:tidb-ansible/resources/bin/tispark-sample-data 环境准备 在 TiDB 实例上安装 JDK 在 Oracle JDK 官方下载页面 下载 JDK 1.8 当前最新版,本示例中下载的版本为 jdk-8u141-linux-x64.tar.gz。解压并根据您的 JDK 部署目录设置环境变量, 编辑 ~/.bashrc 文件,比如:export JAVA_HOME=/home/pingcap/jdk1.8.0_144 export PATH=$JAVA_HOME/bin:$PATH 验证 JDK 有效性:$ java -version java version "1.8.0_144" Java(TM) SE Runtime Environment (build 1.8.0_144-b01) Java HotSpot(TM) 64-Bit Server VM (build 25.144-b01, mixed mode) 导入样例数据 假设 TiDB 集群已启动,其中一台 TiDB 实例服务 IP 为 192.168.0.2,端口为 4000,用户名为 root, 密码为空。cd tidb-ansible/resources/bin/tispark-sample-data 修改 sample_data.sh 中 TiDB 登录信息,比如:mysql -h 192.168.0.2 -P 4000 -u root < dss.ddl 执行脚本./sample_data.sh 执行脚本的机器上需要安装 MySQL client,CentOS 用户可通过 yum -y install mysql来安装。 登录 TiDB 并验证数据包含 TPCH_001 库及以下表:$ mysql -uroot -P4000 -h192.168.0.2 MySQL [(none)]> show databases; +--------------------+ | Database | +--------------------+ | INFORMATION_SCHEMA | | PERFORMANCE_SCHEMA | | TPCH_001 | | mysql | | test | +--------------------+ 5 rows in set (0.00 sec) MySQL [(none)]> use TPCH_001 Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed MySQL [TPCH_001]> show tables; +--------------------+ | Tables_in_TPCH_001 | +--------------------+ | CUSTOMER | | LINEITEM | | NATION | | ORDERS | | PART | | PARTSUPP | | REGION | | SUPPLIER | +--------------------+ 8 rows in set (0.00 sec) 使用范例 假设您的 PD 节点 IP 为 192.168.0.2,端口 2379, 先进入 spark 部署目录启动 spark-shell:$ cd spark $ bin/spark-shellscala> import org.apache.spark.sql.TiContext scala> val ti = new TiContext(spark) // Mapping all TiDB tables from `TPCH_001` database as Spark SQL tables scala> ti.tidbMapDatabase("TPCH_001") 之后您可以直接调用 Spark SQL:scala> spark.sql("select count(*) from lineitem").show 结果为+--------+ |count(1)| +--------+ | 60175| +--------+ 下面执行另一个复杂一点的 Spark SQL:scala> spark.sql( """select | l_returnflag, | l_linestatus, | sum(l_quantity) as sum_qty, | sum(l_extendedprice) as sum_base_price, | sum(l_extendedprice * (1 - l_discount)) as sum_disc_price, | sum(l_extendedprice * (1 - l_discount) * (1 + l_tax)) as sum_charge, | avg(l_quantity) as avg_qty, | avg(l_extendedprice) as avg_price, | avg(l_discount) as avg_disc, | count(*) as count_order |from | lineitem |where | l_shipdate <= date '1998-12-01' - interval '90' day |group by | l_returnflag, | l_linestatus |order by | l_returnflag, | l_linestatus """.stripMargin).show 结果为:+------------+------------+---------+--------------+--------------+ |l_returnflag|l_linestatus| sum_qty|sum_base_price|sum_disc_price| +------------+------------+---------+--------------+--------------+ | A| F|380456.00| 532348211.65|505822441.4861| | N| F| 8971.00| 12384801.37| 11798257.2080| | N| O|742802.00| 1041502841.45|989737518.6346| | R| F|381449.00| 534594445.35|507996454.4067| +------------+------------+---------+--------------+--------------+ (续) -----------------+---------+------------+--------+-----------+ sum_charge| avg_qty| avg_price|avg_disc|count_order| -----------------+---------+------------+--------+-----------+ 526165934.000839|25.575155|35785.709307|0.050081| 14876| 12282485.056933|25.778736|35588.509684|0.047759| 348| 1029418531.523350|25.454988|35691.129209|0.049931| 29181| 528524219.358903|25.597168|35874.006533|0.049828| 14902| -----------------+---------+------------+--------+-----------+ 更多样例请参考 https://github.com/ilovesoup/tpch/tree/master/sparksql 。"}, {"url": "https://pingcap.com/docs-cn/tispark/tispark-user-guide/", "title": "TiSpark 用户指南", "content": " TiSpark 用户指南 TiSpark 是 PingCAP 为解决用户复杂 OLAP 需求而推出的产品。它借助 Spark 平台,同时融合 TiKV 分布式集群的优势,和 TiDB 一起为用户一站式解决 HTAP (Hybrid Transactional/Analytical Processing) 的需求。TiSpark 依赖于 TiKV 集群和 Placement Driver (PD),也需要你搭建一个 Spark 集群。本文简单介绍如何部署和使用 TiSpark。本文假设你对 Spark 有基本认知。你可以参阅 Apache Spark 官网 了解 Spark 的相关信息。概述 TiSpark 是将 Spark SQL 直接运行在分布式存储引擎 TiKV 上的 OLAP 解决方案。其架构图如下: TiSpark 深度整合了 Spark Catalyst 引擎, 可以对计算提供精确的控制,使 Spark 能够高效的读取 TiKV 中的数据,提供索引支持以实现高速的点查。 通过多种计算下推减少 Spark SQL 需要处理的数据大小,以加速查询;利用 TiDB 的内建的统计信息选择更优的查询计划。 从数据集群的角度看,TiSpark + TiDB 可以让用户无需进行脆弱和难以维护的 ETL,直接在同一个平台进行事务和分析两种工作,简化了系统架构和运维。 除此之外,用户借助 TiSpark 项目可以在 TiDB 上使用 Spark 生态圈提供的多种工具进行数据处理。例如,使用 TiSpark 进行数据分析和 ETL;使用 TiKV 作为机器学习的数据源;借助调度系统产生定时报表等等。 环境准备 现有 TiSpark 版本支持 Spark 2.1。对于 Spark 2.0 及 Spark 2.2 尚未经过良好的测试验证,对于更低版本暂时不支持。TiSpark 需要 JDK 1.8+ 以及 Scala 2.11(Spark2.0+ 默认 Scala 版本)。TiSpark 可以在 YARN,Mesos,Standalone 等任意 Spark 模式下运行。推荐配置 本部分描述了 TiKV 与 TiSpark 集群分开部署、Spark 与 TiSpark 集群独立部署,以及TiSpark 与 TiKV 集群混合部署的建议配置。TiKV 与 TiSpark 集群分开部署的配置 对于 TiKV 与 TiSpark 分开部署的场景,可以参考如下建议配置: 硬件配置建议普通场景可以参考 TiDB 和 TiKV 硬件配置建议,但是如果是偏重分析的场景,可以将 TiKV 节点增加到至少 64G 内存。 TiKV 参数建议[server] end-point-concurrency = 8 # 如果使用场景偏向分析,则可以考虑扩大这个参数 [raftstore] sync-log = false [rocksdb] max-background-compactions = 6 max-background-flushes = 2 [rocksdb.defaultcf] block-cache-size = "10GB" [rocksdb.writecf] block-cache-size = "4GB" [rocksdb.raftcf] block-cache-size = "1GB" [rocksdb.lockcf] block-cache-size = "1GB" [storage] scheduler-worker-pool-size = 4 Spark 与 TiSpark 集群独立部署的配置 关于 Spark 的详细硬件推荐配置请参考官网,如下是 TiSpark 所需环境的简单描述:Spark 推荐 32G 内存以上的配额。请在配置中预留 25% 的内存给操作系统。Spark 推荐每台计算节点配备 CPU 累计 8 到 16 核以上。你可以初始设定分配所有 CPU 核给 Spark。Spark 的具体配置方式也请参考官方说明。以下为根据 spark-env.sh 配置的范例:SPARK_EXECUTOR_MEMORY=32g SPARK_WORKER_MEMORY=32g SPARK_WORKER_CORES=8 TiSpark 与 TiKV 集群混合部署的配置 对于 TiKV 与 TiSpark 混合部署的场景,需在原有 TiKV 预留资源之外累加 Spark 所需部分,并分配 25% 的内存作为系统本身占用。部署 TiSpark TiSpark 的 jar 包可以在这里下载。已有 Spark 集群的部署方式 如果在已有 Spark 集群上运行 TiSpark,无需重启集群。可以使用 Spark 的 --jars 参数将 TiSpark 作为依赖引入:spark-shell --jars $PATH/tispark-0.1.0.jar 如果想将 TiSpark 作为默认组件部署,只需要将 TiSpark 的 jar 包放进 Spark 集群每个节点的 jars 路径并重启 Spark 集群:${SPARK_INSTALL_PATH}/jars 这样无论是使用 Spark-Submit 还是 Spark-Shell 都可以直接使用 TiSpark。没有 Spark 集群的部署方式 如果没有使用中的 Spark 集群,推荐使用 Saprk Standalone 方式部署。这里简单介绍下 Standalone 部署方式。如果遇到问题,可以去官网寻求帮助;也欢迎在我们的 GitHub 上提 issue。下载安装包并安装 你可以在这里下载 Apache Spark。对于 Standalone 模式且无需 Hadoop 支持,则选择 Spark 2.1.x 且带有 Hadoop 依赖的 Pre-build with Apache Hadoop 2.x 任意版本。如有需要配合使用的 Hadoop 集群,则选择对应的 Hadoop 版本号。你也可以选择从源代码自行构建以配合官方 Hadoop 2.6 之前的版本。注意目前 TiSpark 仅支持 Spark 2.1.x 版本。如果你已经有了 Spark 二进制文件,并且当前 PATH 为 SPARKPATH,需将 TiSpark jar 包拷贝到 ${SPARKPATH}/jars 目录下。启动 Master 在选中的 Spark Master 节点执行如下命令:cd $SPARKPATH ./sbin/start-master.sh 在这步完成以后,屏幕上会打印出一个 log 文件。检查 log 文件确认 Spark-Master 是否启动成功。你可以打开 http://spark-master-hostname:8080 查看集群信息(如果你没有改动 Spark-Master 默认 Port Numebr)。在启动 Spark-Slave 的时候,也可以通过这个面板来确认 Slave 是否已经加入集群。启动 Slave 类似地,可以用如下命令启动 Spark-Slave 节点:./sbin/start-slave.sh spark://spark-master-hostname:7077 命令返回以后,即可通过刚才的面板查看这个 Slave 是否已经正确地加入了 Spark 集群。在所有 Slave 节点重复刚才的命令。确认所有的 Slave 都可以正确连接 Master,这样你就拥有了一个 Standalone 模式的 Spark 集群。一个使用范例 假设你已经按照上述步骤成功启动了 TiSpark 集群,下面简单介绍如何使用 Spark SQL 来做 OLAP 分析。这里我们用名为 tpch 数据库中的 lineitem 表作为范例。假设你的 PD 节点位于 192.168.1.100,端口为 2379,在$SPARK_HOME/conf/spark-defaults.conf加入:spark.tispark.pd.addresses 192.168.1.100:2379 然后在 Spark-Shell 里输入下面的命令:import org.apache.spark.sql.TiContext val ti = new TiContext(spark) ti.tidbMapDatabase("tpch") 之后你可以直接调用 Spark SQL:spark.sql("select count(*) from lineitem").show 结果为:+-------------+ | Count (1) | +-------------+ | 600000000 | +-------------+ TiSpark FAQ Q. 是独立部署还是和现有 Spark/Hadoop 集群共用资源?A. 可以利用现有 Spark 集群无需单独部署,但是如果现有集群繁忙,TiSpark 将无法达到理想速度。 Q. 是否可以和 TiKV 混合部署?A. 如果 TiDB 以及 TiKV 负载较高且运行关键的线上任务,请考虑单独部署 TiSpark;并且考虑使用不同的网卡保证 OLTP 的网络资源不被侵占而影响线上业务。如果线上业务要求不高或者机器负载不大,可以考虑与 TiKV 混合部署。 "}, {"url": "https://pingcap.com/docs-cn/v1.0/tispark/tispark-user-guide/", "title": "TiSpark 用户指南", "content": " TiSpark 用户指南 TiSpark 是 PingCAP 为解决用户复杂 OLAP 需求而推出的产品。借助 Spark 平台,同时融合 TiKV 分布式集群的优势,和 TiDB 一起为用户一站式解决 HTAP (Hybrid Transactional/Analytical Processing)需求。 TiSpark 依赖于 TiKV 集群和 Placement Driver(PD)。当然,TiSpark 也需要您搭建一个 Spark 集群。本文简单介绍如何部署和使用 TiSpark。本文假设你对 Spark 有基本认知。你可以参阅 Apache Spark 官网 了解 Spark 相关信息。概述 TiSpark 是将 Spark SQL 直接运行在分布式存储引擎 TiKV 上的 OLAP 解决方案。其架构图如下: TiSpark 深度整合了 Spark Catalyst 引擎, 可以对计算提供精确的控制,使 Spark 能够高效的读取 TiKV 中的数据,提供索引支持以实现高速的点查。 通过多种计算下推减少 Spark SQL 需要处理的数据大小,以加速查询;利用 TiDB 的内建的统计信息选择更优的查询计划。 从数据集群的角度看,TiSpark + TiDB 可以让用户无需进行脆弱和难以维护的 ETL,直接在同一个平台进行事务和分析两种工作,简化了系统架构和运维。 除此之外,用户借助 TiSpark 项目可以在 TiDB 上使用 Spark 生态圈提供的多种工具进行数据处理。例如使用 TiSpark 进行数据分析和 ETL;使用 TiKV 作为机器学习的数据源;借助调度系统产生定时报表等等。 环境准备 现有 TiSpark 版本支持 Spark 2.1。对于 Spark 2.0 及 Spark 2.2 还没有经过良好的测试验证,对于更低版本暂时无法支持。TiSpark 需要 JDK 1.8+ 以及 Scala 2.11(Spark2.0+ 默认 Scala 版本)。TiSpark 可以在 YARN,Mesos,Standalone 等任意 Spark 模式下运行。推荐配置 部署 TiKV 和 TiSpark 集群 TiKV 集群部署配置 对于 TiKV 和 TiSpark 分开部署的场景,可以参考如下建议: 硬件配置建议普通场景可以参考 TiDB 和 TiKV 硬件配置建议,但是如果是偏重分析的场景,可以将 TiKV 节点增加到至少 64G 内存。 TiKV 参数建议[server] end-point-concurrency = 8 # 如果使用场景偏向分析,则可以考虑扩大这个参数 [raftstore] sync-log = false [rocksdb] max-background-compactions = 6 max-background-flushes = 2 [rocksdb.defaultcf] block-cache-size = "10GB" [rocksdb.writecf] block-cache-size = "4GB" [rocksdb.raftcf] block-cache-size = "1GB" [rocksdb.lockcf] block-cache-size = "1GB" [storage] scheduler-worker-pool-size = 4 Spark / TiSpark 集群独立部署配置 关于 Spark 的详细硬件推荐配置请参考官网,如下是 TiSpark 所需环境的简单描述:Spark 推荐 32G 内存以上配额。请在配置中预留 25% 的内存给操作系统。Spark 推荐每台计算节点配备 CPU 累计 8 到 16 核以上。你可以初始设定分配所有 CPU 核给 Spark。Spark 的具体配置方式也请参考官方说明。下面给出的是根据 spark-env.sh 配置的范例:SPARK_EXECUTOR_MEMORY=32g SPARK_WORKER_MEMORY=32g SPARK_WORKER_CORES=8 TiSpark 与 TiKV 集群混合部署配置 对于 TiKV、TiSpark 混合部署场景,请在原有 TiKV 预留资源之外累加 Spark 所需部分并分配 25% 的内存作为系统本身占用。部署 TiSpark TiSpark 的 jar 包可以在这里下载。已有 Spark 集群的部署方式 如果在已有 Spark 集群上运行 TiSpark,您无需重启集群。您可以使用 Spark 的 –jars 参数将 TiSpark 作为依赖引入:spark-shell --jars $PATH/tispark-0.1.0.jar 如果想将 TiSpark 作为默认组件部署,只需要将 TiSpark 的 jar 包放进 Spark 集群每个节点的 jars 路径并重启 Spark 集群:${SPARK_INSTALL_PATH}/jars 这样无论您是使用 Spark-Submit 还是 Spark-Shell 都可以直接使用 TiSpark。没有 Spark 集群的部署方式 如果您没有使用中的 Spark 集群,我们推荐 Saprk Standalone 方式部署。我们在这里简单介绍下 Standalone 部署方式。如果遇到问题,可以去官网寻找帮助;也欢迎在我们的 GitHub 上提 issue。下载安装包并安装 你可以在这里下载 Apache Spark。对于 Standalone 模式且无需 Hadoop 支持,请选择 Spark 2.1.x 且带有 Hadoop 依赖的 Pre-build with Apache Hadoop 2.x 任意版本。如您有需要配合使用的 Hadoop 集群,请选择对应的 Hadoop 版本号。您也可以选择从源代码自行构建以配合官方 Hadoop 2.6 之前的版本。请注意目前 TiSpark 仅支持 Spark 2.1.x 版本。假设您已经有了 Spark 二进制文件,并且当前 PATH 为 SPARKPATH。请将 TiSpark jar 包拷贝到 ${SPARKPATH}/jars 目录下。启动 Master 在选中的 Spark Master 节点执行如下命令:cd $SPARKPATH ./sbin/start-master.sh 在这步完成以后,屏幕上会打印出一个 log 文件。检查 log 文件确认 Spark-Master 是否启动成功。您可以打开 http://spark-master-hostname:8080 查看集群信息(如果你没有改动 Spark-Master 默认 Port Numebr)。 在启动 Spark-Slave 的时候,您也可以通过这个面板来确认 Slave 是否已经加入集群。启动 Slave 类似地,可以用如下命令启动 Spark-Slave节点:./sbin/start-slave.sh spark://spark-master-hostname:7077 命令返回以后,您就可以通过刚才的面板查看这个 Slave 是否已经正确的加入了 Spark 集群。 在所有 Slave 节点重复刚才的命令。在确认所有的 Slave 都可以正确连接 Master,这样您就拥有了一个 Standalone 模式的 Spark 集群。一个使用范例 假设您已经按照上述步骤成功启动了 TiSpark 集群, 下面简单介绍如何使用 Spark SQL 来做 OLAP 分析。这里我们用名为 tpch 数据库中的 lineitem 表作为范例。假设你的 PD 节点位于 192.168.1.100,端口为 2379,在$SPARK_HOME/conf/spark-defaults.conf加入spark.tispark.pd.addresses 192.168.1.100:2379 然后在 Spark-Shell 里输入下面的命令:import org.apache.spark.sql.TiContext val ti = new TiContext(spark) ti.tidbMapDatabase("tpch") 之后您可以直接调用 Spark SQL:spark.sql("select count(*) from lineitem").show 结果为:+-------------+ | Count (1) | +-------------+ | 600000000 | +-------------+ TiSpark FAQ Q. 是独立部署还是和现有 Spark/Hadoop 集群共用资源?A. 您可以利用现有 Spark 集群无需单独部署,但是如果现有集群繁忙,TiSpark 将无法达到理想速度。 Q. 是否可以和 TiKV 混合部署?A. 如果 TiDB 以及 TiKV 负载较高且运行关键的线上任务,请考虑单独部署 TiSpark;并且考虑使用不同的网卡保证 OLTP 的网络资源不被侵占而影响线上业务。如果线上业务要求不高或者机器负载不大,可以考虑与 TiKV 混合部署。 "}, {"url": "https://pingcap.com/docs-cn/v2.0/tispark/tispark-user-guide/", "title": "TiSpark 用户指南", "content": " TiSpark 用户指南 TiSpark 是 PingCAP 为解决用户复杂 OLAP 需求而推出的产品。借助 Spark 平台,同时融合 TiKV 分布式集群的优势,和 TiDB 一起为用户一站式解决 HTAP (Hybrid Transactional/Analytical Processing)需求。 TiSpark 依赖于 TiKV 集群和 Placement Driver(PD)。当然,TiSpark 也需要您搭建一个 Spark 集群。本文简单介绍如何部署和使用 TiSpark。本文假设你对 Spark 有基本认知。你可以参阅 Apache Spark 官网 了解 Spark 相关信息。概述 TiSpark 是将 Spark SQL 直接运行在分布式存储引擎 TiKV 上的 OLAP 解决方案。其架构图如下: TiSpark 深度整合了 Spark Catalyst 引擎, 可以对计算提供精确的控制,使 Spark 能够高效的读取 TiKV 中的数据,提供索引支持以实现高速的点查。 通过多种计算下推减少 Spark SQL 需要处理的数据大小,以加速查询;利用 TiDB 的内建的统计信息选择更优的查询计划。 从数据集群的角度看,TiSpark + TiDB 可以让用户无需进行脆弱和难以维护的 ETL,直接在同一个平台进行事务和分析两种工作,简化了系统架构和运维。 除此之外,用户借助 TiSpark 项目可以在 TiDB 上使用 Spark 生态圈提供的多种工具进行数据处理。例如使用 TiSpark 进行数据分析和 ETL;使用 TiKV 作为机器学习的数据源;借助调度系统产生定时报表等等。 环境准备 现有 TiSpark 版本支持 Spark 2.1。对于 Spark 2.0 及 Spark 2.2 还没有经过良好的测试验证,对于更低版本暂时无法支持。TiSpark 需要 JDK 1.8+ 以及 Scala 2.11(Spark2.0+ 默认 Scala 版本)。TiSpark 可以在 YARN,Mesos,Standalone 等任意 Spark 模式下运行。推荐配置 部署 TiKV 和 TiSpark 集群 TiKV 集群部署配置 对于 TiKV 和 TiSpark 分开部署的场景,可以参考如下建议: 硬件配置建议普通场景可以参考 TiDB 和 TiKV 硬件配置建议,但是如果是偏重分析的场景,可以将 TiKV 节点增加到至少 64G 内存。 TiKV 参数建议[server] end-point-concurrency = 8 # 如果使用场景偏向分析,则可以考虑扩大这个参数 [raftstore] sync-log = false [rocksdb] max-background-compactions = 6 max-background-flushes = 2 [rocksdb.defaultcf] block-cache-size = "10GB" [rocksdb.writecf] block-cache-size = "4GB" [rocksdb.raftcf] block-cache-size = "1GB" [rocksdb.lockcf] block-cache-size = "1GB" [storage] scheduler-worker-pool-size = 4 Spark / TiSpark 集群独立部署配置 关于 Spark 的详细硬件推荐配置请参考官网,如下是 TiSpark 所需环境的简单描述:Spark 推荐 32G 内存以上配额。请在配置中预留 25% 的内存给操作系统。Spark 推荐每台计算节点配备 CPU 累计 8 到 16 核以上。你可以初始设定分配所有 CPU 核给 Spark。Spark 的具体配置方式也请参考官方说明。下面给出的是根据 spark-env.sh 配置的范例:SPARK_EXECUTOR_MEMORY=32g SPARK_WORKER_MEMORY=32g SPARK_WORKER_CORES=8 TiSpark 与 TiKV 集群混合部署配置 对于 TiKV、TiSpark 混合部署场景,请在原有 TiKV 预留资源之外累加 Spark 所需部分并分配 25% 的内存作为系统本身占用。部署 TiSpark TiSpark 的 jar 包可以在这里下载。已有 Spark 集群的部署方式 如果在已有 Spark 集群上运行 TiSpark,您无需重启集群。您可以使用 Spark 的 –jars 参数将 TiSpark 作为依赖引入:spark-shell --jars $PATH/tispark-0.1.0.jar 如果想将 TiSpark 作为默认组件部署,只需要将 TiSpark 的 jar 包放进 Spark 集群每个节点的 jars 路径并重启 Spark 集群:${SPARK_INSTALL_PATH}/jars 这样无论您是使用 Spark-Submit 还是 Spark-Shell 都可以直接使用 TiSpark。没有 Spark 集群的部署方式 如果您没有使用中的 Spark 集群,我们推荐 Saprk Standalone 方式部署。我们在这里简单介绍下 Standalone 部署方式。如果遇到问题,可以去官网寻找帮助;也欢迎在我们的 GitHub 上提 issue。下载安装包并安装 你可以在这里下载 Apache Spark。对于 Standalone 模式且无需 Hadoop 支持,请选择 Spark 2.1.x 且带有 Hadoop 依赖的 Pre-build with Apache Hadoop 2.x 任意版本。如您有需要配合使用的 Hadoop 集群,请选择对应的 Hadoop 版本号。您也可以选择从源代码自行构建以配合官方 Hadoop 2.6 之前的版本。请注意目前 TiSpark 仅支持 Spark 2.1.x 版本。假设您已经有了 Spark 二进制文件,并且当前 PATH 为 SPARKPATH。请将 TiSpark jar 包拷贝到 ${SPARKPATH}/jars 目录下。启动 Master 在选中的 Spark Master 节点执行如下命令:cd $SPARKPATH ./sbin/start-master.sh 在这步完成以后,屏幕上会打印出一个 log 文件。检查 log 文件确认 Spark-Master 是否启动成功。您可以打开 http://spark-master-hostname:8080 查看集群信息(如果你没有改动 Spark-Master 默认 Port Numebr)。 在启动 Spark-Slave 的时候,您也可以通过这个面板来确认 Slave 是否已经加入集群。启动 Slave 类似地,可以用如下命令启动 Spark-Slave节点:./sbin/start-slave.sh spark://spark-master-hostname:7077 命令返回以后,您就可以通过刚才的面板查看这个 Slave 是否已经正确的加入了 Spark 集群。 在所有 Slave 节点重复刚才的命令。在确认所有的 Slave 都可以正确连接 Master,这样您就拥有了一个 Standalone 模式的 Spark 集群。一个使用范例 假设您已经按照上述步骤成功启动了 TiSpark 集群, 下面简单介绍如何使用 Spark SQL 来做 OLAP 分析。这里我们用名为 tpch 数据库中的 lineitem 表作为范例。假设你的 PD 节点位于 192.168.1.100,端口为 2379,在$SPARK_HOME/conf/spark-defaults.conf加入spark.tispark.pd.addresses 192.168.1.100:2379 然后在 Spark-Shell 里输入下面的命令:import org.apache.spark.sql.TiContext val ti = new TiContext(spark) ti.tidbMapDatabase("tpch") 之后您可以直接调用 Spark SQL:spark.sql("select count(*) from lineitem").show 结果为:+-------------+ | Count (1) | +-------------+ | 600000000 | +-------------+ TiSpark FAQ Q. 是独立部署还是和现有 Spark/Hadoop 集群共用资源?A. 您可以利用现有 Spark 集群无需单独部署,但是如果现有集群繁忙,TiSpark 将无法达到理想速度。 Q. 是否可以和 TiKV 混合部署?A. 如果 TiDB 以及 TiKV 负载较高且运行关键的线上任务,请考虑单独部署 TiSpark;并且考虑使用不同的网卡保证 OLTP 的网络资源不被侵占而影响线上业务。如果线上业务要求不高或者机器负载不大,可以考虑与 TiKV 混合部署。 "}, {"url": "https://pingcap.com/tidb-academy/", "title": "Tidb-academies", "content": ""}, {"url": "https://pingcap.com/tidb-cloud/", "title": "Tidb-clouds", "content": ""}, {"url": "https://pingcap.com/docs/v1.0/sql/time-zone/", "title": "Time Zone", "content": " Time Zone The time zone in TiDB is decided by the global time_zone system variable and the session time_zone system variable. The initial value for time_zone is ‘SYSTEM’, which indicates that the server time zone is the same as the system time zone.You can use the following statement to set the global server time_zone value at runtime:mysql> SET GLOBAL time_zone = timezone; Each client has its own time zone setting, given by the session time_zone variable. Initially, the session variable takes its value from the global time_zone variable, but the client can change its own time zone with this statement:mysql> SET time_zone = timezone; You can use the following statment to view the current values of the global and client-specific time zones:mysql> SELECT @@global.time_zone, @@session.time_zone; To set the format of the value of the time_zone: The value ‘SYSTEM’ indicates that the time zone should be the same as the system time zone. The value can be given as a string indicating an offset from UTC, such as ‘+10:00’ or ‘-6:00’. The value can be given as a named time zone, such as ‘Europe/Helsinki’, ‘US/Eastern’, or ‘MET’. The current session time zone setting affects the display and storage of time values that are zone-sensitive. This includes the values displayed by functions such as NOW() or CURTIME(), Note: Only the values of the Timestamp data type is affected by time zone. This is because the Timestamp data type uses the literal value + time zone information. Other data types, such as Datetime/Date/Time, do not have time zone information, thus their values are not affected by the changes of time zone. mysql> create table t (ts timestamp, dt datetime); Query OK, 0 rows affected (0.02 sec) mysql> set @@time_zone = 'UTC'; Query OK, 0 rows affected (0.00 sec) mysql> insert into t values ('2017-09-30 11:11:11', '2017-09-30 11:11:11'); Query OK, 1 row affected (0.00 sec) mysql> set @@time_zone = '+8:00'; Query OK, 0 rows affected (0.00 sec) mysql> select * from t; +---------------------|---------------------+ | ts | dt | +---------------------|---------------------+ | 2017-09-30 19:11:11 | 2017-09-30 11:11:11 | +---------------------|---------------------+ 1 row in set (0.00 sec) In this example, no matter how you adjust the value of the time zone, the value of the Datetime data type is not affected. But the displayed value of the Timestamp data type changes if the time zone information changes. In fact, the value that is stored in the storage does not change, it’s just displayed differently according to different time zone setting. Note: Time zone is involved during the conversion of the value of Timestamp and Datetime, which is handled based on the current time_zone of the session. For data migration, you need to pay special attention to the time zone setting of the master database and the slave database. "}, {"url": "https://pingcap.com/docs/v2.0/sql/time-zone/", "title": "Time Zone", "content": " Time Zone The time zone in TiDB is decided by the global time_zone system variable and the session time_zone system variable. The initial value for time_zone is ‘SYSTEM’, which indicates that the server time zone is the same as the system time zone.You can use the following statement to set the global server time_zone value at runtime:mysql> SET GLOBAL time_zone = timezone; Each client has its own time zone setting, given by the session time_zone variable. Initially, the session variable takes its value from the global time_zone variable, but the client can change its own time zone with this statement:mysql> SET time_zone = timezone; You can use the following statment to view the current values of the global and client-specific time zones:mysql> SELECT @@global.time_zone, @@session.time_zone; To set the format of the value of the time_zone: The value ‘SYSTEM’ indicates that the time zone should be the same as the system time zone. The value can be given as a string indicating an offset from UTC, such as ‘+10:00’ or ‘-6:00’. The value can be given as a named time zone, such as ‘Europe/Helsinki’, ‘US/Eastern’, or ‘MET’. The current session time zone setting affects the display and storage of time values that are zone-sensitive. This includes the values displayed by functions such as NOW() or CURTIME(), Note: Only the values of the Timestamp data type is affected by time zone. This is because the Timestamp data type uses the literal value + time zone information. Other data types, such as Datetime/Date/Time, do not have time zone information, thus their values are not affected by the changes of time zone. mysql> create table t (ts timestamp, dt datetime); Query OK, 0 rows affected (0.02 sec) mysql> set @@time_zone = 'UTC'; Query OK, 0 rows affected (0.00 sec) mysql> insert into t values ('2017-09-30 11:11:11', '2017-09-30 11:11:11'); Query OK, 1 row affected (0.00 sec) mysql> set @@time_zone = '+8:00'; Query OK, 0 rows affected (0.00 sec) mysql> select * from t; +---------------------|---------------------+ | ts | dt | +---------------------|---------------------+ | 2017-09-30 19:11:11 | 2017-09-30 11:11:11 | +---------------------|---------------------+ 1 row in set (0.00 sec) In this example, no matter how you adjust the value of the time zone, the value of the Datetime data type is not affected. But the displayed value of the Timestamp data type changes if the time zone information changes. In fact, the value that is stored in the storage does not change, it’s just displayed differently according to different time zone setting. Note: Time zone is involved during the conversion of the value of Timestamp and Datetime, which is handled based on the current time_zone of the session. For data migration, you need to pay special attention to the time zone setting of the master database and the slave database. "}, {"url": "https://pingcap.com/docs/sql/time-zone/", "title": "Time Zone Support", "content": " Time Zone Support The time zone in TiDB is decided by the global time_zone system variable and the session time_zone system variable. The default value of time_zone is SYSTEM. The actual time zone corresponding to System is configured when the TiDB cluster bootstrap is initialized. The detailed logic is as follows: Prioritize the use of the TZ environment variable. If the TZ environment variable fails, extract the time zone from the actual soft link address of /etc/localtime. If both of the above methods fail, use UTC as the system time zone. You can use the following statement to set the global server time_zone value at runtime:mysql> SET GLOBAL time_zone = timezone; Each client has its own time zone setting, given by the session time_zone variable. Initially, the session variable takes its value from the global time_zone variable, but the client can change its own time zone with this statement:mysql> SET time_zone = timezone; You can use the following statement to view the current values of the global and client-specific time zones:mysql> SELECT @@global.time_zone, @@session.time_zone; To set the format of the value of the time_zone: The value ‘SYSTEM’ indicates that the time zone should be the same as the system time zone. The value can be given as a string indicating an offset from UTC, such as ‘+10:00’ or ‘-6:00’. The value can be given as a named time zone, such as ‘Europe/Helsinki’, ‘US/Eastern’, or ‘MET’. The current session time zone setting affects the display and storage of time values that are zone-sensitive. This includes the values displayed by functions such as NOW() or CURTIME(), Note: Only the values of the Timestamp data type is affected by time zone. This is because the Timestamp data type uses the literal value + time zone information. Other data types, such as Datetime/Date/Time, do not have time zone information, thus their values are not affected by the changes of time zone. mysql> create table t (ts timestamp, dt datetime); Query OK, 0 rows affected (0.02 sec) mysql> set @@time_zone = 'UTC'; Query OK, 0 rows affected (0.00 sec) mysql> insert into t values ('2017-09-30 11:11:11', '2017-09-30 11:11:11'); Query OK, 1 row affected (0.00 sec) mysql> set @@time_zone = '+8:00'; Query OK, 0 rows affected (0.00 sec) mysql> select * from t; +---------------------|---------------------+ | ts | dt | +---------------------|---------------------+ | 2017-09-30 19:11:11 | 2017-09-30 11:11:11 | +---------------------|---------------------+ 1 row in set (0.00 sec) In this example, no matter how you adjust the value of the time zone, the value of the Datetime data type is not affected. But the displayed value of the Timestamp data type changes if the time zone information changes. In fact, the value that is stored in the storage does not change, it’s just displayed differently according to different time zone setting. Note: Time zone is involved during the conversion of the value of Timestamp and Datetime, which is handled based on the current time_zone of the session. For data migration, you need to pay special attention to the time zone setting of the master database and the slave database. "}, {"url": "https://pingcap.com/docs/sql/transaction/", "title": "Transactions", "content": " Transactions TiDB supports distributed transactions. The statements that relate to transactions include the Autocommit variable, START TRANSACTION/BEGIN, COMMIT and ROLLBACK.Autocommit Syntax:SET autocommit = {0 | 1} If you set the value of autocommit to 1, the status of the current Session is autocommit. If you set the value of autocommit to 0, the status of the current Session is non-autocommit. The value of autocommit is 1 by default.In the autocommit status, the updates are automatically committed to the database after you run each statement. Otherwise, the updates are only committed when you run the COMMIT or BEGIN statement.autocommit is also a System Variable. You can update the current Session or the Global value using the following variable assignment statement:SET @@SESSION.autocommit = {0 | 1}; SET @@GLOBAL.autocommit = {0 | 1}; START TRANSACTION, BEGIN Syntax:BEGIN; START TRANSACTION; START TRANSACTION WITH CONSISTENT SNAPSHOT; The three statements above are all statements that transactions start with, through which you can explicitly start a new transaction. If at this time, the current Session is in the process of a transaction, a new transaction is started after the current transaction is committed.COMMIT Syntax:COMMIT; This statement is used to commit the current transaction, including all the updates between BEGIN and COMMIT.ROLLBACK Syntax:ROLLBACK; This statement is used to roll back the current transaction and cancels all the updates between BEGIN and COMMIT.Explicit and implicit transaction TiDB supports explicit transactions (BEGIN/COMMIT) and implicit transactions (SET autocommit = 1).If you set the value of autocommit to 1 and start a new transaction through BEGIN, the autocommit is disabled before COMMIT/ROLLBACK which makes the transaction becomes explicit.For DDL statements, the transaction is committed automatically and does not support rollback. If you run the DDL statement while the current Session is in the process of a transaction, the DDL statement is run after the current transaction is committed.Transaction isolation level TiDB uses SNAPSHOT ISOLATION by default. You can set the isolation level of the current Session to READ COMMITTED using the following statement:SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;"}, {"url": "https://pingcap.com/docs/v1.0/sql/transaction/", "title": "Transactions", "content": " Transactions TiDB supports distributed transactions. The statements that relate to transactions include the Autocommit variable, START TRANSACTION/BEGIN, COMMIT and ROLLBACK.Autocommit Syntax:SET autocommit = {0 | 1} If you set the value of autocommit to 1, the status of the current Session is autocommit. If you set the value of autocommit to 0, the status of the current Session is non-autocommit. The value of autocommit is 1 by default.In the autocommit status, the updates are automatically committed to the database after you run each statement. Otherwise, the updates are only committed when you run the COMMIT or BEGIN statement.Besides, autocommit is also a System Variable. You can update the current Session or the Global value using the following variable assignment statement:SET @@SESSION.autocommit = {0 | 1}; SET @@GLOBAL.autocommit = {0 | 1}; START TRANSACTION, BEGIN Syntax:BEGIN; START TRANSACTION; START TRANSACTION WITH CONSISTENT SNAPSHOT; The three statements above are all statements that transactions start with, through which you can explicitly start a new transaction. If at this time, the current Session is in the process of a transaction, a new transaction is started after the current transaction is committed.COMMIT Syntax:COMMIT; This statement is used to commit the current transaction, including all the updates between BEGIN and COMMIT.ROLLBACK Syntax:ROLLBACK; This statement is used to roll back the current transaction and cancels all the updates between BEGIN and COMMIT.Explicit and implicit transaction TiDB supports explicit transactions (BEGIN/COMMIT) and implicit transactions (SET autocommit = 1).If you set the value of autocommit to 1 and start a new transaction through BEGIN, the autocommit is disabled before COMMIT/ROLLBACK which makes the transaction becomes explicit.For DDL statements, the transaction is committed automatically and does not support rollback. If you run the DDL statement while the current Session is in the process of a transaction, the DDL statement is run after the current transaction is committed.Transaction isolation level TiDB uses SNAPSHOT ISOLATION by default. You can set the isolation level of the current Session to READ COMMITTED using the following statement:SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;"}, {"url": "https://pingcap.com/docs/v2.0/sql/transaction/", "title": "Transactions", "content": " Transactions TiDB supports distributed transactions. The statements that relate to transactions include the Autocommit variable, START TRANSACTION/BEGIN, COMMIT and ROLLBACK.Autocommit Syntax:SET autocommit = {0 | 1} If you set the value of autocommit to 1, the status of the current Session is autocommit. If you set the value of autocommit to 0, the status of the current Session is non-autocommit. The value of autocommit is 1 by default.In the autocommit status, the updates are automatically committed to the database after you run each statement. Otherwise, the updates are only committed when you run the COMMIT or BEGIN statement.autocommit is also a System Variable. You can update the current Session or the Global value using the following variable assignment statement:SET @@SESSION.autocommit = {0 | 1}; SET @@GLOBAL.autocommit = {0 | 1}; START TRANSACTION, BEGIN Syntax:BEGIN; START TRANSACTION; START TRANSACTION WITH CONSISTENT SNAPSHOT; The three statements above are all statements that transactions start with, through which you can explicitly start a new transaction. If at this time, the current Session is in the process of a transaction, a new transaction is started after the current transaction is committed.COMMIT Syntax:COMMIT; This statement is used to commit the current transaction, including all the updates between BEGIN and COMMIT.ROLLBACK Syntax:ROLLBACK; This statement is used to roll back the current transaction and cancels all the updates between BEGIN and COMMIT.Explicit and implicit transaction TiDB supports explicit transactions (BEGIN/COMMIT) and implicit transactions (SET autocommit = 1).If you set the value of autocommit to 1 and start a new transaction through BEGIN, the autocommit is disabled before COMMIT/ROLLBACK which makes the transaction becomes explicit.For DDL statements, the transaction is committed automatically and does not support rollback. If you run the DDL statement while the current Session is in the process of a transaction, the DDL statement is run after the current transaction is committed.Transaction isolation level TiDB uses SNAPSHOT ISOLATION by default. You can set the isolation level of the current Session to READ COMMITTED using the following statement:SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;"}, {"url": "https://pingcap.com/docs/tools/troubleshooting-sharding-ddl-locks/", "title": "Troubleshooting Sharding DDL Locks", "content": " Troubleshooting Sharding DDL Locks The Data Migration tool uses a sharding DDL lock to ensure operations are applied in the correct order. This locking mechanism works automatically, but in some abnormal conditions you might need to perform manual operations such as force-releasing the lock.This document shows how to troubleshoot sharding DDL locks in different abnormal conditions.The possible causes of an abnormal condition include: Some DM-workers go offline A DM-worker restarts (or is unreachable temporarily) DM-master restarts Warning: Do not use unlock-ddl-lock/break-ddl-lock unless you are definitely clear about the possible impacts brought by this command and you can accept the impacts. Condition one: some DM-workers go offline Before the DM-master tries to automatically unlock the sharding DDL lock, all the DM-workers need to receive the sharding DDL event. If the sharding DDL operation is already in the synchronization process, and some DM-workers have gone offline and are not to be restarted, then the sharding DDL lock cannot be automatically synchronized and unlocked because not all the DM-workers can receive the DDL event.If you do not need to make some DM-workers offline in the process of synchronizing sharding DDL statements, a better solution is using stop-task to stop the running task first, then make the DM-workers offline, and finally use start-task and the new task configuration that does not contain the already offline DM-workers to restart the task.If the owner goes offline when the owner has finished executing the DDL statement but other DM-workers have not skipped this DDL statement. For the solution, see Condition two: a DM-worker restarts.Manual solution Run show-ddl-locks to obtain the information of the sharding DDL lock that is currently pending synchronization. Run the unlock-ddl-lock command to specify the information of the lock to be unlocked manually. If the owner of this lock is offline, you can configure the --owner parameter to specify another DM-worker as the new owner to execute the DDL statement. Run show-ddl-locks to check whether this lock has been successfully unlocked. Impact After you have manually unlocked the lock, it still might exist that the lock cannot be automatically synchronized when the next sharding DDL event is received, because the offline DM-workers are included in the task configuration information.Therefore, after you have manually unlocked the DM-workers, you need to use stop-task/start-task and the updated task configuration that does not include offline DM-workers to restart the task. Note: If the DM-workers that went offline become online again after you run unlock-ddl-lock, it means: These DM-workers will synchronize the unlocked DDL operation again. (Other DM-workers that were not offline have synchronized the DDL statement.) The DDL operation of these DM-workers will try to match the subsequent synchronized DDL statements of other DM-workers. A match error of synchronizing sharding DDL statements of different DM-workers might occur. Condition two: a DM-worker restarts (or is unreachable temporarily) Currently, the DDL unlocking process is not atomic, during which the DM-master schedules multiple DM-workers to execute or skip the sharding DDL statement and updates the checkpoint. Therefore, it might exist that after the owner finishes executing the DDL statement, a non-owner restarts before it skips this DDL statement and updates the checkpoint. At this time, the lock information on the DM-master has been removed but the restarted DM-worker has failed to skip this DDL statement and update the checkpoint.After the DM-worker restarts and runs start-task, it retries to synchronize the sharding DDL statement. But as other DM-workers have finished synchronizing this DDL statement, the restarted DM-worker cannot synchronize or skip this DDL statement.Manual solution Run query-status to check the information of the sharding DDL statement that the restarted DM-worker is currently blocking. Run break-ddl-lock to specify the DM-worker that is to break the lock forcefully. Specify skip to skip the sharding DDL statement. Run query-status to check whether the lock has been successfully broken. Impact No bad impact. After you have manually broken the lock, the subsequent sharding DDL statements can be automatically synchronized normally.Condition three: DM-master restarts After a DM-worker sends the sharding DDL information to DM-master, this DM-worker will hang up, wait for the message from DM-master, and then decide whether to execute or skip this DDL statement.Because the state of DM-master is not persistent, the lock information that a DM-worker sends to DM-master will be lost if DM-master restarts.Therefore, DM-master cannot schedule the DM-worker to execute or skip the DDL statement after DM-master restarts due to lock information loss.Manual solution Run show-ddl-locks to verify whether the sharding DDL lock information is lost. Run query-status to verify whether the DM-worker is blocked as it is waiting for synchronization of the sharding DDL lock. Run pause-task to pause the blocked task. Run resume-task to resume the blocked task and restart synchronizing the sharding DDL lock. Impact No bad impact. After you have manually paused and resumed the task, the DM-worker resumes synchronizing the sharding DDL lock and sends the lost lock information to DM-master. The subsequent sharding DDL statements can be synchronized normally.Parameter description of sharding DDL lock commands show-ddl-locks task-name: Non-flag parameter, string, optional If it is not set, no specific task is queried; if it is set, only this task is queried. worker: Flag parameter, string array, --worker, optional Can be specified repeatedly multiple times. If it is set, only the DDL lock information related to these DM-workers is to be queried. unlock-ddl-lock lock-ID: Non-flag parameter, string, required Specifies the ID of the DDL lock that to be unlocked (this ID can be obtained by show-ddl-locks) owner: Flag parameter, string, --owner, optional If it is set, this value should correspond to a DM-worker that substitutes for the default owner to execute the DDL statement of the lock. force-remove: Flag parameter, boolean, --force-remove, optional If it is set, the lock information is removed even though the owner fails to execute the DDL statement. The owner cannot retry or perform other operations on this DDL statement. worker: Flag parameter, string array, --worker, optional Can be specified repeatedly multiple times. If it is not set, all the DM-workers to receive the lock event execute or skip the DDL statement. If it is set, only the specified DM-workers execute or skip the DDL statement. break-ddl-lock task-name: Non-flag parameter, string, required Specifies the name of the task where the lock to be broken is located. worker: Flag parameter, string, --worker, required You must specify one and can only specify one. Specifies the DM-worker that is to break the lock. remove-id: Flag parameter, string, --remove-id, optional If it is set, the value should be the ID of a DDL lock. Then the information about the DDL lock recorded in the DM-worker is removed. exec: Flag parameter, boolean, --exec, optional If it is set, a specific DM-worker executes the DDL statement corresponding to the lock. You cannot specify exec and skip at the same time. skip: Flag parameter, boolean, --skip, optional If it is set, a specific DM-worker skips the DDL operation of the lock. You cannot specify exec and skip at the same time. "}, {"url": "https://pingcap.com/docs-cn/op-guide/try-tidb/", "title": "Try TiDB", "content": " Try TiDB TiDB 支持 SQL92 标准并兼容 MySQL 语法,目前已经实现了大多数常用的 MySQL 语法。用户可以直接使用现有的 MySQL 客户端连接。如果现有的业务已经基于 MySQL 开发,大多数情况不需要修改代码即可直接替换单机的 MySQL。创建数据库 使用 CREATE DATABASE 语句可完成对数据库的创建, 创建命令的格式如下:CREATE DATABASE 数据库名 [其他选项]; 例如我们需要创建一个名为 samp_db 的数据库, 在命令行下执行以下命令:CREATE DATABASE IF NOT EXISTS samp_db; 查看 TiDB 中的所有数据库:SHOW DATABASES; 删除数据库:DROP DATABASE samp_db; 创建表 使用 CREATE TABLE + 表名 + 列名 + 数据类型 + 约束。具体例子如下:CREATE TABLE person ( number INT(11), name VARCHAR(255), birthday DATE ); 如果表已存在,则使用关键词 IF NOT EXISTS 可以防止发生错误。CREATE TABLE IF NOT EXISTS person ( number INT(11), name VARCHAR(255), birthday DATE ); 查看建表语句SHOW CREATE table person; 查看表所有的列:SHOW FULL COLUMNS FROM person; 删除表DROP TABLE person; 或者DROP TABLE IF EXISTS person; 查看 samp_db 中的所有表:SHOW TABLES FROM samp_db; 创建索引 对于值不唯一的列,可以使用 CREATE INDEX 和 ALTER TABLE:CREATE INDEX person_num ON person (number ); ALTER TABLE person ADD INDEX person_num (number ); 对于值唯一的列可以创建唯一索引:CREATE UNIQUE INDEX person_num ON person (number); ALTER TABLE person ADD UNIQUE person_num ON (number); 可利用 ALTER TABLE 或 DROP INDEX 语句来删除索引。类似于 CREATE INDEX 语句,DROP INDEX 可以在 ALTER TABLE 内部作为一条语句处理,语法如下。DROP INDEX person_num ON person; ALTER TABLE person DROP INDEX person_num ; 查看表内所有索引:SHOW INDEX FROM person ; 增删改查数据 利用 INSERT 插入数据INSERT INTO person VALUES("1","tom","20170912"); 利用 SELECT 检索数据SELECT * FROM person; +--------+------+------------+ | number | name | birthday | +--------+------+------------+ | 1 | tom | 2017-09-12 | +--------+------+------------+ 利用 UPDATE 修改表内数据:UPDATE person SET birthday='20171010' WHERE name='tom'; SELECT * FROM person; +--------+------+------------+ | number | name | birthday | +--------+------+------------+ | 1 | tom | 2017-10-10 | +--------+------+------------+ 利用 DELETE 删除表内数据:DELETE FROM person WHERE number=1; SELECT * FROM person; Empty set (0.00 sec) 创建用户 使用 CREATE USER 语句创建一个只在本地登录的用户 tiuser,密码为 123456:CREATE USER 'tiuser'@'localhost' IDENTIFIED BY '123456'; 授权用户可查询 samp_db 库下的表:GRANT SELECT ON samp_db .* TO 'tiuser'@'localhost'; 查询 tiuser 用户的授权:SHOW GRANTS FOR tiuser@localhost; 删除用户:DROP USER 'tiuser'@'localhost';"}, {"url": "https://pingcap.com/docs-cn/v1.0/op-guide/try-tidb/", "title": "Try TiDB", "content": " Try TiDB TiDB 支持 SQL92 标准并兼容 MySQL 语法,目前已经实现了大多数常用的 MySQL 语法。用户可以直接使用现有的 MySQL 客户端连接。如果现有的业务已经基于 MySQL 开发,大多数情况不需要修改代码即可直接替换单机的 MySQL。创建数据库 使用 CREATE DATABASE 语句可完成对数据库的创建, 创建命令的格式如下:CREATE DATABASE 数据库名 [其他选项]; 例如我们需要创建一个名为 samp_db 的数据库, 在命令行下执行以下命令:CREATE DATABASE IF NOT EXISTS samp_db; 查看 TiDB 中的所有数据库:SHOW DATABASES; 删除数据库:DROP DATABASE samp_db; 创建表 使用 CREATE TABLE + 表名 + 列名 + 数据类型 + 约束。具体例子如下:CREATE TABLE person ( number INT(11), name VARCHAR(255), birthday DATE ); 如果表已存在,则使用关键词 IF NOT EXISTS 可以防止发生错误。CREATE TABLE IF NOT EXISTS person ( number INT(11), name VARCHAR(255), birthday DATE ); 查看建表语句SHOW CREATE table person; 查看表所有的列:SHOW FULL COLUMNS FROM person; 删除表DROP TABLE person; 或者DROP TABLE IF EXISTS person; 查看 samp_db 中的所有表:SHOW TABLES FROM samp_db; 创建索引 对于值不唯一的列,可以使用 CREATE INDEX 和 ALTER TABLE:CREATE INDEX person_num ON person (number ); ALTER TABLE person ADD INDEX person_num (number ); 对于值唯一的列可以创建唯一索引:CREATE UNIQUE INDEX person_num ON person (number);  ALTER TABLE person ADD UNIQUE person_num ON (number);可利用 ALTER TABLE 或 DROP INDEX 语句来删除索引。类似于 CREATE INDEX 语句,DROP INDEX 可以在 ALTER TABLE 内部作为一条语句处理,语法如下。DROP INDEX person_num ON person; ALTER TABLE person DROP INDEX person_num ; 查看表内所有索引: SHOW INDEX FROM person ;增删改查数据 利用 INSERT 插入数据INSERT INTO person VALUES("1","tom","20170912"); 利用 SELECT 检索数据SELECT * FROM person; +--------+------+------------+ | number | name | birthday | +--------+------+------------+ | 1 | tom | 2017-09-12 | +--------+------+------------+ 利用 UPDATE 修改表内数据:UPDATE person SET birthday='20171010' WHERE name='tom'; SELECT * FROM person; +--------+------+------------+ | number | name | birthday | +--------+------+------------+ | 1 | tom | 2017-10-10 | +--------+------+------------+ 利用 DELETE 删除表内数据:DELETE FROM person WHERE number=1; SELECT * FROM person; Empty set (0.00 sec) 创建用户 使用 CREATE USER 语句创建一个只在本地登录的用户 tiuser,密码为 123456:CREATE USER 'tiuser'@'localhost' IDENTIFIED BY '123456'; 授权用户可查询 samp_db 库下的表:GRANT SELECT ON samp_db .* TO 'tiuser'@'localhost'; 查询 tiuser 用户的授权: SHOW GRANTS FOR tiuser@localhost;删除用户DROP USER 'tiuser'@'localhost';"}, {"url": "https://pingcap.com/docs-cn/v2.0/op-guide/try-tidb/", "title": "Try TiDB", "content": " Try TiDB TiDB 支持 SQL92 标准并兼容 MySQL 语法,目前已经实现了大多数常用的 MySQL 语法。用户可以直接使用现有的 MySQL 客户端连接。如果现有的业务已经基于 MySQL 开发,大多数情况不需要修改代码即可直接替换单机的 MySQL。创建数据库 使用 CREATE DATABASE 语句可完成对数据库的创建, 创建命令的格式如下:CREATE DATABASE 数据库名 [其他选项]; 例如我们需要创建一个名为 samp_db 的数据库, 在命令行下执行以下命令:CREATE DATABASE IF NOT EXISTS samp_db; 查看 TiDB 中的所有数据库:SHOW DATABASES; 删除数据库:DROP DATABASE samp_db; 创建表 使用 CREATE TABLE + 表名 + 列名 + 数据类型 + 约束。具体例子如下:CREATE TABLE person ( number INT(11), name VARCHAR(255), birthday DATE ); 如果表已存在,则使用关键词 IF NOT EXISTS 可以防止发生错误。CREATE TABLE IF NOT EXISTS person ( number INT(11), name VARCHAR(255), birthday DATE ); 查看建表语句SHOW CREATE table person; 查看表所有的列:SHOW FULL COLUMNS FROM person; 删除表DROP TABLE person; 或者DROP TABLE IF EXISTS person; 查看 samp_db 中的所有表:SHOW TABLES FROM samp_db; 创建索引 对于值不唯一的列,可以使用 CREATE INDEX 和 ALTER TABLE:CREATE INDEX person_num ON person (number ); ALTER TABLE person ADD INDEX person_num (number ); 对于值唯一的列可以创建唯一索引:CREATE UNIQUE INDEX person_num ON person (number);  ALTER TABLE person ADD UNIQUE person_num ON (number);可利用 ALTER TABLE 或 DROP INDEX 语句来删除索引。类似于 CREATE INDEX 语句,DROP INDEX 可以在 ALTER TABLE 内部作为一条语句处理,语法如下。DROP INDEX person_num ON person; ALTER TABLE person DROP INDEX person_num ; 查看表内所有索引: SHOW INDEX FROM person ;增删改查数据 利用 INSERT 插入数据INSERT INTO person VALUES("1","tom","20170912"); 利用 SELECT 检索数据SELECT * FROM person; +--------+------+------------+ | number | name | birthday | +--------+------+------------+ | 1 | tom | 2017-09-12 | +--------+------+------------+ 利用 UPDATE 修改表内数据:UPDATE person SET birthday='20171010' WHERE name='tom'; SELECT * FROM person; +--------+------+------------+ | number | name | birthday | +--------+------+------------+ | 1 | tom | 2017-10-10 | +--------+------+------------+ 利用 DELETE 删除表内数据:DELETE FROM person WHERE number=1; SELECT * FROM person; Empty set (0.00 sec) 创建用户 使用 CREATE USER 语句创建一个只在本地登录的用户 tiuser,密码为 123456:CREATE USER 'tiuser'@'localhost' IDENTIFIED BY '123456'; 授权用户可查询 samp_db 库下的表:GRANT SELECT ON samp_db .* TO 'tiuser'@'localhost'; 查询 tiuser 用户的授权: SHOW GRANTS FOR tiuser@localhost;删除用户DROP USER 'tiuser'@'localhost';"}, {"url": "https://pingcap.com/docs/try-tidb/", "title": "Try TiDB", "content": " Try TiDB After you successfully deploy a TiDB cluster, you can run SQL statements in TiDB. Because TiDB is compatible with MySQL, you can use THE MySQL client to connect to TiDB and run MySQL statements directly in most of the cases. For more information, see Compatibility with MySQL.This page includes some basic SQL statements such as CRUD operations. For a complete list of the statements, see TiDB SQL Syntax Diagram.Create, show, and drop a database Create a database To create a database, use the CREATE DATABASE statement:CREATE DATABASE db_name [options]; For example, to create a database named samp_db:CREATE DATABASE IF NOT EXISTS samp_db; Show the databases To show the databases, use the SHOW DATABASES statement:SHOW DATABASES; Delete a database To delete a database, use the DROP DATABASE statement:DROP DATABASE samp_db; Create, show, and drop a table Create a table To create a table, use the CREATE TABLE statement:CREATE TABLE table_name column_name data_type constraint; For example:CREATE TABLE person ( number INT(11), name VARCHAR(255), birthday DATE ); Add IF NOT EXISTS to prevent an error if the table exists:CREATE TABLE IF NOT EXISTS person ( number INT(11), name VARCHAR(255), birthday DATE ); To view the statement that creates the table, use the SHOW CREATE statement:SHOW CREATE table person; Show the tables To show all the tables in a database, use the SHOW TABLES statement:SHOW TABLES FROM samp_db; To show all the columns in a table, use the SHOW FULL COLUMNS statement:SHOW FULL COLUMNS FROM person; Delete a table To delete a table, use the DROP TABLE statement:DROP TABLE person; orDROP TABLE IF EXISTS person; Create, show, and drop an index Create an index To create an index for the column whose value is not unique, use the CREATE INDEX or ALTER TABLE statement:CREATE INDEX person_num ON person (number); orALTER TABLE person ADD INDEX person_num (number); To create a unique index for the column whose value is unique, use the CREATE UNIQUE INDEX or ALTER TABLE statement:CREATE UNIQUE INDEX person_num ON person (number); orALTER TABLE person ADD UNIQUE person_num on (number); Show the indexes To show all the indexes in a table, use the SHOW INDEX statement:SHOW INDEX from person; Delete an index To delete an index, use the DROP INDEX or ALTER TABLE statement:DROP INDEX person_num ON person; ALTER TABLE person DROP INDEX person_num; Insert, select, update, and delete data Insert data To insert data into a table, use the INSERT statement:INSERT INTO person VALUES("1","tom","20170912"); Select data To view the data in a table, use the SELECT statement:SELECT * FROM person; +--------+------+------------+ | number | name | birthday | +--------+------+------------+ | 1 | tom | 2017-09-12 | +--------+------+------------+ Update data To update the data in a table, use the UPDATE statement:UPDATE person SET birthday='20171010' WHERE name='tom'; SELECT * FROM person; +--------+------+------------+ | number | name | birthday | +--------+------+------------+ | 1 | tom | 2017-10-10 | +--------+------+------------+ Delete data To delete the data in a table, use the DELETE statement:DELETE FROM person WHERE number=1; SELECT * FROM person; Empty set (0.00 sec) Create, authorize, and delete a user Create a user To create a user, use the CREATE USER statement. The following example creates a user named tiuser with the password 123456:CREATE USER 'tiuser'@'localhost' IDENTIFIED BY '123456'; Authorize a user To grant tiuser the privilege to retrieve the tables in the samp_db database:GRANT SELECT ON samp_db.* TO 'tiuser'@'localhost'; To check the privileges of tiuser:SHOW GRANTS for tiuser@localhost; Delete a user To delete tiuser:DROP USER 'tiuser'@'localhost';"}, {"url": "https://pingcap.com/docs/tikv/go-client-api/", "title": "Try Two Types of APIs", "content": " Try Two Types of APIs To apply to different scenarios, TiKV provides two types of APIs for developers: the Raw Key-Value API and the Transactional Key-Value API. This document uses two examples to guide you through how to use the two APIs in TiKV.The usage examples are based on the deployment of TiKV using binary files on multiple nodes for test. You can also quickly try the two types of APIs on a single machine.Try the Raw Key-Value API To use the Raw Key-Value API in applications developed by golang, take the following steps: Install the necessary packages.export GO111MODULE=on go mod init rawkv-demo go get github.com/pingcap/tidb@master Import the dependency packages.import ( "fmt" "github.com/pingcap/tidb/config" "github.com/pingcap/tidb/store/tikv" ) Create a Raw Key-Value client.cli, err := tikv.NewRawKVClient([]string{"192.168.199.113:2379"}, config.Security{}) Description of two parameters in the above command: string: a list of PD servers’ addresses config.Security: used for establishing TLS connections, usually left empty when you do not need TLS Call the Raw Key-Value client methods to access the data on TiKV. The Raw Key-Value API contains the following methods, and you can also find them at GoDoc.type RawKVClient struct func (c *RawKVClient) Close() error func (c *RawKVClient) ClusterID() uint64 func (c *RawKVClient) Delete(key []byte) error func (c *RawKVClient) Get(key []byte) ([]byte, error) func (c *RawKVClient) Put(key, value []byte) error func (c *RawKVClient) Scan(startKey []byte, limit int) (keys [][]byte, values [][]byte, err error) Usage example of the Raw Key-Value API package main import ( "fmt" "github.com/pingcap/tidb/config" "github.com/pingcap/tidb/store/tikv" ) func main() { cli, err := tikv.NewRawKVClient([]string{"192.168.199.113:2379"}, config.Security{}) if err != nil { panic(err) } defer cli.Close() fmt.Printf("cluster ID: %dn", cli.ClusterID()) key := []byte("Company") val := []byte("PingCAP") // put key into tikv err = cli.Put(key, val) if err != nil { panic(err) } fmt.Printf("Successfully put %s:%s to tikvn", key, val) // get key from tikv val, err = cli.Get(key) if err != nil { panic(err) } fmt.Printf("found val: %s for key: %sn", val, key) // delete key from tikv err = cli.Delete(key) if err != nil { panic(err) } fmt.Printf("key: %s deletedn", key) // get key again from tikv val, err = cli.Get(key) if err != nil { panic(err) } fmt.Printf("found val: %s for key: %sn", val, key) } The result is like:INFO[0000] [pd] create pd client with endpoints [192.168.199.113:2379] INFO[0000] [pd] leader switches to: http://127.0.0.1:2379, previous: INFO[0000] [pd] init cluster id 6554145799874853483 cluster ID: 6554145799874853483 Successfully put Company:PingCAP to tikv found val: PingCAP for key: Company key: Company deleted found val: for key: Company RawKVClient is a client of the TiKV server and only supports the GET/PUT/DELETE/SCAN commands. The RawKVClient can be safely and concurrently accessed by multiple goroutines, as long as it is not closed. Therefore, for one process, one client is enough generally.Try the Transactional Key-Value API The Transactional Key-Value API is more complicated than the Raw Key-Value API. Some transaction related concepts are listed as follows. For more details, see the KV package. StorageLike the RawKVClient, a Storage is an abstract TiKV cluster. SnapshotA Snapshot is the state of a Storage at a particular point of time, which provides some readonly methods. The multiple times read from a same Snapshot is guaranteed consistent. TransactionLike the Transaction in SQL, a Transaction symbolizes a series of read and write operations performed within the Storage. Internally, a Transaction consists of a Snapshot for reads, and a MemBuffer for all writes. The default isolation level of a Transaction is Snapshot Isolation. To use the Transactional Key-Value API in applications developed by golang, take the following steps: Install the necessary packages.export GO111MODULE=on go mod init txnkv-demo go get github.com/pingcap/tidb@master Import the dependency packages.import ( "flag" "fmt" "os" "github.com/juju/errors" "github.com/pingcap/tidb/kv" "github.com/pingcap/tidb/store/tikv" "github.com/pingcap/tidb/terror" goctx "golang.org/x/net/context" ) Create Storage using a URL scheme.driver := tikv.Driver{} storage, err := driver.Open("tikv://192.168.199.113:2379") (Optional) Modify the Storage using a Transaction.The lifecycle of a Transaction is: begin → {get, set, delete, scan} → {commit, rollback}. Call the Transactional Key-Value API’s methods to access the data on TiKV. The Transactional Key-Value API contains the following methods:Begin() -> Txn Txn.Get(key []byte) -> (value []byte) Txn.Set(key []byte, value []byte) Txn.Iter(begin, end []byte) -> Iterator Txn.Delete(key []byte) Txn.Commit() Usage example of the Transactional Key-Value API package main import ( "flag" "fmt" "os" "github.com/juju/errors" "github.com/pingcap/tidb/kv" "github.com/pingcap/tidb/store/tikv" "github.com/pingcap/tidb/terror" goctx "golang.org/x/net/context" ) type KV struct { K, V []byte } func (kv KV) String() string { return fmt.Sprintf("%s => %s (%v)", kv.K, kv.V, kv.V) } var ( store kv.Storage pdAddr = flag.String("pd", "192.168.199.113:2379", "pd address:192.168.199.113:2379") ) // Init initializes information. func initStore() { driver := tikv.Driver{} var err error store, err = driver.Open(fmt.Sprintf("tikv://%s", *pdAddr)) terror.MustNil(err) } // key1 val1 key2 val2 ... func puts(args ...[]byte) error { tx, err := store.Begin() if err != nil { return errors.Trace(err) } for i := 0; i < len(args); i += 2 { key, val := args[i], args[i+1] err := tx.Set(key, val) if err != nil { return errors.Trace(err) } } err = tx.Commit(goctx.Background()) if err != nil { return errors.Trace(err) } return nil } func get(k []byte) (KV, error) { tx, err := store.Begin() if err != nil { return KV{}, errors.Trace(err) } v, err := tx.Get(k) if err != nil { return KV{}, errors.Trace(err) } return KV{K: k, V: v}, nil } func dels(keys ...[]byte) error { tx, err := store.Begin() if err != nil { return errors.Trace(err) } for _, key := range keys { err := tx.Delete(key) if err != nil { return errors.Trace(err) } } err = tx.Commit(goctx.Background()) if err != nil { return errors.Trace(err) } return nil } func scan(keyPrefix []byte, limit int) ([]KV, error) { tx, err := store.Begin() if err != nil { return nil, errors.Trace(err) } it, err := tx.Iter(kv.Key(keyPrefix), nil) if err != nil { return nil, errors.Trace(err) } defer it.Close() var ret []KV for it.Valid() && limit > 0 { ret = append(ret, KV{K: it.Key()[:], V: it.Value()[:]}) limit-- it.Next() } return ret, nil } func main() { pdAddr := os.Getenv("PD_ADDR") if pdAddr != "" { os.Args = append(os.Args, "-pd", pdAddr) } flag.Parse() initStore() // set err := puts([]byte("key1"), []byte("value1"), []byte("key2"), []byte("value2")) terror.MustNil(err) // get kv, err := get([]byte("key1")) terror.MustNil(err) fmt.Println(kv) // scan ret, err := scan([]byte("key"), 10) for _, kv := range ret { fmt.Println(kv) } // delete err = dels([]byte("key1"), []byte("key2")) terror.MustNil(err) } The result is like:INFO[0000] [pd] create pd client with endpoints [192.168.199.113:2379] INFO[0000] [pd] leader switches to: http://192.168.199.113:2379, previous: INFO[0000] [pd] init cluster id 6563858376412119197 key1 => value1 ([118 97 108 117 101 49]) key1 => value1 ([118 97 108 117 101 49]) key2 => value2 ([118 97 108 117 101 50])"}, {"url": "https://pingcap.com/docs/v2.0/tikv/go-client-api/", "title": "Try Two Types of APIs", "content": " Try Two Types of APIs To apply to different scenarios, TiKV provides two types of APIs for developers: the Raw Key-Value API and the Transactional Key-Value API. This document uses two examples to guide you through how to use the two APIs in TiKV.The usage examples are based on the deployment of TiKV using binary files on multiple nodes for test. You can also quickly try the two types of APIs on a single machine.Try the Raw Key-Value API To use the Raw Key-Value API in applications developed by golang, take the following steps: Install the necessary packages.go get -v -u github.com/pingcap/tidb/store/tikv Import the dependency packages.import ( "fmt" "github.com/pingcap/tidb/config" "github.com/pingcap/tidb/store/tikv" ) Create a Raw Key-Value client.cli, err := tikv.NewRawKVClient([]string{"192.168.199.113:2379"}, config.Security{}) Description of two parameters in the above command: string: a list of PD servers’ addresses config.Security: used for establishing TLS connections, usually left empty when you do not need TLS Call the Raw Key-Value client methods to access the data on TiKV. The Raw Key-Value API contains the following methods, and you can also find them at GoDoc.type RawKVClient struct func (c *RawKVClient) Close() error func (c *RawKVClient) ClusterID() uint64 func (c *RawKVClient) Delete(key []byte) error func (c *RawKVClient) Get(key []byte) ([]byte, error) func (c *RawKVClient) Put(key, value []byte) error func (c *RawKVClient) Scan(startKey []byte, limit int) (keys [][]byte, values [][]byte, err error) Usage example of the Raw Key-Value API package main import ( "fmt" "github.com/pingcap/tidb/config" "github.com/pingcap/tidb/store/tikv" ) func main() { cli, err := tikv.NewRawKVClient([]string{"192.168.199.113:2379"}, config.Security{}) if err != nil { panic(err) } defer cli.Close() fmt.Printf("cluster ID: %dn", cli.ClusterID()) key := []byte("Company") val := []byte("PingCAP") // put key into tikv err = cli.Put(key, val) if err != nil { panic(err) } fmt.Printf("Successfully put %s:%s to tikvn", key, val) // get key from tikv val, err = cli.Get(key) if err != nil { panic(err) } fmt.Printf("found val: %s for key: %sn", val, key) // delete key from tikv err = cli.Delete(key) if err != nil { panic(err) } fmt.Printf("key: %s deletedn", key) // get key again from tikv val, err = cli.Get(key) if err != nil { panic(err) } fmt.Printf("found val: %s for key: %sn", val, key) } The result is like:INFO[0000] [pd] create pd client with endpoints [192.168.199.113:2379] INFO[0000] [pd] leader switches to: http://127.0.0.1:2379, previous: INFO[0000] [pd] init cluster id 6554145799874853483 cluster ID: 6554145799874853483 Successfully put Company:PingCAP to tikv found val: PingCAP for key: Company key: Company deleted found val: for key: Company RawKVClient is a client of the TiKV server and only supports the GET/PUT/DELETE/SCAN commands. The RawKVClient can be safely and concurrently accessed by multiple goroutines, as long as it is not closed. Therefore, for one process, one client is enough generally.Try the Transactional Key-Value API The Transactional Key-Value API is more complicated than the Raw Key-Value API. Some transaction related concepts are listed as follows. For more details, see the KV package. StorageLike the RawKVClient, a Storage is an abstract TiKV cluster. SnapshotA Snapshot is the state of a Storage at a particular point of time, which provides some readonly methods. The multiple times read from a same Snapshot is guaranteed consistent. TransactionLike the Transaction in SQL, a Transaction symbolizes a series of read and write operations performed within the Storage. Internally, a Transaction consists of a Snapshot for reads, and a MemBuffer for all writes. The default isolation level of a Transaction is Snapshot Isolation. To use the Transactional Key-Value API in applications developed by golang, take the following steps: Install the necessary packages.go get -v -u github.com/juju/errors go get -v -u github.com/pingcap/tidb/kv go get -v -u github.com/pingcap/tidb/store/tikv go get -v -u golang.org/x/net/context Import the dependency packages.import ( "flag" "fmt" "os" "github.com/juju/errors" "github.com/pingcap/tidb/kv" "github.com/pingcap/tidb/store/tikv" "github.com/pingcap/tidb/terror" goctx "golang.org/x/net/context" ) Create Storage using a URL scheme.driver := tikv.Driver{} storage, err := driver.Open("tikv://192.168.199.113:2379") (Optional) Modify the Storage using a Transaction.The lifecycle of a Transaction is: begin → {get, set, delete, scan} → {commit, rollback}. Call the Transactional Key-Value API’s methods to access the data on TiKV. The Transactional Key-Value API contains the following methods:Begin() -> Txn Txn.Get(key []byte) -> (value []byte) Txn.Set(key []byte, value []byte) Txn.Seek(begin []byte) -> Iterator Txn.Delete(key []byte) Txn.Commit() Usage example of the Transactional Key-Value API package main import ( "flag" "fmt" "os" "github.com/juju/errors" "github.com/pingcap/tidb/kv" "github.com/pingcap/tidb/store/tikv" "github.com/pingcap/tidb/terror" goctx "golang.org/x/net/context" ) type KV struct { K, V []byte } func (kv KV) String() string { return fmt.Sprintf("%s => %s (%v)", kv.K, kv.V, kv.V) } var ( store kv.Storage pdAddr = flag.String("pd", "192.168.199.113:2379", "pd address:192.168.199.113:2379") ) // Init initializes information. func initStore() { driver := tikv.Driver{} var err error store, err = driver.Open(fmt.Sprintf("tikv://%s", *pdAddr)) terror.MustNil(err) } // key1 val1 key2 val2 ... func puts(args ...[]byte) error { tx, err := store.Begin() if err != nil { return errors.Trace(err) } for i := 0; i < len(args); i += 2 { key, val := args[i], args[i+1] err := tx.Set(key, val) if err != nil { return errors.Trace(err) } } err = tx.Commit(goctx.Background()) if err != nil { return errors.Trace(err) } return nil } func get(k []byte) (KV, error) { tx, err := store.Begin() if err != nil { return KV{}, errors.Trace(err) } v, err := tx.Get(k) if err != nil { return KV{}, errors.Trace(err) } return KV{K: k, V: v}, nil } func dels(keys ...[]byte) error { tx, err := store.Begin() if err != nil { return errors.Trace(err) } for _, key := range keys { err := tx.Delete(key) if err != nil { return errors.Trace(err) } } err = tx.Commit(goctx.Background()) if err != nil { return errors.Trace(err) } return nil } func scan(keyPrefix []byte, limit int) ([]KV, error) { tx, err := store.Begin() if err != nil { return nil, errors.Trace(err) } it, err := tx.Seek(keyPrefix) if err != nil { return nil, errors.Trace(err) } defer it.Close() var ret []KV for it.Valid() && limit > 0 { ret = append(ret, KV{K: it.Key()[:], V: it.Value()[:]}) limit-- it.Next() } return ret, nil } func main() { pdAddr := os.Getenv("PD_ADDR") if pdAddr != "" { os.Args = append(os.Args, "-pd", pdAddr) } flag.Parse() initStore() // set err := puts([]byte("key1"), []byte("value1"), []byte("key2"), []byte("value2")) terror.MustNil(err) // get kv, err := get([]byte("key1")) terror.MustNil(err) fmt.Println(kv) // scan ret, err := scan([]byte("key"), 10) for _, kv := range ret { fmt.Println(kv) } // delete err = dels([]byte("key1"), []byte("key2")) terror.MustNil(err) } The result is like:INFO[0000] [pd] create pd client with endpoints [192.168.199.113:2379] INFO[0000] [pd] leader switches to: http://192.168.199.113:2379, previous: INFO[0000] [pd] init cluster id 6563858376412119197 key1 => value1 ([118 97 108 117 101 49]) key1 => value1 ([118 97 108 117 101 49]) key2 => value2 ([118 97 108 117 101 50])"}, {"url": "https://pingcap.com/docs/op-guide/tune-tikv/", "title": "Tune TiKV Performance", "content": " Tune TiKV Performance This document describes how to tune the TiKV parameters for optimal performance.TiKV uses RocksDB for persistent storage at the bottom level of the TiKV architecture. Therefore, many of the performance parameters are related to RocksDB. TiKV uses two RocksDB instances: the default RocksDB instance stores KV data, the Raft RocksDB instance (RaftDB) stores Raft logs.TiKV implements Column Families (CF) from RocksDB. The default RocksDB instance stores KV data in the default, write and lock CFs. The default CF stores the actual data. The corresponding parameters are in [rocksdb.defaultcf]. The write CF stores the version information in Multi-Version Concurrency Control (MVCC) and index-related data. The corresponding parameters are in [rocksdb.writecf]. The lock CF stores the lock information. The system uses the default parameters. The Raft RocksDB (RaftDB) instance stores Raft logs. The default CF stores the Raft log. The corresponding parameters are in [raftdb.defaultcf]. Each CF has a separate block cache to cache data blocks to accelerate the data reading speed in RocksDB. You can configure the size of the block cache by setting the block-cache-size parameter. The bigger the block-cache-size, the more hot data can be cached, and the easier to read data, in the meantime, the more system memory will be occupied.Each CF also has a separate write buffer. You can configure the size by setting the write-buffer-size parameter.Parameter specification # Log level: trace, debug, info, warn, error, off. log-level = "info" [server] # Set listening address # addr = "127.0.0.1:20160" # Size of thread pool for gRPC # grpc-concurrency = 4 # The number of gRPC connections between each TiKV instance # grpc-raft-conn-num = 10 # Most read requests from TiDB are sent to the coprocessor of TiKV. This parameter is used to set the number of threads # of the coprocessor. If many read requests exist, add the number of threads and keep the number within that of the # system CPU cores. For example, for a 32-core machine deployed with TiKV, you can even set this parameter to 30 in # repeatable read scenarios. If this parameter is not set, TiKV automatically sets it to CPU cores * 0.8. # end-point-concurrency = 8 # Tag the TiKV instances to schedule replicas. # labels = {zone = "cn-east-1", host = "118", disk = "ssd"} [storage] # The data directory # data-dir = "/tmp/tikv/store" # In most cases, you can use the default value. When importing data, it is recommended to set the parameter to 1024000. # scheduler-concurrency = 102400 # This parameter controls the number of write threads. When write operations occur frequently, set this parameter value # higher. Run `top -H -p tikv-pid` and if the threads named `sched-worker-pool` are busy, set the value of parameter # `scheduler-worker-pool-size` higher and increase the number of write threads. # scheduler-worker-pool-size = 4 [pd] # PD address # endpoints = ["127.0.0.1:2379","127.0.0.2:2379","127.0.0.3:2379"] [metric] # The interval of pushing metrics to Prometheus Pushgateway interval = "15s" # Prometheus Pushgateway address address = "" job = "tikv" [raftstore] # The default value is true, which means writing the data on the disk compulsorily. If it is not in a business scenario # of the financial security level, it is recommended to set the value to false to achieve better performance. sync-log = true # Raft RocksDB directory. The default value is Raft subdirectory of [storage.data-dir]. # If there are multiple disks on the machine, store the data of Raft RocksDB on different disks to improve TiKV performance. # raftdb-dir = "/tmp/tikv/store/raft" region-max-size = "384MB" # The threshold value of Region split region-split-size = "256MB" # When the data size change in a Region is larger than the threshold value, TiKV checks whether this Region needs split. # To reduce the costs of scanning data in the checking process, set the value to 32MB during checking and set it to # the default value in normal operation. region-split-check-diff = "32MB" [rocksdb] # The maximum number of threads of RocksDB background tasks. The background tasks include compaction and flush. # For detailed information why RocksDB needs to implement compaction, see RocksDB-related materials. When write # traffic (like the importing data size) is big, it is recommended to enable more threads. But set the number of the enabled # threads smaller than that of CPU cores. For example, when importing data, for a machine with a 32-core CPU, # set the value to 28. # max-background-jobs = 8 # The maximum number of file handles RocksDB can open # max-open-files = 40960 # The file size limit of RocksDB MANIFEST. For more details, see https://github.com/facebook/rocksdb/wiki/MANIFEST max-manifest-file-size = "20MB" # The directory of RocksDB write-ahead logs. If there are two disks on the machine, store the RocksDB data and WAL logs # on different disks to improve TiKV performance. # wal-dir = "/tmp/tikv/store" # Use the following two parameters to deal with RocksDB archiving WAL. # For more details, see https://github.com/facebook/rocksdb/wiki/How-to-persist-in-memory-RocksDB-database%3F # wal-ttl-seconds = 0 # wal-size-limit = 0 # In most cases, set the maximum total size of RocksDB WAL logs to the default value. # max-total-wal-size = "4GB" # Use this parameter to enable or disable the statistics of RocksDB. # enable-statistics = true # Use this parameter to enable the readahead feature during RocksDB compaction. If you are using mechanical disks, it is recommended to set the value to 2MB at least. # compaction-readahead-size = "2MB" [rocksdb.defaultcf] # The data block size. RocksDB compresses data based on the unit of block. # Similar to page in other databases, block is the smallest unit cached in block-cache. block-size = "64KB" # The compaction mode of each layer of RocksDB data. The optional values include no, snappy, zlib, # bzip2, lz4, lz4hc, and zstd. # "no:no:lz4:lz4:lz4:zstd:zstd" indicates there is no compaction of level0 and level1; lz4 compaction algorithm is used # from level2 to level4; zstd compaction algorithm is used from level5 to level6. # "no" means no compaction. "lz4" is a compaction algorithm with moderate speed and compaction ratio. The # compaction ratio of zlib is high. It is friendly to the storage space, but its compaction speed is slow. This # compaction occupies many CPU resources. Different machines deploy compaction modes according to CPU and I/O resources. # For example, if you use the compaction mode of "no:no:lz4:lz4:lz4:zstd:zstd" and find much I/O pressure of the # system (run the iostat command to find %util lasts 100%, or run the top command to find many iowaits) when writing # (importing) a lot of data while the CPU resources are adequate, you can compress level0 and level1 and exchange CPU # resources for I/O resources. If you use the compaction mode of "no:no:lz4:lz4:lz4:zstd:zstd" and you find the I/O # pressure of the system is not big when writing a lot of data, but CPU resources are inadequate. Then run the top # command and choose the -H option. If you find a lot of bg threads (namely the compaction thread of RocksDB) are # running, you can exchange I/O resources for CPU resources and change the compaction mode to "no:no:no:lz4:lz4:zstd:zstd". # In a word, it aims at making full use of the existing resources of the system and improving TiKV performance # in terms of the current resources. compression-per-level = ["no", "no", "lz4", "lz4", "lz4", "zstd", "zstd"] # The RocksDB memtable size write-buffer-size = "128MB" # The maximum number of the memtables. The data written into RocksDB is first recorded in the WAL log, …"}, {"url": "https://pingcap.com/docs/v1.0/op-guide/tune-tikv/", "title": "Tune TiKV Performance", "content": " Tune TiKV Performance This document describes how to tune the TiKV parameters for optimal performance.TiKV uses RocksDB for persistent storage at the bottom level of the TiKV architecture. Therefore, many of the performance parameters are related to RocksDB. TiKV uses two RocksDB instances: the default RocksDB instance stores KV data, the Raft RocksDB instance (RaftDB) stores Raft logs.TiKV implements Column Families (CF) from RocksDB.The default RocksDB instance stores KV data in the default, write and lock CFs. + The default CF stores the actual data. The corresponding parameters are in [rocksdb.defaultcf]. + The write CF stores the version information in Multi-Version Concurrency Control (MVCC) and index-related data. The corresponding parameters are in [rocksdb.writecf]. + The lock CF stores the lock information. The system uses the default parameters.The Raft RocksDB (RaftDB) instance stores Raft logs. + The default CF stores the Raft log. The corresponding parameters are in [raftdb.defaultcf].Each CF has a separate block cache to cache data blocks to accelerate the data reading speed in RocksDB. You can configure the size of the block cache by setting the block-cache-size parameter. The bigger the block-cache-size, the more hot data can be cached, and the easier to read data, in the meantime, the more system memory will be occupied.Each CF also has a separate write buffer. You can configure the size by setting the write-buffer-size parameter.Parameter specification # Log level: trace, debug, info, warn, error, off. log-level = "info" [server] # Set listening address # addr = "127.0.0.1:20160" # It is recommended to use the default value. # notify-capacity = 40960 # messages-per-tick = 4096 # Size of thread pool for gRPC # grpc-concurrency = 4 # The number of gRPC connections between each TiKV instance # grpc-raft-conn-num = 10 # Most read requests from TiDB are sent to the coprocessor of TiKV. This parameter is used to set the number of threads # of the coprocessor. If many read requests exist, add the number of threads and keep the number within that of the # system CPU cores. For example, for a 32-core machine deployed with TiKV, you can even set this parameter to 30 in # repeatable read scenarios. If this parameter is not set, TiKV automatically sets it to CPU cores * 0.8. # end-point-concurrency = 8 # Tag the TiKV instances to schedule replicas. # labels = {zone = "cn-east-1", host = "118", disk = "ssd"} [storage] # The data directory # data-dir = "/tmp/tikv/store" # In most cases, you can use the default value. When importing data, it is recommended to set the parameter to 1024000. # scheduler-concurrency = 102400 # This parameter controls the number of write threads. When write operations occur frequently, set this parameter value # higher. Run `top -H -p tikv-pid` and if the threads named `sched-worker-pool` are busy, set the value of parameter # `scheduler-worker-pool-size` higher and increase the number of write threads. # scheduler-worker-pool-size = 4 [pd] # PD address # endpoints = ["127.0.0.1:2379","127.0.0.2:2379","127.0.0.3:2379"] [metric] # The interval of pushing metrics to Prometheus pushgateway interval = "15s" # Prometheus pushgateway adress address = "" job = "tikv" [raftstore] # The default value is true,which means writing the data on the disk compulsorily. If it is not in a business scenario # of the financial security level, it is recommended to set the value to false to achieve better performance. sync-log = true # Raft RocksDB directory. The default value is Raft subdirectory of [storage.data-dir]. # If there are multiple disks on the machine, store the data of Raft RocksDB on different disks to improve TiKV performance. # raftdb-dir = "/tmp/tikv/store/raft" region-max-size = "384MB" # The threshold value of Region split region-split-size = "256MB" # When the data size in a Region is larger than the threshold value, TiKV checks whether this Region needs split. # To reduce the costs of scanning data in the checking process,set the value to 32MB during checking and set it to # the default value in normal operation. region-split-check-diff = "32MB" [rocksdb] # The maximum number of threads of RocksDB background tasks. The background tasks include compaction and flush. # For detailed information why RocksDB needs to implement compaction, see RocksDB-related materials. When write # traffic (like the importing data size) is big,it is recommended to enable more threads. But set the number of the enabled # threads smaller than that of CPU cores. For example, when importing data, for a machine with a 32-core CPU, # set the value to 28. # max-background-jobs = 8 # The maximum number of file handles RocksDB can open # max-open-files = 40960 # The file size limit of RocksDB MANIFEST. For more details, see https://github.com/facebook/rocksdb/wiki/MANIFEST max-manifest-file-size = "20MB" # The directory of RocksDB write-ahead logs. If there are two disks on the machine, store the RocksDB data and WAL logs # on different disks to improve TiKV performance. # wal-dir = "/tmp/tikv/store" # Use the following two parameters to deal with RocksDB archiving WAL. # For more details, see https://github.com/facebook/rocksdb/wiki/How-to-persist-in-memory-RocksDB-database%3F # wal-ttl-seconds = 0 # wal-size-limit = 0 # In most cases, set the maximum total size of RocksDB WAL logs to the default value. # max-total-wal-size = "4GB" # Use this parameter to enable or disable the statistics of RocksDB. # enable-statistics = true # Use this parameter to enable the readahead feature during RocksDB compaction. If you are using mechanical disks, it is recommended to set the value to 2MB at least. # compaction-readahead-size = "2MB" [rocksdb.defaultcf] # The data block size. RocksDB compresses data based on the unit of block. # Similar to page in other databases, block is the smallest unit cached in block-cache. block-size = "64KB" # The compaction mode of each layer of RocksDB data. The optional values include no, snappy, zlib, # bzip2, lz4, lz4hc, and zstd. # "no:no:lz4:lz4:lz4:zstd:zstd" indicates there is no compaction of level0 and level1; lz4 compaction algorithm is used # from level2 to level4; zstd compaction algorithm is used from level5 to level6. # "no" means no compaction. "lz4" is a compaction algorithm with moderate speed and compaction ratio. The # compaction ratio of zlib is high. It is friendly to the storage space, but its compaction speed is slow. This # compaction occupies many CPU resources. Different machines deploy compaction modes according to CPU and I/O resources. # For example, if you use the compaction mode of "no:no:lz4:lz4:lz4:zstd:zstd" and find much I/O pressure of the # system (run the iostat command to find %util lasts 100%, or run the top command to find many iowaits) when writing # (importing) a lot of data while the CPU resources are adequate, you can compress level0 and level1 and exchange CPU # resources for I/O resources. If you use the compaction mode of "no:no:lz4:lz4:lz4:zstd:zstd" and you find the I/O # pressure of the system is not big when writing a lot of data, but CPU resources are inadequate. Then run the top # command and choose the -H option. If you find a lot of bg threads (namely the compaction thread of RocksDB) are # running, you can exchange I/O resources for CPU resources and change the compaction mode to "no:no:no:lz4:lz4:zstd:zstd". # In a word, it aims at making full use of the existing resources of the system and improving TiKV performance # in terms of the current resources. compression-per-level = ["no", "no", "lz4", "lz4", "lz4", "zstd", "zstd"] # The RocksDB memtable size write-buffer-size = "128MB" # The maximum …"}, {"url": "https://pingcap.com/docs/v2.0/op-guide/tune-tikv/", "title": "Tune TiKV Performance", "content": " Tune TiKV Performance This document describes how to tune the TiKV parameters for optimal performance.TiKV uses RocksDB for persistent storage at the bottom level of the TiKV architecture. Therefore, many of the performance parameters are related to RocksDB. TiKV uses two RocksDB instances: the default RocksDB instance stores KV data, the Raft RocksDB instance (RaftDB) stores Raft logs.TiKV implements Column Families (CF) from RocksDB. The default RocksDB instance stores KV data in the default, write and lock CFs. The default CF stores the actual data. The corresponding parameters are in [rocksdb.defaultcf]. The write CF stores the version information in Multi-Version Concurrency Control (MVCC) and index-related data. The corresponding parameters are in [rocksdb.writecf]. The lock CF stores the lock information. The system uses the default parameters. The Raft RocksDB (RaftDB) instance stores Raft logs. The default CF stores the Raft log. The corresponding parameters are in [raftdb.defaultcf]. Each CF has a separate block cache to cache data blocks to accelerate the data reading speed in RocksDB. You can configure the size of the block cache by setting the block-cache-size parameter. The bigger the block-cache-size, the more hot data can be cached, and the easier to read data, in the meantime, the more system memory will be occupied.Each CF also has a separate write buffer. You can configure the size by setting the write-buffer-size parameter.Parameter specification # Log level: trace, debug, info, warn, error, off. log-level = "info" [server] # Set listening address # addr = "127.0.0.1:20160" # It is recommended to use the default value. # notify-capacity = 40960 # messages-per-tick = 4096 # Size of thread pool for gRPC # grpc-concurrency = 4 # The number of gRPC connections between each TiKV instance # grpc-raft-conn-num = 10 # Most read requests from TiDB are sent to the coprocessor of TiKV. This parameter is used to set the number of threads # of the coprocessor. If many read requests exist, add the number of threads and keep the number within that of the # system CPU cores. For example, for a 32-core machine deployed with TiKV, you can even set this parameter to 30 in # repeatable read scenarios. If this parameter is not set, TiKV automatically sets it to CPU cores * 0.8. # end-point-concurrency = 8 # Tag the TiKV instances to schedule replicas. # labels = {zone = "cn-east-1", host = "118", disk = "ssd"} [storage] # The data directory # data-dir = "/tmp/tikv/store" # In most cases, you can use the default value. When importing data, it is recommended to set the parameter to 1024000. # scheduler-concurrency = 102400 # This parameter controls the number of write threads. When write operations occur frequently, set this parameter value # higher. Run `top -H -p tikv-pid` and if the threads named `sched-worker-pool` are busy, set the value of parameter # `scheduler-worker-pool-size` higher and increase the number of write threads. # scheduler-worker-pool-size = 4 [pd] # PD address # endpoints = ["127.0.0.1:2379","127.0.0.2:2379","127.0.0.3:2379"] [metric] # The interval of pushing metrics to Prometheus pushgateway interval = "15s" # Prometheus pushgateway adress address = "" job = "tikv" [raftstore] # The default value is true, which means writing the data on the disk compulsorily. If it is not in a business scenario # of the financial security level, it is recommended to set the value to false to achieve better performance. sync-log = true # Raft RocksDB directory. The default value is Raft subdirectory of [storage.data-dir]. # If there are multiple disks on the machine, store the data of Raft RocksDB on different disks to improve TiKV performance. # raftdb-dir = "/tmp/tikv/store/raft" region-max-size = "384MB" # The threshold value of Region split region-split-size = "256MB" # When the data size in a Region is larger than the threshold value, TiKV checks whether this Region needs split. # To reduce the costs of scanning data in the checking process, set the value to 32MB during checking and set it to # the default value in normal operation. region-split-check-diff = "32MB" [rocksdb] # The maximum number of threads of RocksDB background tasks. The background tasks include compaction and flush. # For detailed information why RocksDB needs to implement compaction, see RocksDB-related materials. When write # traffic (like the importing data size) is big, it is recommended to enable more threads. But set the number of the enabled # threads smaller than that of CPU cores. For example, when importing data, for a machine with a 32-core CPU, # set the value to 28. # max-background-jobs = 8 # The maximum number of file handles RocksDB can open # max-open-files = 40960 # The file size limit of RocksDB MANIFEST. For more details, see https://github.com/facebook/rocksdb/wiki/MANIFEST max-manifest-file-size = "20MB" # The directory of RocksDB write-ahead logs. If there are two disks on the machine, store the RocksDB data and WAL logs # on different disks to improve TiKV performance. # wal-dir = "/tmp/tikv/store" # Use the following two parameters to deal with RocksDB archiving WAL. # For more details, see https://github.com/facebook/rocksdb/wiki/How-to-persist-in-memory-RocksDB-database%3F # wal-ttl-seconds = 0 # wal-size-limit = 0 # In most cases, set the maximum total size of RocksDB WAL logs to the default value. # max-total-wal-size = "4GB" # Use this parameter to enable or disable the statistics of RocksDB. # enable-statistics = true # Use this parameter to enable the readahead feature during RocksDB compaction. If you are using mechanical disks, it is recommended to set the value to 2MB at least. # compaction-readahead-size = "2MB" [rocksdb.defaultcf] # The data block size. RocksDB compresses data based on the unit of block. # Similar to page in other databases, block is the smallest unit cached in block-cache. block-size = "64KB" # The compaction mode of each layer of RocksDB data. The optional values include no, snappy, zlib, # bzip2, lz4, lz4hc, and zstd. # "no:no:lz4:lz4:lz4:zstd:zstd" indicates there is no compaction of level0 and level1; lz4 compaction algorithm is used # from level2 to level4; zstd compaction algorithm is used from level5 to level6. # "no" means no compaction. "lz4" is a compaction algorithm with moderate speed and compaction ratio. The # compaction ratio of zlib is high. It is friendly to the storage space, but its compaction speed is slow. This # compaction occupies many CPU resources. Different machines deploy compaction modes according to CPU and I/O resources. # For example, if you use the compaction mode of "no:no:lz4:lz4:lz4:zstd:zstd" and find much I/O pressure of the # system (run the iostat command to find %util lasts 100%, or run the top command to find many iowaits) when writing # (importing) a lot of data while the CPU resources are adequate, you can compress level0 and level1 and exchange CPU # resources for I/O resources. If you use the compaction mode of "no:no:lz4:lz4:lz4:zstd:zstd" and you find the I/O # pressure of the system is not big when writing a lot of data, but CPU resources are inadequate. Then run the top # command and choose the -H option. If you find a lot of bg threads (namely the compaction thread of RocksDB) are # running, you can exchange I/O resources for CPU resources and change the compaction mode to "no:no:no:lz4:lz4:zstd:zstd". # In a word, it aims at making full use of the existing resources of the system and improving TiKV performance # in terms of the current resources. compression-per-level = ["no", "no", "lz4", "lz4", "lz4", "zstd", "zstd"] # The RocksDB memtable size write-buffer-size = "128MB" # The maximum …"}, {"url": "https://pingcap.com/docs/sql/type-conversion-in-expression-evaluation/", "title": "Type Conversion in Expression Evaluation", "content": " Type Conversion in Expression Evaluation TiDB behaves the same as MySQL: https://dev.mysql.com/doc/refman/5.7/en/type-conversion.html"}, {"url": "https://pingcap.com/docs/v1.0/sql/type-conversion-in-expression-evaluation/", "title": "Type Conversion in Expression Evaluation", "content": " Type Conversion in Expression Evaluation TiDB behaves the same as MySQL: https://dev.mysql.com/doc/refman/5.7/en/type-conversion.html"}, {"url": "https://pingcap.com/docs/v2.0/sql/type-conversion-in-expression-evaluation/", "title": "Type Conversion in Expression Evaluation", "content": " Type Conversion in Expression Evaluation TiDB behaves the same as MySQL: https://dev.mysql.com/doc/refman/5.7/en/type-conversion.html"}, {"url": "https://pingcap.com/docs/sql/understanding-the-query-execution-plan/", "title": "Understand the Query Execution Plan", "content": " Understand the Query Execution Plan Based on the details of your tables, the TiDB optimizer chooses the most efficient query execution plan, which consists of a series of operators. This document details the execution plan information returned by the EXPLAIN statement in TiDB.Optimize SQL statements using EXPLAIN The result of the EXPLAIN statement provides information about how TiDB executes SQL queries: EXPLAIN works together with SELECT, DELETE, INSERT, REPLACE, and UPDATE. When you run the EXPLAIN statement, TiDB returns the final physical execution plan which is optimized by the SQL statement of EXPLAIN. In other words, EXPLAIN displays the complete information about how TiDB executes the SQL statement, such as in which order, how tables are joined, and what the expression tree looks like. For more information, see EXPLAIN output format. TiDB does not support EXPLAIN [options] FOR CONNECTION connection_id currently. We’ll do it in the future. For more information, see #4351. The results of EXPLAIN shed light on how to index the data tables so that the execution plan can use the index to speed up the execution of SQL statements. You can also use EXPLAIN to check if the optimizer chooses the optimal order to join tables.EXPLAIN output format Currently, the EXPLAIN statement returns the following four columns: id, count, task, operator info. Each operator in the execution plan is described by the four properties. In the results returned by EXPLAIN, each row describes an operator. See the following table for details: Property Name Description id The id of an operator, to identify the uniqueness of an operator in the entire execution plan. As of TiDB 2.1, the id includes formatting to show a tree structure of operators. The data flows from a child to its parent, and each operator has one and only one parent. count An estimation of the number of data items that the current operator outputs, based on the statistics and the execution logic of the operator task the task that the current operator belongs to. The current execution plan contains two types of tasks: 1) the root task that runs on the TiDB server; 2) the cop task that runs concurrently on the TiKV server. The topological relations of the current execution plan in the task level is that a root task can be followed by many cop tasks. The root task uses the output of cop task as the input. The cop task executes the tasks that TiDB pushes to TiKV. Each cop task scatters in the TiKV cluster and is executed by multiple processes. operator info The details about each operator. The information of each operator differs from others, see Operator Info. Example usage Using the bikeshare example database:mysql> EXPLAIN SELECT count(*) FROM trips WHERE start_date BETWEEN '2017-07-01 00:00:00' AND '2017-07-01 23:59:59'; +--------------------------+-------------+------+------------------------------------------------------------------------------------------------------------------------+ | id | count | task | operator info | +--------------------------+-------------+------+------------------------------------------------------------------------------------------------------------------------+ | StreamAgg_20 | 1.00 | root | funcs:count(col_0) | | └─TableReader_21 | 1.00 | root | data:StreamAgg_9 | | └─StreamAgg_9 | 1.00 | cop | funcs:count(1) | | └─Selection_19 | 8166.73 | cop | ge(bikeshare.trips.start_date, 2017-07-01 00:00:00.000000), le(bikeshare.trips.start_date, 2017-07-01 23:59:59.000000) | | └─TableScan_18 | 19117643.00 | cop | table:trips, range:[-inf,+inf], keep order:false | +--------------------------+-------------+------+------------------------------------------------------------------------------------------------------------------------+ 5 rows in set (0.00 sec) Here you can see that the coprocesor (cop) needs to scan the table trips to find rows that match the criteria of start_date. Rows that meet this criteria are determined in Selection_19 and passed to StreamAgg_9, all still within the coprocessor (i.e. inside of TiKV). The count column shows an approximate number of rows that will be processed, which is estimated with the help of table statistics. In this query it is estimated that each of the TiKV nodes will return 1.00 row to TiDB (as TableReader_21), which are then aggregated as StreamAgg_20 to return an estimated 1.00 row to the client.The good news with this query is that most of the work is pushed down to the coprocessor. This means that minimal data transfer is required for query execution. However, the TableScan_18 can be eliminated by adding an index to speed up queries on start_date:mysql> ALTER TABLE trips ADD INDEX (start_date); .. mysql> EXPLAIN SELECT count(*) FROM trips WHERE start_date BETWEEN '2017-07-01 00:00:00' AND '2017-07-01 23:59:59'; +------------------------+---------+------+--------------------------------------------------------------------------------------------------+ | id | count | task | operator info | +------------------------+---------+------+--------------------------------------------------------------------------------------------------+ | StreamAgg_25 | 1.00 | root | funcs:count(col_0) | | └─IndexReader_26 | 1.00 | root | index:StreamAgg_9 | | └─StreamAgg_9 | 1.00 | cop | funcs:count(1) | | └─IndexScan_24 | 8166.73 | cop | table:trips, index:start_date, range:[2017-07-01 00:00:00,2017-07-01 23:59:59], keep order:false | +------------------------+---------+------+--------------------------------------------------------------------------------------------------+ 4 rows in set (0.01 sec) In the revisited EXPLAIN you can see the count of rows scanned has reduced via the use of an index. On a reference system, the query execution time reduced from 50.41 seconds to 0.00 seconds!EXPLAIN ANALYZE output format As an extension to EXPLAIN, EXPLAIN ANALYZE will execute the query and provide additional execution statistics in the execution info column as follows: time shows the total wall time from entering the operator until exiting the execution. It includes all execution time of any child operator operations. If the operator is called multiple times (loops) from a parent operator, the time will be the cumulative time. loops is the number of times the operator was called from the parent operator. rows is the total number of rows that were returned by this operator. So for example, you can compare the accuracy of the count column to rows/loops in the execution_info column to assess how accurate the query optimizer’s estimations are. Example usage mysql> EXPLAIN ANALYZE SELECT count(*) FROM trips WHERE start_date BETWEEN '2017-07-01 00:00:00' AND '2017-07-01 23:59:59'; +------------------------+---------+------+--------------------------------------------------------------------------------------------------+-----------------------------------+ | id | count | task | operator info | execution info | +------------------------+---------+------+--------------------------------------------------------------------------------------------------+-----------------------------------+ | StreamAgg_25 | 1.00 | root | funcs:count(col_0) | time:79.851424ms, loops:2, rows:1 | | └─IndexReader_26 | 1.00 | root | index:StreamAgg_9 | time:79.835575ms, loops:2, rows:1 | | └─StreamAgg_9 | 1.00 | cop | funcs:count(1) | | | └─IndexScan_24 | 8161.83 | cop | table:trips, index:start_date, range:[2017-07-01 00:00:00,2017-07-01 23:59:59], keep order:false | | +------------------------+---------+------+--------------------------------------------------------------------------------------------------+-----------------------------------+ 4 rows in set (0.08 sec) Overview Introduction to task Currently, the calculation task of TiDB contains two different tasks: cop task and root task. The cop task refers to the computing task that is pushed to the KV side and executed distributedly. The root task refers …"}, {"url": "https://pingcap.com/docs/v1.0/sql/understanding-the-query-execution-plan/", "title": "Understand the Query Execution Plan", "content": " Understand the Query Execution Plan Based on the details of your tables, the TiDB optimizer chooses the most efficient query execution plan, which consists of a series of operators. This document details the execution plan information returned by the EXPLAIN statement in TiDB.Optimize SQL statements using EXPLAIN The result of the EXPLAIN statement provides information about how TiDB executes SQL queries: EXPLAIN works together with SELECT, DELETE, INSERT, REPLACE, and UPDATE. When you run the EXPLAIN statement, TiDB returns the final physical execution plan which is optimized by the SQL statment of EXPLAIN. In other words, EXPLAIN displays the complete information about how TiDB executes the SQL statement, such as in which order, how tables are joined, and what the expression tree looks like. For more information, see EXPLAIN output format. TiDB dose not support EXPLAIN [options] FOR CONNECTION connection_id currently. We’ll do it in the future. For more information, see #4351. The results of EXPLAIN shed light on how to index the data tables so that the execution plan can use the index to speed up the execution of SQL statements. You can also use EXPLAIN to check if the optimizer chooses the optimal order to join tables.EXPLAIN output format Currently, the EXPLAIN statement returns the following six columns: id, parent, children, task, operator info, and count. Each operator in the execution plan is described by the six properties. In the results returned by EXPLAIN, each row describes an operator. See the following table for details: Property Name Description id The id of an operator, to identify the uniqueness of an operator in the entire execution plan. parent The parent of an operator. The current execution plan is like a tree structure composed of operators. The data flows from a child to its parent, and each operator has one and only one parent. children the children and the data source of an operator task the task that the current operator belongs to. The current execution plan contains two types of tasks: 1) the root task that runs on the TiDB server; 2) the cop task that runs concurrently on the TiKV server. The topological relations of the current execution plan in the task level is that a root task can be followed by many cop tasks. The root task uses the output of cop task as the input. The cop task executes the tasks that TiDB pushes to TiKV. Each cop task scatters in the TiKV cluster and is executed by multiple processes. operator info The details about each operator. The information of each operator differs from others, see Operator Info. count to predict the number of data items that the current operator outputs, based on the statistics and the execution logic of the operator Overview Introduction to task Currently, the calculation task of TiDB contains two different tasks: cop task and root task. The cop task refers to the computing task that is pushed to the KV side and executed distributedly. The root task refers to the computing task that is executed at a single point in TiDB. One of the goals of SQL optimization is to push the calculation down to the KV side as much as possible.Table data and index data The table data in TiDB refers to the raw data of a table, which is stored in TiKV. For each row of the table data, its key is a 64-bit integer called Handle ID. If a table has int type primary key, the value of the primary key is taken as the Handle ID of the table data, otherwise the system automatically generates the Handle ID. The value of the table data is encoded by all the data in this row. When the table data is read, return the results in the order in which the Handle ID is incremented.Similar to the table data, the index data in TiDB is also stored in TiKV. The key of index data is ordered bytes encoded by index columns. The value is the Handle ID of each row of index data. You can use the Handle ID to read the non-index columns in this row. When the index data is read, return the results in the order in which the index columns are incremented. If the case of multiple index columns, make sure that the first column is incremented and that the i + 1 column is incremented when the i column is equal.Range query In the WHERE/HAVING/ON condition, analyze the results returned by primary key or index key queries. For example, number and date types of comparison symbols, greater than, less than, equal to, greater than or equal to, less than or equal to, and character type LIKE symbols.TiDB only supports the comparison symbols of which one side is a column and the other side is a constant or can be calculated as a constant. Query conditions like year(birth_day) < 1992 cannot use the index. Besides, try to use the same type to compare, to avoid that the index cannot be used because of additional cast operations. For example, in user_id = 123456, if the user_id is a string, you need to write 123456 as a string constant.Using AND and OR combination on the range query conditions of the same column is equivalent to getting the intersection or union set. For multidimensional combined indexes, you can write the conditions for multiple columns. For example, in the (a, b, c) combined index, when a is an equivalent query, you can continue to calculate the query range of b; when b is also an equivalent query, you can continue to calculate the query range of c; otherwise, if a is a non-equivalent query, you can only calculate the query range of a.Operator info TableReader and TableScan TableScan refers to scanning the table data at the KV side. TableReader refers to reading the table data from TiKV at the TiDB side. TableReader and TableScan are the two operators of one function. The table represents the table name in SQL statements. If the table is renamed, it displays the new name. The range represents the range of scanned data. If the WHERE/HAVING/ON condition is not specified in the query, full table scan is executed. If the range query condition is specified on the int type primary keys, range query is executed. The keep order indicates whether the table scan is returned in order.IndexReader and IndexLookUp The index data in TiDB is read in two ways: 1) IndexReader represents reading the index columns directly from the index, which is used when only index related columns or primary keys are quoted in SQL statements; 2) IndexLookUp represents filtering part of the data from the index, returning only the Handle ID, and retrieving the table data again using Handle ID. In the second way, data is retrieved twice from TiKV. The way of reading index data is automatically selected by the optimizer.Similar to TableScan, IndexScan is the operator to read index data in the KV side. The table represents the table name in SQL statements. If the table is renamed, it displays the new name. The index represents the index name. The range represents the range of scanned data. The out of order indicates whether the index scan is returned in order. In TiDB, the primary key composed of multiple columns or non-int columns is treated as the unique index.Selection Selection represents the selection conditions in SQL statements, usually used in WHERE/HAVING/ON clause.Projection Projection corresponds to the SELECT list in SQL statements, used to map the input data into new output data.Aggregation Aggregation corresponds to Group By in SQL statements, or the aggregate functions if the Group By statement does not exist, such as the COUNT or SUM function. TiDB supports two aggregation algorithms: Hash Aggregation and Stream Aggregation. Hash Aggregation is a hash-based aggregation algorithm. If Hash Aggregation is close to the read operator of Table or Index, the aggregation operator pre-aggregates in TiKV to improve the concurrency and reduce the network load.Join TiDB supports Inner Join and Left/Right Outer Join, and automatically converts the external connection that can be simplified to Inner Join.TiDB supports three Join …"}, {"url": "https://pingcap.com/docs/v2.0/sql/understanding-the-query-execution-plan/", "title": "Understand the Query Execution Plan", "content": " Understand the Query Execution Plan Based on the details of your tables, the TiDB optimizer chooses the most efficient query execution plan, which consists of a series of operators. This document details the execution plan information returned by the EXPLAIN statement in TiDB.Optimize SQL statements using EXPLAIN The result of the EXPLAIN statement provides information about how TiDB executes SQL queries: EXPLAIN works together with SELECT, DELETE, INSERT, REPLACE, and UPDATE. When you run the EXPLAIN statement, TiDB returns the final physical execution plan which is optimized by the SQL statment of EXPLAIN. In other words, EXPLAIN displays the complete information about how TiDB executes the SQL statement, such as in which order, how tables are joined, and what the expression tree looks like. For more information, see EXPLAIN output format. TiDB does not support EXPLAIN [options] FOR CONNECTION connection_id currently. We’ll do it in the future. For more information, see #4351. The results of EXPLAIN shed light on how to index the data tables so that the execution plan can use the index to speed up the execution of SQL statements. You can also use EXPLAIN to check if the optimizer chooses the optimal order to join tables.EXPLAIN output format Currently, the EXPLAIN statement returns the following four columns: id, count, task, operator info. Each operator in the execution plan is described by the four properties. In the results returned by EXPLAIN, each row describes an operator. See the following table for details: Property Name Description id The id of an operator, to identify the uniqueness of an operator in the entire execution plan. As of TiDB 2.1, the id includes formatting to show a tree structure of operators. The data flows from a child to its parent, and each operator has one and only one parent. count An estimation of the number of data items that the current operator outputs, based on the statistics and the execution logic of the operator task the task that the current operator belongs to. The current execution plan contains two types of tasks: 1) the root task that runs on the TiDB server; 2) the cop task that runs concurrently on the TiKV server. The topological relations of the current execution plan in the task level is that a root task can be followed by many cop tasks. The root task uses the output of cop task as the input. The cop task executes the tasks that TiDB pushes to TiKV. Each cop task scatters in the TiKV cluster and is executed by multiple processes. operator info The details about each operator. The information of each operator differs from others, see Operator Info. Overview Introduction to task Currently, the calculation task of TiDB contains two different tasks: cop task and root task. The cop task refers to the computing task that is pushed to the KV side and executed distributedly. The root task refers to the computing task that is executed at a single point in TiDB. One of the goals of SQL optimization is to push the calculation down to the KV side as much as possible.Table data and index data The table data in TiDB refers to the raw data of a table, which is stored in TiKV. For each row of the table data, its key is a 64-bit integer called Handle ID. If a table has int type primary key, the value of the primary key is taken as the Handle ID of the table data, otherwise the system automatically generates the Handle ID. The value of the table data is encoded by all the data in this row. When the table data is read, return the results in the order in which the Handle ID is incremented.Similar to the table data, the index data in TiDB is also stored in TiKV. The key of index data is ordered bytes encoded by index columns. The value is the Handle ID of each row of index data. You can use the Handle ID to read the non-index columns in this row. When the index data is read, return the results in the order in which the index columns are incremented. If the case of multiple index columns, make sure that the first column is incremented and that the i + 1 column is incremented when the i column is equal.Range query In the WHERE/HAVING/ON condition, analyze the results returned by primary key or index key queries. For example, number and date types of comparison symbols, greater than, less than, equal to, greater than or equal to, less than or equal to, and character type LIKE symbols.TiDB only supports the comparison symbols of which one side is a column and the other side is a constant or can be calculated as a constant. Query conditions like year(birth_day) < 1992 cannot use the index. Try to use the same type to compare: additional cast operations prevent the index from being used. For example, in user_id = 123456, if the user_id is a string, you need to write 123456 as a string constant.Using AND and OR combination on the range query conditions of the same column is equivalent to getting the intersection or union set. For multidimensional combined indexes, you can write the conditions for multiple columns. For example, in the (a, b, c) combined index, when a is an equivalent query, you can continue to calculate the query range of b; when b is also an equivalent query, you can continue to calculate the query range of c; otherwise, if a is a non-equivalent query, you can only calculate the query range of a.Operator info TableReader and TableScan TableScan refers to scanning the table data at the KV side. TableReader refers to reading the table data from TiKV at the TiDB side. TableReader and TableScan are the two operators of one function. The table represents the table name in SQL statements. If the table is renamed, it displays the new name. The range represents the range of scanned data. If the WHERE/HAVING/ON condition is not specified in the query, full table scan is executed. If the range query condition is specified on the int type primary keys, range query is executed. The keep order indicates whether the table scan is returned in order.IndexReader and IndexLookUp The index data in TiDB is read in two ways: 1) IndexReader represents reading the index columns directly from the index, which is used when only index related columns or primary keys are quoted in SQL statements; 2) IndexLookUp represents filtering part of the data from the index, returning only the Handle ID, and retrieving the table data again using Handle ID. In the second way, data is retrieved twice from TiKV. The way of reading index data is automatically selected by the optimizer.Similar to TableScan, IndexScan is the operator to read index data in the KV side. The table represents the table name in SQL statements. If the table is renamed, it displays the new name. The index represents the index name. The range represents the range of scanned data. The out of order indicates whether the index scan is returned in order. In TiDB, the primary key composed of multiple columns or non-int columns is treated as the unique index.Selection Selection represents the selection conditions in SQL statements, usually used in WHERE/HAVING/ON clause.Projection Projection corresponds to the SELECT list in SQL statements, used to map the input data into new output data.Aggregation Aggregation corresponds to Group By in SQL statements, or the aggregate functions if the Group By statement does not exist, such as the COUNT or SUM function. TiDB supports two aggregation algorithms: Hash Aggregation and Stream Aggregation. Hash Aggregation is a hash-based aggregation algorithm. If Hash Aggregation is close to the read operator of Table or Index, the aggregation operator pre-aggregates in TiKV to improve the concurrency and reduce the network load.Join TiDB supports Inner Join and Left/Right Outer Join, and automatically converts the external connection that can be simplified to Inner Join.TiDB supports three Join algorithms: Hash Join, Sort Merge Join and Index Look up Join. The principle of Hash Join is to pre-load the memory with small …"}, {"url": "https://pingcap.com/tidb-academy/mysql_dbas/upgrades/updates/", "title": "Updates", "content": " Updates Resources Container Definition for TiDBTranscript So let’s discuss updates first. Starting with the lowest level, and working our way up.In our cloud deployment, patching of the infrastructure, switches, routers, firmware is all handled by Google. Sitting above that is Kubernetes, which is also handled by Google.We then have the Google Kubernetes Engine and the node pool of VMs running Container-Optimized OS (COS).We have some flexibility in selecting the master version of the Google Kubernetes Engine (at writing the default is 1.9.7), but ultimately Google manages the patching for everything I have mentioned so far.In an on-premises deployment, you may have an infrastructure team that is responsible for patching these components. The good news is that none of this is specific to the TiDB platform so far, and to add to that because each TiDB platform component has built-in High Availability, it makes updates easier.If you need to perform a rolling update where you temporarily shutdown infrastructure as you patch it, that is fine.Sitting above the Google Kubernetes Engine is the TiDB operator and container images for TiDB. One of the nice properties of containers being lighter weight than a full operating system, is there is less surface area for security vulnerabilities.The TiDB container images provided with TiDB operator are built with something called the builder pattern.This means that an initial container is used to build the software binary, and then only the essential components are copied to a new container.The builder pattern plus the use of a minimal alpine Linux base image is considered a best practice in the Kubernetes world, as it has the least amount of surface area for exposure.Moving up the stack, the next component is the TiDB platform itself, and applying minor version updates such as from 2.0.4 to 2.0.7.The first point is that you do not need to follow these updates in order, so upgrading from any 2.0.x to 2.0.y is expected to be a very low risk.TiDB operator also allows you to perform a rolling upgrade and increase the minor version of each pod one after the other without downtime.The second point is what is the best way to find out about updates to TiDB components:One way is that you can watch for CVEs that affect TiDB. If you come from a systems administration background, you will be familiar with the CVE process and know how to watch for vulnerabilities that affect you.But the easier way, and one I recommend is to make sure that you are subscribed for receiving updates with your pingcap.com account. This allows you to receive an email as new updates are released."}, {"url": "https://pingcap.com/tidb-academy/mysql_dbas/upgrades/overview/", "title": "Updates, Upgrades and Migrations", "content": " Updates, Upgrades and Migrations Transcript Welcome back.In this section, we are going to be talking about updates, upgrades, and migrations. To define the terminology: An update is a point release, for example, from TiDB 2.0.4 to 2.0.7. Updates are always expected to be safe to perform, and contain fixes to critical bugs (either security of functionality). They typically will not contain new functionality or changes to behaviors. I usually group Operating System patches into the same category, since it is important to keep up to date with vendor supported patches. An upgrade could be from TiDB 1.0 to 2.0 or TiDB 2.0 to 2.1. These releases contain additional functionality, and while typically compatible it is recommended to apply basic testing to ensure everything works as expected for your specific workload. A migration is converting from one technology to another. For example, migrating from MySQL to TiDB. In this section, we will be describing all three as it applies to TiDB and the KOST stack. Starting with updates and upgrades."}, {"url": "https://pingcap.com/docs/tools/upgrade-loader-or-syncer-to-dm/", "title": "Upgrade Loader or Syncer to Data Migration", "content": " Upgrade Loader or Syncer to Data Migration This document introduces how to upgrade Loader or Syncer to DM (Data Migration).Upgrade Loader to Data Migration Loader is a tool used to load the full data that is dumped from mydumper to TiDB.When the task-mode of the task DM executes is full, DM automatically uses dumper to dump data and then uses loader to load the data.To upgrade Loader to DM, perform the following steps: Deploy the DM cluster. Refer to Loader configuration change and generate the corresponding task configuration file. Use dmctl to start the task. Loader Configuration change Loader uses the TOML file to define the process-related operation parameters and synchronization task parameters; DM uses the YAML file to define task configuration file parameters.Taking the configuration options in Data Migration Task Configuration File as examples, the corresponding relationship of task configuration options between Loader and DM is as follows: Configuration in Loader Corresponding configuration in DM pool-size pool-size of loader dir dir of loader db target-database alternative-db Deprecated source-db Deprecated route-rules route-rules pattern-schema schema-pattern pattern-table table-pattern do-db do-dbs of black-white-list. The filtering feature of databases has been refactored. For detailed configuration, see do-dbs in Data Migration Task Configuration File. do-table do-tables of black-white-list. The filtering feature of tables has been refactored. For detailed configuration, see do-tables in Data Migration Task Configuration File. ignore-db ignore-dbs of black-white-list. The filtering feature of databases has been refactored. For detailed configuration, see ignore-dbs in Data Migration Task Configuration File. ignore-table ignore-tables of black-white-list. The filtering feature of tables has been refactored. For detailed configuration, see ignore-tables in Data Migration Task Configuration File. rm-checkpoint Deprecated. A configuration option with a similar feature is remove-meta. Taking the configuration options in Data Migration Task Configuration File as examples, the corresponding relationship of task configuration options between mydumper and DM is as follows: Configuration in mydumper Corresponding configuration in DM host No corresponding option. Configured when DM-worker is deployed. port No corresponding option. Configured when DM-worker is deployed. user No corresponding option. Configured when DM-worker is deployed. password No corresponding option. Configured when DM-worker is deployed. threads threads of mydumper chunk-filesize chunk-filesize of mydumper skip-tz-utc skip-tz-utc of mydumper Other options are specified using extra-args of mydumper. Their usage in DM is the same as that in mydumper.Upgrade Syncer to Data Migration Syncer is a tool used to import data incrementally. The task Syncer executes is corresponding to the synchronization task with incremental task-mode in DM. The syncer processing unit feature of dm-worker in DM is corresponding to the Syncer feature.To upgrade Syncer to DM, perform the following steps: Deploy the DM cluster. Refer to Syncer configuration change and generate the corresponding task configuration file. Use dmctl to start the task. Syncer Configuration change Syncer uses the TOML file to define the process-related operation parameters and synchronization task parameters; DM uses the YAML file to define task configuration file parameters.Taking the configuration options in Data Migration Task Configuration File as examples, the corresponding relationship of task configuration options between Syncer and DM is as follows: Configuration in Syncer Corresponding configuration in DM server-id Transferred to dm-worker.toml flavor Transferred to dm-worker.toml enable-gtid Transferred to dm-worker.toml auto-fix-gtid Transferred to dm-worker.toml meta meta of mysql-instances. binlog-name/binlog-pos of meta in Syncer corresponds to that of mysql-instances. persistent-dir Deprecated worker-count worker-count of syncer batch batch of syncer max-retry max-retry of syncer do-db do-dbs of black-white-list. The filtering feature of databases has been refactored. For detailed configuration, see do-dbs in Data Migration Task Configuration File. do-table do-tables of black-white-list. The filtering feature of tables has been refactored. For detailed configuration, see do-tables in Data Migration Task Configuration File. ignore-db ingore-dbs of black-white-list. The filtering feature of databases has been refactored. For detailed configuration, see ignore-dbs in Data Migration Task Configuration File. ignore-table ignore-tables of black-white-list. The filtering feature of tables has been refactored. For detailed configuration, see ignore-tables in Data Migration Task Configuration File. skip-ddls Deprecated. Use filters. skip-sqls Deprecated. Use filters. skip-events Deprecated. Use filters. skip-dmls Deprecated. Use filters. route-rules route-rules pattern-schema schema-pattern pattern-table table-pattern from config of mysql-instances. Keep it consistent with the upstream MySQL information during the DM-worker deployment. to target-database disable-detect disable-detect of syncer safe-mode safe-mode of syncer stop-on-ddl Deprecated execute-ddl-timeout Deprecated execute-dml-timeout Deprecated "}, {"url": "https://pingcap.com/docs/op-guide/ansible-deployment-rolling-update/", "title": "Upgrade TiDB Using TiDB-Ansible", "content": " Upgrade TiDB Using TiDB-Ansible When you perform a rolling update for a TiDB cluster, the service is shut down serially and is started after you update the service binary and the configuration file. If the load balancing is configured in the front-end, the rolling update of TiDB does not impact the running applications. Minimum requirements: pd*3, tidb*2, tikv*3. Note: If the binlog is enabled, and Pump and Drainer services are deployed in the TiDB cluster, stop the Drainer service before the rolling update. The Pump service is automatically updated in the rolling update of TiDB. Upgrade the component version To upgrade between large versions, you must upgrade tidb-ansible. To upgrade the TiDB version from 1.0 to 2.0, see TiDB 2.0 Upgrade Guide. To upgrade the TiDB version from 2.0 to 2.1, see TiDB 2.1 Upgrade Guide. For a minor upgrade, it is also recommended to update tidb-ansible for the latest configuration file templates, features, and bug fixes. Download the binary automatically Edit the value of the tidb_version parameter in the /home/tidb/tidb-ansible/inventory.ini file, and specify the version number you need to upgrade to.For example, to upgrade from v2.0.6 to v2.0.7:tidb_version = v2.0.7 Note: If you use tidb-ansible of the master branch, you can keep tidb_version = latest. The installation package of the latest TiDB version is updated each day. Delete the existing downloads directory /home/tidb/tidb-ansible/downloads/.$ cd /home/tidb/tidb-ansible $ rm -rf downloads Use playbook to download the TiDB binary and replace the existing binary in /home/tidb/tidb-ansible/resource/bin/ with it automatically.$ ansible-playbook local_prepare.yml Download the binary manually You can also download the binary manually. Use wget to download the binary and replace the existing binary in /home/tidb/tidb-ansible/resource/bin/ with it manually.wget http://download.pingcap.org/tidb-v2.0.7-linux-amd64.tar.gz Note: Remember to replace the version number in the download link with the one you need. If you use tidb-ansible of the master branch, download the binary using the following command:$ wget http://download.pingcap.org/tidb-latest-linux-amd64.tar.gz Perform a rolling update using Ansible Apply a rolling update to the PD node (only upgrade the PD service)$ ansible-playbook rolling_update.yml --tags=pd When you apply a rolling update to the PD leader instance, if the number of PD instances is not less than 3, Ansible migrates the PD leader to another node before stopping this instance. Apply a rolling update to the TiKV node (only upgrade the TiKV service)$ ansible-playbook rolling_update.yml --tags=tikv When you apply a rolling update to the TiKV instance, Ansible migrates the Region leader to other nodes. The concrete logic is as follows: Call the PD API to add the evict leader scheduler -> Inspect the leader_count of this TiKV instance every 10 seconds -> Wait the leader_count to reduce to below 1, or until the times of inspecting the leader_count is more than 18 -> Start closing the rolling update of TiKV after three minutes of timeout -> Delete the evict leader scheduler after successful start. The operations are executed serially.If the rolling update fails in the process, log in to pd-ctl to execute scheduler show and check whether evict-leader-scheduler exists. If it does exist, delete it manually. Replace {PD_IP} and {STORE_ID} with your PD IP and the store_id of the TiKV instance:$ /home/tidb/tidb-ansible/resources/bin/pd-ctl -u "http://{PD_IP}:2379"$ /home/tidb/tidb-ansible/resources/bin/pd-ctl -u "http://{PD_IP}:2379" » scheduler show [ "label-scheduler", "evict-leader-scheduler-{STORE_ID}", "balance-region-scheduler", "balance-leader-scheduler", "balance-hot-region-scheduler" ] » scheduler remove evict-leader-scheduler-{STORE_ID} Apply a rolling update to the TiDB node (only upgrade the TiDB service)If the binlog is enabled in the TiDB cluster, the Pump service is automatically upgraded in the rolling update of the TiDB service.$ ansible-playbook rolling_update.yml --tags=tidb Apply a rolling update to all services (upgrade PD, TiKV, and TiDB in sequence)If the binlog is enabled in the TiDB cluster, the Pump service is automatically upgraded in the rolling update of the TiDB service.$ ansible-playbook rolling_update.yml Apply a rolling update to the monitoring component$ ansible-playbook rolling_update_monitor.yml Modify component configuration This section describes how to modify component configuration using Ansible. Update the component configuration template.The component configuration template of the TiDB cluster is in the /home/tidb/tidb-ansible/conf folder. Component Template Name of the Configuration File TiDB tidb.yml TiKV tikv.yml PD pd.yml The comment status if the default configuration item, which uses the default value. To modify it, you need to cancel the comment by removing # and then modify the corresponding parameter value.The configuration template uses the yaml format, so separate the parameter name and the parameter value using :, and indent two spaces.For example, modify the value of the high-concurrency, normal-concurrency and low-concurrency parameters to 16 for the TiKV component:readpool: coprocessor: # Notice: if CPU_NUM > 8, the default thread pool size for coprocessors # will be set to CPU_NUM * 0.8. high-concurrency: 16 normal-concurrency: 16 low-concurrency: 16 After modifying the component configuration, you need to perform a rolling update using Ansible. See Perform a rolling update using Ansible. "}, {"url": "https://pingcap.com/docs/v2.0/op-guide/ansible-deployment-rolling-update/", "title": "Upgrade TiDB Using TiDB-Ansible", "content": " Upgrade TiDB Using TiDB-Ansible When you perform a rolling update for a TiDB cluster, the service is shut down serially and is started after you update the service binary and the configuration file. If the load balancing is configured in the front-end, the rolling update of TiDB does not impact the running applications. Minimum requirements: pd*3, tidb*2, tikv*3. Note: If the binlog is enabled, and Pump and Drainer services are deployed in the TiDB cluster, stop the Drainer service before the rolling update. The Pump service is automatically updated in the rolling update of TiDB. Upgrade the component version To upgrade between large versions, you need to upgrade tidb-ansible. If you want to upgrade the version of TiDB from 1.0 to 2.0, see TiDB 2.0 Upgrade Guide. For a minor upgrade, it is also recommended to update tidb-ansible for the latest configuration file templates, features, and bug fixes. Download the binary automatically Edit the value of the tidb_version parameter in the /home/tidb/tidb-ansible/inventory.ini file, and specify the version number you need to upgrade to.For example, to upgrade from v2.0.2 to v2.0.3:tidb_version = v2.0.3 Delete the existing downloads directory /home/tidb/tidb-ansible/downloads/.$ cd /home/tidb/tidb-ansible $ rm -rf downloads Use playbook to download the TiDB v2.0.3 binary and replace the existing binary in /home/tidb/tidb-ansible/resource/bin/ with it automatically.$ ansible-playbook local_prepare.yml Download the binary manually You can also download the binary manually. Use wget to download the binary and replace the existing binary in /home/tidb/tidb-ansible/resource/bin/ with it manually.wget http://download.pingcap.org/tidb-v2.0.3-linux-amd64-unportable.tar.gz Note: Remember to replace the version number in the download link with the one you need. Perform a rolling update using Ansible Apply a rolling update to the PD node (only upgrade the PD service)$ ansible-playbook rolling_update.yml --tags=pd When you apply a rolling update to the PD leader instance, if the number of PD instances is not less than 3, Ansible migrates the PD leader to another node before stopping this instance. Apply a rolling update to the TiKV node (only upgrade the TiKV service)$ ansible-playbook rolling_update.yml --tags=tikv When you apply a rolling update to the TiKV instance, Ansible migrates the Region leader to other nodes. The concrete logic is as follows: Call the PD API to add the evict leader scheduler -> Inspect the leader_count of this TiKV instance every 10 seconds -> Wait the leader_count to reduce to below 1, or until the times of inspecting the leader_count is more than 18 -> Start closing the rolling update of TiKV after three minutes of timeout -> Delete the evict leader scheduler after successful start. The operations are executed serially.If the rolling update fails in the process, log in to pd-ctl to execute scheduler show and check whether evict-leader-scheduler exists. If it does exist, delete it manually. Replace {PD_IP} and {STORE_ID} with your PD IP and the store_id of the TiKV instance:$ /home/tidb/tidb-ansible/resources/bin/pd-ctl -u "http://{PD_IP}:2379"$ /home/tidb/tidb-ansible/resources/bin/pd-ctl -u "http://{PD_IP}:2379" » scheduler show [ "label-scheduler", "evict-leader-scheduler-{STORE_ID}", "balance-region-scheduler", "balance-leader-scheduler", "balance-hot-region-scheduler" ] » scheduler remove evict-leader-scheduler-{STORE_ID} Apply a rolling update to the TiDB node (only upgrade the TiDB service)If the binlog is enabled in the TiDB cluster, the Pump service is automatically upgraded in the rolling update of the TiDB service.$ ansible-playbook rolling_update.yml --tags=tidb Apply a rolling update to all services (upgrade PD, TiKV, and TiDB in sequence)If the binlog is enabled in the TiDB cluster, the Pump service is automatically upgraded in the rolling update of the TiDB service.$ ansible-playbook rolling_update.yml Apply a rolling update to the monitoring component$ ansible-playbook rolling_update_monitor.yml Modify component configuration This section describes how to modify component configuration using Ansible. Update the component configuration template.The component configuration template of the TiDB cluster is in the /home/tidb/tidb-ansible/conf folder. Component Template Name of the Configuration File TiDB tidb.yml TiKV tikv.yml PD pd.yml The comment status if the default configuration item, which uses the default value. To modify it, you need to cancel the comment by removing # and then modify the corresponding parameter value.The configuration template uses the yaml format, so separate the parameter name and the parameter value using :, and indent two spaces.For example, modify the value of the high-concurrency, normal-concurrency and low-concurrency parameters to 16 for the TiKV component:readpool: coprocessor: # Notice: if CPU_NUM > 8, the default thread pool size for coprocessors # will be set to CPU_NUM * 0.8. high-concurrency: 16 normal-concurrency: 16 low-concurrency: 16 After modifying the component configuration, you need to perform a rolling update using Ansible. See Perform a rolling update using Ansible. "}, {"url": "https://pingcap.com/tidb-academy/mysql_dbas/upgrades/upgrades/", "title": "Upgrades", "content": " Upgrades Transcript Upgrades are often less time sensitive or critical than updates.Rather than the motivation being security updates as it is with updates, an upgrade is more forward looking and strategic. The motivation could be for improved compatibility with MySQL, performance enhancements, or an entirely new feature.In the case of TiDB, you may be planning your upgrade from TiDB 2.0 to 2.1.Using this as an example, an upgrade to 2.1 would bring you: A number of performance enhancements such as a “fast-path” optimization for point lookup queries. For very simple queries, TiDB skips large parts of its optimizer and the co-processor and just retrieves records directly from TiKV, improving performance by up to 40%. Improvements for analytics queries, such as improved parallel execution. Experimental support for table partitioning. In most cases, upgrades are a safe and straight forward process. But if you come from a Database Administration background, you probably know it is better to play safe and not rush into an upgrade.From my experience working on the MySQL Server, the most typical upgrade related issue that I encountered was regressions in query optimization. Because SQL is declarative (as we covered earlier in query optimization), it doesn’t actually instruct how the query should be executed. And while this makes it easier for newer versions of the software to introduce performance improvements, there are edge cases.It is not unheard of for a new query optimization to make a certain type of query much faster, but also incorrectly be applied in scenarios which make queries slower.If you have an application that is particularly sensitive to performance regressions, you may want to look at evaluating your upgrade with the help of some third party tools. I will talk about these in more detail in our next video, on migration."}, {"url": "https://pingcap.com/docs/sql/encrypted-connections/", "title": "Use Encrypted Connections", "content": " Use Encrypted Connections It is recommended to use the encrypted connection to ensure data security because non-encrypted connection might lead to information leak.The TiDB server supports the encrypted connection based on the TLS (Transport Layer Security). The protocol is consistent with MySQL encrypted connections and is directly supported by existing MySQL clients such as MySQL operation tools and MySQL drivers. TLS is sometimes referred to as SSL (Secure Sockets Layer). Because the SSL protocol has known security vulnerabilities, TiDB does not support it. TiDB supports the following versions: TLS 1.0, TLS 1.1, and TLS 1.2.After using an encrypted connection, the connection has the following security properties: Confidentiality: the traffic plaintext cannot be eavesdropped Integrity: the traffic plaintext cannot be tampered Authentication: (optional) the client and the server can verify the identity of both parties to avoid man-in-the-middle attacks The encrypted connections in TiDB are disabled by default. To use encrypted connections in the client, you must first configure the TiDB server and enable encrypted connections. In addition, similar to MySQL, the encrypted connections in TiDB consist of single optional connection. For a TiDB server with encrypted connections enabled, you can choose to securely connect to the TiDB server through an encrypted connection, or to use a generally unencrypted connection. Most MySQL clients do not use encrypted connections by default, so generally the client is explicitly required to use an encrypted connection.In short, to use encrypted connections, both of the following conditions must be met: Enable encrypted connections in the TiDB server. The client specifies to use an encrypted connection. Configure TiDB to use encrypted connections See the following desrciptions about the related parameters to enable encrypted connections: ssl-cert: specifies the file path of the SSL certificate ssl-key: specifies the private key that matches the certificate ssl-ca: (optional) specifies the file path of the trusted CA certificate To enable encrypted connections in the TiDB server, you must specify both of the ssl-cert and ssl-key parameters in the configuration file when you start the TiDB server. You can also specify the ssl-ca parameter for client authentication (see Enable authentication).All the files specified by the parameters are in PEM (Privacy Enhanced Mail) format. Currently, TiDB does not support the import of a password-protected private key, so it is required to provide a private key file without a password. If the certificate or private key is invalid, the TiDB server starts as usual, but the client cannot connect to the TiDB server through an encrypted connection.The certificate or key is signed and generated using OpenSSL, or quickly generated using the mysql_ssl_rsa_setup tool in MySQL:mysql_ssl_rsa_setup --datadir=./certs This command generates the following files in the certs directory:certs ├── ca-key.pem ├── ca.pem ├── client-cert.pem ├── client-key.pem ├── private_key.pem ├── public_key.pem ├── server-cert.pem └── server-key.pem The corresponding TiDB configuration file parameters are:[security] ssl-cert = "certs/server-cert.pem" ssl-key = "certs/server-key.pem" If the certificate parameters are correct, TiDB outputs Secure connection is enabled when started, otherwise it outputs Secure connection is NOT ENABLED.Configure the MySQL client to use encrypted connections The client of MySQL 5.7 or later versions attempts to establish an encrypted connection by default. If the server does not support encrypted connections, it automatically returns to unencrypted connections. The client of MySQL earlier than version 5.7 uses the unencrypted connection by default.You can change the connection behavior of the client using the following --ssl-mode parameters: --ssl-mode=REQUIRED: The client requires an encrypted connection. The connection cannot be established if the server side does not support encrypted connections. In the absence of the --ssl-mode parameter: The client attempts to use an encrypted connection, but the encrypted connection cannot be established if the server side does not support encrypted connections. Then the client uses an unencrypted connection. --ssl-mode=DISABLED: The client uses an unencrypted connection. For more information, see Client-Side Configuration for Encrypted Connections in MySQL.Enable authentication If the ssl-ca parameter is not specified in the TiDB server or MySQL client, the client or the server does not perform authentication by default and cannot prevent man-in-the-middle attack. For example, the client might “securely” connect to a disguised client. You can configure the ssl-ca parameter for authentication in the server and client. Generally, you only need to authenticate the server, but you can also authenticate the client to further enhance the security. To authenticate the TiDB server from the MySQL client: Specify the ssl-cert and ssl-key parameters in the TiDB server. Specify the --ssl-ca parameter in the MySQL client. Specify the --ssl-mode to VERIFY_IDENTITY in the MySQL client. Make sure that the certificate (ssl-cert) configured by the TiDB server is signed by the CA specified by the client --ssl-ca parameter, otherwise the authentication fails. To authenticate the MySQL client from the TiDB server: Specify the ssl-cert, ssl-key, and ssl-ca parameters in the TiDB server. Specify the --ssl-cert and --ssl-key parameters in the client. Make sure the server-configured certificate and the client-configured certificate are both signed by the ssl-ca specified by the server. To perform mutual authentication, meet both of the above requirements. Note: Currently, it is optional that TiDB server authenticates the client. If the client does not present its identity certificate in the TLS handshake, the TLS connection can also be successfully established. Check whether the current connection uses encryption Use the SHOW STATUS LIKE "%Ssl%"; statement to get the details of the current connection, including whether encryption is used, the encryption protocol used by encrypted connections, the TLS version number and so on.See the following example of the result in an encrypted connection. The results change according to different TLS versions or encryption protocols supported by the client.mysql> SHOW STATUS LIKE "%Ssl%"; ...... | Ssl_verify_mode | 5 | | Ssl_version | TLSv1.2 | | Ssl_cipher | ECDHE-RSA-AES128-GCM-SHA256 | ...... For the official MySQL client, you can also use the STATUS or s statement to view the connection status:mysql> s ... SSL: Cipher in use is ECDHE-RSA-AES128-GCM-SHA256 ... Supported TLS versions, key exchange protocols, and encryption algorithms The TLS versions, key exchange protocols and encryption algorithms supported by TiDB are determined by the official Golang libraries.Supported TLS versions TLS 1.0 TLS 1.1 TLS 1.2 Supported key exchange protocols and encryption algorithms TLS_RSA_WITH_RC4_128_SHA TLS_RSA_WITH_3DES_EDE_CBC_SHA TLS_RSA_WITH_AES_128_CBC_SHA TLS_RSA_WITH_AES_256_CBC_SHA TLS_RSA_WITH_AES_128_CBC_SHA256 TLS_RSA_WITH_AES_128_GCM_SHA256 TLS_RSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_ECDSA_WITH_RC4_128_SHA TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA TLS_ECDHE_RSA_WITH_RC4_128_SHA TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305 TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 "}, {"url": "https://pingcap.com/docs/v1.0/sql/encrypted-connections/", "title": "Use Encrypted Connections", "content": " Use Encrypted Connections It is recommended to use the encrypted connection to ensure data security because non-encrypted connection might lead to information leak.The TiDB server supports the encrypted connection based on the TLS (Transport Layer Security). The protocol is consistent with MySQL encrypted connections and is directly supported by existing MySQL clients such as MySQL operation tools and MySQL drivers. TLS is sometimes referred to as SSL (Secure Sockets Layer). Because the SSL protocol has known security vulnerabilities, TiDB does not support it. TiDB supports the following versions: TLS 1.0, TLS 1.1, and TLS 1.2.After using an encrypted connection, the connection has the following security properties: Confidentiality: the traffic plaintext cannot be eavesdropped Integrity: the traffic plaintext cannot be tampered Authentication: (optional) the client and the server can verify the identity of both parties to avoid man-in-the-middle attacks The encrypted connections in TiDB are disabled by default. To use encrypted connections in the client, you must first configure the TiDB server and enable encrypted connections. In addition, similar to MySQL, the encrypted connections in TiDB consist of single optional connection. For a TiDB server with encrypted connections enabled, you can choose to securely connect to the TiDB server through an encrypted connection, or to use a generally unencrypted connection. Most MySQL clients do not use encrypted connections by default, so generally the client is explicitly required to use an encrypted connection.In short, to use encrypted connections, both of the following conditions must be met: Enable encrypted connections in the TiDB server. The client specifies to use an encrypted connection. Configure TiDB to use encrypted connections See the following desrciptions about the related parameters to enable encrypted connections: ssl-cert: specifies the file path of the SSL certificate ssl-key: specifies the private key that matches the certificate ssl-ca: (optional) specifies the file path of the trusted CA certificate To enable encrypted connections in the TiDB server, you must specify both of the ssl-cert and ssl-key parameters in the configuration file when you start the TiDB server. You can also specify the ssl-ca parameter for client authentication (see Enable authentication).All the files specified by the parameters are in PEM (Privacy Enhanced Mail) format. Currently, TiDB does not support the import of a password-protected private key, so it is required to provide a private key file without a password. If the certificate or private key is invalid, the TiDB server starts as usual, but the client cannot connect to the TiDB server through an encrypted connection.The certificate or key is signed and generated using OpenSSL, or quickly generated using the mysql_ssl_rsa_setup tool in MySQL:mysql_ssl_rsa_setup --datadir=./certs This command generates the following files in the certs directory:certs ├── ca-key.pem ├── ca.pem ├── client-cert.pem ├── client-key.pem ├── private_key.pem ├── public_key.pem ├── server-cert.pem └── server-key.pem The corresponding TiDB configuration file parameters are:[security] ssl-cert = "certs/server-cert.pem" ssl-key = "certs/server-key.pem" If the certificate parameters are correct, TiDB outputs Secure connection is enabled when started, otherwise it outputs Secure connection is NOT ENABLED.Configure the MySQL client to use encrypted connections The client of MySQL 5.7 or later versions attempts to establish an encrypted connection by default. If the server does not support encrypted connections, it automatically returns to unencrypted connections. The client of MySQL earlier than version 5.7 uses the unencrypted connection by default.You can change the connection behavior of the client using the following --ssl-mode parameters: --ssl-mode=REQUIRED: The client requires an encrypted connection. The connection cannot be established if the server side does not support encrypted connections. In the absence of the --ssl-mode parameter: The client attempts to use an encrypted connection, but the encrypted connection cannot be established if the server side does not support encrypted connections. Then the client uses an unencrypted connection. --ssl-mode=DISABLED: The client uses an unencrypted connection. For more information, see Client-Side Configuration for Encrypted Connections in MySQL.Enable authentication If the ssl-ca parameter is not specified in the TiDB server or MySQL client, the client or the server does not perform authentication by default and cannot prevent man-in-the-middle attack. For example, the client might “securely” connect to a disguised client. You can configure the ssl-ca parameter for authentication in the server and client. Generally, you only need to authenticate the server, but you can also authenticate the client to further enhance the security. To authenticate the TiDB server from the MySQL client: Specify the ssl-cert andssl-key parameters in the TiDB server. Specify the --ssl-ca parameter in the MySQL client. Specify the --ssl-mode to VERIFY_IDENTITY in the MySQL client. Make sure that the certificate (ssl-cert) configured by the TiDB server is signed by the CA specified by the client --ssl-ca parameter, otherwise the authentication fails. To authenticate the MySQL client from the TiDB server: Specify the ssl-cert, ssl-key, and ssl-ca parameters in the TiDB server. Specify the --ssl-cert and --ssl-key parameters in the client. Make sure the server-configured certificate and the client-configured certificate are both signed by the ssl-ca specified by the server. To perform mutual authentication, meet both of the above requirements. Note: Currently, it is optional that TiDB server authenticates the client. If the client does not present its identity certificate in the TLS handshake, the TLS connection can also be successfully established. Check whether the current connection uses encryption Use the SHOW STATUS LIKE "%Ssl%"; statement to get the details of the current connection, including whether encryption is used, the encryption protocol used by encrypted connections, the TLS version number and so on.See the following example of the result in an encrypted connection. The results change according to different TLS versions or encryption protocols supported by the client.mysql> SHOW STATUS LIKE "%Ssl%"; ...... | Ssl_verify_mode | 5 | | Ssl_version | TLSv1.2 | | Ssl_cipher | ECDHE-RSA-AES128-GCM-SHA256 | ...... Besides, for the official MySQL client, you can also use the STATUS or s statement to view the connection status:mysql> s ... SSL: Cipher in use is ECDHE-RSA-AES128-GCM-SHA256 ... Supported TLS versions, key exchange protocols, and encryption algorithms The TLS versions, key exchange protocols and encryption algorithms supported by TiDB are determined by the official Golang libraries.Supported TLS versions TLS 1.0 TLS 1.1 TLS 1.2 Supported key exchange protocols and encryption algorithms TLS_RSA_WITH_RC4_128_SHA TLS_RSA_WITH_3DES_EDE_CBC_SHA TLS_RSA_WITH_AES_128_CBC_SHA TLS_RSA_WITH_AES_256_CBC_SHA TLS_RSA_WITH_AES_128_CBC_SHA256 TLS_RSA_WITH_AES_128_GCM_SHA256 TLS_RSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_ECDSA_WITH_RC4_128_SHA TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA TLS_ECDHE_RSA_WITH_RC4_128_SHA TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305 TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 "}, {"url": "https://pingcap.com/docs/v2.0/sql/encrypted-connections/", "title": "Use Encrypted Connections", "content": " Use Encrypted Connections It is recommended to use the encrypted connection to ensure data security because non-encrypted connection might lead to information leak.The TiDB server supports the encrypted connection based on the TLS (Transport Layer Security). The protocol is consistent with MySQL encrypted connections and is directly supported by existing MySQL clients such as MySQL operation tools and MySQL drivers. TLS is sometimes referred to as SSL (Secure Sockets Layer). Because the SSL protocol has known security vulnerabilities, TiDB does not support it. TiDB supports the following versions: TLS 1.0, TLS 1.1, and TLS 1.2.After using an encrypted connection, the connection has the following security properties: Confidentiality: the traffic plaintext cannot be eavesdropped Integrity: the traffic plaintext cannot be tampered Authentication: (optional) the client and the server can verify the identity of both parties to avoid man-in-the-middle attacks The encrypted connections in TiDB are disabled by default. To use encrypted connections in the client, you must first configure the TiDB server and enable encrypted connections. In addition, similar to MySQL, the encrypted connections in TiDB consist of single optional connection. For a TiDB server with encrypted connections enabled, you can choose to securely connect to the TiDB server through an encrypted connection, or to use a generally unencrypted connection. Most MySQL clients do not use encrypted connections by default, so generally the client is explicitly required to use an encrypted connection.In short, to use encrypted connections, both of the following conditions must be met: Enable encrypted connections in the TiDB server. The client specifies to use an encrypted connection. Configure TiDB to use encrypted connections See the following desrciptions about the related parameters to enable encrypted connections: ssl-cert: specifies the file path of the SSL certificate ssl-key: specifies the private key that matches the certificate ssl-ca: (optional) specifies the file path of the trusted CA certificate To enable encrypted connections in the TiDB server, you must specify both of the ssl-cert and ssl-key parameters in the configuration file when you start the TiDB server. You can also specify the ssl-ca parameter for client authentication (see Enable authentication).All the files specified by the parameters are in PEM (Privacy Enhanced Mail) format. Currently, TiDB does not support the import of a password-protected private key, so it is required to provide a private key file without a password. If the certificate or private key is invalid, the TiDB server starts as usual, but the client cannot connect to the TiDB server through an encrypted connection.The certificate or key is signed and generated using OpenSSL, or quickly generated using the mysql_ssl_rsa_setup tool in MySQL:mysql_ssl_rsa_setup --datadir=./certs This command generates the following files in the certs directory:certs ├── ca-key.pem ├── ca.pem ├── client-cert.pem ├── client-key.pem ├── private_key.pem ├── public_key.pem ├── server-cert.pem └── server-key.pem The corresponding TiDB configuration file parameters are:[security] ssl-cert = "certs/server-cert.pem" ssl-key = "certs/server-key.pem" If the certificate parameters are correct, TiDB outputs Secure connection is enabled when started, otherwise it outputs Secure connection is NOT ENABLED.Configure the MySQL client to use encrypted connections The client of MySQL 5.7 or later versions attempts to establish an encrypted connection by default. If the server does not support encrypted connections, it automatically returns to unencrypted connections. The client of MySQL earlier than version 5.7 uses the unencrypted connection by default.You can change the connection behavior of the client using the following --ssl-mode parameters: --ssl-mode=REQUIRED: The client requires an encrypted connection. The connection cannot be established if the server side does not support encrypted connections. In the absence of the --ssl-mode parameter: The client attempts to use an encrypted connection, but the encrypted connection cannot be established if the server side does not support encrypted connections. Then the client uses an unencrypted connection. --ssl-mode=DISABLED: The client uses an unencrypted connection. For more information, see Client-Side Configuration for Encrypted Connections in MySQL.Enable authentication If the ssl-ca parameter is not specified in the TiDB server or MySQL client, the client or the server does not perform authentication by default and cannot prevent man-in-the-middle attack. For example, the client might “securely” connect to a disguised client. You can configure the ssl-ca parameter for authentication in the server and client. Generally, you only need to authenticate the server, but you can also authenticate the client to further enhance the security. To authenticate the TiDB server from the MySQL client: Specify the ssl-cert andssl-key parameters in the TiDB server. Specify the --ssl-ca parameter in the MySQL client. Specify the --ssl-mode to VERIFY_IDENTITY in the MySQL client. Make sure that the certificate (ssl-cert) configured by the TiDB server is signed by the CA specified by the client --ssl-ca parameter, otherwise the authentication fails. To authenticate the MySQL client from the TiDB server: Specify the ssl-cert, ssl-key, and ssl-ca parameters in the TiDB server. Specify the --ssl-cert and --ssl-key parameters in the client. Make sure the server-configured certificate and the client-configured certificate are both signed by the ssl-ca specified by the server. To perform mutual authentication, meet both of the above requirements. Note: Currently, it is optional that TiDB server authenticates the client. If the client does not present its identity certificate in the TLS handshake, the TLS connection can also be successfully established. Check whether the current connection uses encryption Use the SHOW STATUS LIKE "%Ssl%"; statement to get the details of the current connection, including whether encryption is used, the encryption protocol used by encrypted connections, the TLS version number and so on.See the following example of the result in an encrypted connection. The results change according to different TLS versions or encryption protocols supported by the client.mysql> SHOW STATUS LIKE "%Ssl%"; ...... | Ssl_verify_mode | 5 | | Ssl_version | TLSv1.2 | | Ssl_cipher | ECDHE-RSA-AES128-GCM-SHA256 | ...... For the official MySQL client, you can also use the STATUS or s statement to view the connection status:mysql> s ... SSL: Cipher in use is ECDHE-RSA-AES128-GCM-SHA256 ... Supported TLS versions, key exchange protocols, and encryption algorithms The TLS versions, key exchange protocols and encryption algorithms supported by TiDB are determined by the official Golang libraries.Supported TLS versions TLS 1.0 TLS 1.1 TLS 1.2 Supported key exchange protocols and encryption algorithms TLS_RSA_WITH_RC4_128_SHA TLS_RSA_WITH_3DES_EDE_CBC_SHA TLS_RSA_WITH_AES_128_CBC_SHA TLS_RSA_WITH_AES_256_CBC_SHA TLS_RSA_WITH_AES_128_CBC_SHA256 TLS_RSA_WITH_AES_128_GCM_SHA256 TLS_RSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_ECDSA_WITH_RC4_128_SHA TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA TLS_ECDHE_RSA_WITH_RC4_128_SHA TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305 TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 "}, {"url": "https://pingcap.com/tidb-planet/user/", "title": "User Information", "content": ""}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/user-defined-variables/", "title": "User-Defined Variables", "content": " 用户自定义变量 用户自定义变量格式为 @var_name。var_name 目前只支持字母,数字,_$组成。用户自定义变量是大小写不敏感的。用户自定义变量是跟 session 绑定的,也就是说只有当前连接可以看见设置的用户变量,其他客户端连接无法查看到。用 SET 语句可以设置用户自定义变量:SET @var_name = expr [, @var_name = expr] ... 或 SET @var_name := expr 对于 SET 语句,赋值操作符可以是 = 也可以是 :=例:mysql> SET @a1=1, @a2=2, @a3:=4; mysql> SELECT @a1, @a2, @t3, @a4 := @a1+@a2+@a3; +------+------+------+--------------------+ | @a1 | @a2 | @a3 | @a4 := @a1+@a2+@a3 | +------+------+------+--------------------+ | 1 | 2 | 4 | 7 | +------+------+------+--------------------+ 如果设置用户变量用了 HEX 或者 BIT 值,TiDB会把它当成二进制字符串。如果你要将其设置成数字,那么需要手动加上 CAST转换: CAST(.. AS UNSIGNED):mysql> SELECT @v1, @v2, @v3; +------+------+------+ | @v1 | @v2 | @v3 | +------+------+------+ | A | 65 | 65 | +------+------+------+ 1 row in set (0.00 sec) mysql> SET @v1 = b'1000001'; Query OK, 0 rows affected (0.00 sec) mysql> SET @v2 = b'1000001'+0; Query OK, 0 rows affected (0.00 sec) mysql> SET @v3 = CAST(b'1000001' AS UNSIGNED); Query OK, 0 rows affected (0.00 sec) mysql> SELECT @v1, @v2, @v3; +------+------+------+ | @v1 | @v2 | @v3 | +------+------+------+ | A | 65 | 65 | +------+------+------+ 1 row in set (0.00 sec) 如果获取一个没有设置过的变量,会返回一个 NULL:mysql> select @not_exist; +------------+ | @not_exist | +------------+ | NULL | +------------+ 1 row in set (0.00 sec) 用户自定义变量不能直接在 SQL 语句中被当成 identifier,例:mysql> select * from t; +------+ | a | +------+ | 1 | +------+ 1 row in set (0.00 sec) mysql> SET @col = "a"; Query OK, 0 rows affected (0.00 sec) mysql> SELECT @col FROM t; +------+ | @col | +------+ | a | +------+ 1 row in set (0.00 sec) mysql> SELECT `@col` FROM t; ERROR 1054 (42S22): Unknown column '@col' in 'field list' mysql> SET @col = "`a`"; Query OK, 0 rows affected (0.00 sec) mysql> SELECT @col FROM t; +------+ | @col | +------+ | `a` | +------+ 1 row in set (0.01 sec) 但是有一个例外是如果你在 PREPARE 语句中使用它,是可以的:mysql> PREPARE stmt FROM "SELECT @c FROM t"; Query OK, 0 rows affected (0.00 sec) mysql> EXECUTE stmt; +------+ | @c | +------+ | a | +------+ 1 row in set (0.01 sec) mysql> DEALLOCATE PREPARE stmt; Query OK, 0 rows affected (0.00 sec) 更多细节"}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/user-defined-variables/", "title": "User-Defined Variables", "content": " 用户自定义变量 用户自定义变量格式为 @var_name。var_name 目前只支持字母,数字,_$组成。用户自定义变量是大小写不敏感的。用户自定义变量是跟 session 绑定的,也就是说只有当前连接可以看见设置的用户变量,其他客户端连接无法查看到。用 SET 语句可以设置用户自定义变量:SET @var_name = expr [, @var_name = expr] ... 或 SET @var_name := expr 对于 SET 语句,赋值操作符可以是 = 也可以是 :=例:mysql> SET @a1=1, @a2=2, @a3:=4; mysql> SELECT @a1, @a2, @t3, @a4 := @a1+@a2+@a3; +------+------+------+--------------------+ | @a1 | @a2 | @a3 | @a4 := @a1+@a2+@a3 | +------+------+------+--------------------+ | 1 | 2 | 4 | 7 | +------+------+------+--------------------+ 如果设置用户变量用了 HEX 或者 BIT 值,TiDB会把它当成二进制字符串。如果你要将其设置成数字,那么需要手动加上 CAST转换: CAST(.. AS UNSIGNED):mysql> SELECT @v1, @v2, @v3; +------+------+------+ | @v1 | @v2 | @v3 | +------+------+------+ | A | 65 | 65 | +------+------+------+ 1 row in set (0.00 sec) mysql> SET @v1 = b'1000001'; Query OK, 0 rows affected (0.00 sec) mysql> SET @v2 = b'1000001'+0; Query OK, 0 rows affected (0.00 sec) mysql> SET @v3 = CAST(b'1000001' AS UNSIGNED); Query OK, 0 rows affected (0.00 sec) mysql> SELECT @v1, @v2, @v3; +------+------+------+ | @v1 | @v2 | @v3 | +------+------+------+ | A | 65 | 65 | +------+------+------+ 1 row in set (0.00 sec) 如果获取一个没有设置过的变量,会返回一个 NULL:mysql> select @not_exist; +------------+ | @not_exist | +------------+ | NULL | +------------+ 1 row in set (0.00 sec) 用户自定义变量不能直接在 SQL 语句中被当成 identifier,例:mysql> select * from t; +------+ | a | +------+ | 1 | +------+ 1 row in set (0.00 sec) mysql> SET @col = "a"; Query OK, 0 rows affected (0.00 sec) mysql> SELECT @col FROM t; +------+ | @col | +------+ | a | +------+ 1 row in set (0.00 sec) mysql> SELECT `@col` FROM t; ERROR 1054 (42S22): Unknown column '@col' in 'field list' mysql> SET @col = "`a`"; Query OK, 0 rows affected (0.00 sec) mysql> SELECT @col FROM t; +------+ | @col | +------+ | `a` | +------+ 1 row in set (0.01 sec) 但是有一个例外是如果你在 PREPARE 语句中使用它,是可以的:mysql> PREPARE stmt FROM "SELECT @c FROM t"; Query OK, 0 rows affected (0.00 sec) mysql> EXECUTE stmt; +------+ | @c | +------+ | a | +------+ 1 row in set (0.01 sec) mysql> DEALLOCATE PREPARE stmt; Query OK, 0 rows affected (0.00 sec) 更多细节"}, {"url": "https://pingcap.com/docs/sql/user-defined-variables/", "title": "User-Defined Variables", "content": " User-Defined Variables The format of the user-defined variables is @var_name. @var_name consists of alphanumeric characters, _, and $. The user-defined variables are case-insensitive.The user-defined variables are session specific, which means a user variable defined by one client cannot be seen or used by other clients.You can use the SET statement to set a user variable:SET @var_name = expr [, @var_name = expr] ... orSET @var_name := expr For SET, you can use = or := as the assignment operator.For example:mysql> SET @a1=1, @a2=2, @a3:=4; mysql> SELECT @a1, @a2, @t3, @a4 := @a1+@a2+@a3; +------+------+------+--------------------+ | @a1 | @a2 | @a3 | @a4 := @a1+@a2+@a3 | +------+------+------+--------------------+ | 1 | 2 | 4 | 7 | +------+------+------+--------------------+ Hexadecimal or bit values assigned to user variables are treated as binary strings in TiDB. To assign a hexadecimal or bit value as a number, use it in numeric context. For example, add 0 or use CAST(... AS UNSIGNED):mysql> SELECT @v1, @v2, @v3; +------+------+------+ | @v1 | @v2 | @v3 | +------+------+------+ | A | 65 | 65 | +------+------+------+ 1 row in set (0.00 sec) mysql> SET @v1 = b'1000001'; Query OK, 0 rows affected (0.00 sec) mysql> SET @v2 = b'1000001'+0; Query OK, 0 rows affected (0.00 sec) mysql> SET @v3 = CAST(b'1000001' AS UNSIGNED); Query OK, 0 rows affected (0.00 sec) mysql> SELECT @v1, @v2, @v3; +------+------+------+ | @v1 | @v2 | @v3 | +------+------+------+ | A | 65 | 65 | +------+------+------+ 1 row in set (0.00 sec) If you refer to a user-defined variable that has not been initialized, it has a value of NULL and a type of string.mysql> select @not_exist; +------------+ | @not_exist | +------------+ | NULL | +------------+ 1 row in set (0.00 sec) The user-defined variables cannot be used as an identifier in the SQL statement. For example:mysql> select * from t; +------+ | a | +------+ | 1 | +------+ 1 row in set (0.00 sec) mysql> SET @col = "a"; Query OK, 0 rows affected (0.00 sec) mysql> SELECT @col FROM t; +------+ | @col | +------+ | a | +------+ 1 row in set (0.00 sec) mysql> SELECT `@col` FROM t; ERROR 1054 (42S22): Unknown column '@col' in 'field list' mysql> SET @col = "`a`"; Query OK, 0 rows affected (0.00 sec) mysql> SELECT @col FROM t; +------+ | @col | +------+ | `a` | +------+ 1 row in set (0.01 sec) An exception is that when you are constructing a string for use as a prepared statement to execute later:mysql> PREPARE stmt FROM "SELECT @c FROM t"; Query OK, 0 rows affected (0.00 sec) mysql> EXECUTE stmt; +------+ | @c | +------+ | a | +------+ 1 row in set (0.01 sec) mysql> DEALLOCATE PREPARE stmt; Query OK, 0 rows affected (0.00 sec) For more information, see User-Defined Variables in MySQL."}, {"url": "https://pingcap.com/docs/v1.0/sql/user-defined-variables/", "title": "User-Defined Variables", "content": " User-Defined Variables The format of the user-defined variables is @var_name. @var_name consists of alphanumeric characters, _, and $. The user-defined variables are case-insensitive.The user-defined variables are session specific, which means a user variable defined by one client cannot be seen or used by other clients. You can use the SET statement to set a user variable:SET @var_name = expr [, @var_name = expr] ... orSET @var_name := expr For SET, you can use = or := as the assignment operator.For example:mysql> SET @a1=1, @a2=2, @a3:=4; mysql> SELECT @a1, @a2, @t3, @a4 := @a1+@a2+@a3; +------+------+------+--------------------+ | @a1 | @a2 | @a3 | @a4 := @a1+@a2+@a3 | +------+------+------+--------------------+ | 1 | 2 | 4 | 7 | +------+------+------+--------------------+ Hexadecimal or bit values assigned to user variables are treated as binary strings in TiDB. To assign a hexadecimal or bit value as a number, use it in numeric context. For example, add 0 or use CAST(... AS UNSIGNED):mysql> SELECT @v1, @v2, @v3; +------+------+------+ | @v1 | @v2 | @v3 | +------+------+------+ | A | 65 | 65 | +------+------+------+ 1 row in set (0.00 sec) mysql> SET @v1 = b'1000001'; Query OK, 0 rows affected (0.00 sec) mysql> SET @v2 = b'1000001'+0; Query OK, 0 rows affected (0.00 sec) mysql> SET @v3 = CAST(b'1000001' AS UNSIGNED); Query OK, 0 rows affected (0.00 sec) mysql> SELECT @v1, @v2, @v3; +------+------+------+ | @v1 | @v2 | @v3 | +------+------+------+ | A | 65 | 65 | +------+------+------+ 1 row in set (0.00 sec) If you refer to a user-defined variable that has not been initialized, it has a value of NULL and a type of string.mysql> select @not_exist; +------------+ | @not_exist | +------------+ | NULL | +------------+ 1 row in set (0.00 sec) The user-defined variables cannot be used as an identifier in the SQL statement. For example:mysql> select * from t; +------+ | a | +------+ | 1 | +------+ 1 row in set (0.00 sec) mysql> SET @col = "a"; Query OK, 0 rows affected (0.00 sec) mysql> SELECT @col FROM t; +------+ | @col | +------+ | a | +------+ 1 row in set (0.00 sec) mysql> SELECT `@col` FROM t; ERROR 1054 (42S22): Unknown column '@col' in 'field list' mysql> SET @col = "`a`"; Query OK, 0 rows affected (0.00 sec) mysql> SELECT @col FROM t; +------+ | @col | +------+ | `a` | +------+ 1 row in set (0.01 sec) An exception is that when you are constructing a string for use as a prepared statement to execute later:mysql> PREPARE stmt FROM "SELECT @c FROM t"; Query OK, 0 rows affected (0.00 sec) mysql> EXECUTE stmt; +------+ | @c | +------+ | a | +------+ 1 row in set (0.01 sec) mysql> DEALLOCATE PREPARE stmt; Query OK, 0 rows affected (0.00 sec) For more information, see User-Defined Variables in MySQL."}, {"url": "https://pingcap.com/docs/v2.0/sql/user-defined-variables/", "title": "User-Defined Variables", "content": " User-Defined Variables The format of the user-defined variables is @var_name. @var_name consists of alphanumeric characters, _, and $. The user-defined variables are case-insensitive.The user-defined variables are session specific, which means a user variable defined by one client cannot be seen or used by other clients.You can use the SET statement to set a user variable:SET @var_name = expr [, @var_name = expr] ... orSET @var_name := expr For SET, you can use = or := as the assignment operator.For example:mysql> SET @a1=1, @a2=2, @a3:=4; mysql> SELECT @a1, @a2, @t3, @a4 := @a1+@a2+@a3; +------+------+------+--------------------+ | @a1 | @a2 | @a3 | @a4 := @a1+@a2+@a3 | +------+------+------+--------------------+ | 1 | 2 | 4 | 7 | +------+------+------+--------------------+ Hexadecimal or bit values assigned to user variables are treated as binary strings in TiDB. To assign a hexadecimal or bit value as a number, use it in numeric context. For example, add 0 or use CAST(... AS UNSIGNED):mysql> SELECT @v1, @v2, @v3; +------+------+------+ | @v1 | @v2 | @v3 | +------+------+------+ | A | 65 | 65 | +------+------+------+ 1 row in set (0.00 sec) mysql> SET @v1 = b'1000001'; Query OK, 0 rows affected (0.00 sec) mysql> SET @v2 = b'1000001'+0; Query OK, 0 rows affected (0.00 sec) mysql> SET @v3 = CAST(b'1000001' AS UNSIGNED); Query OK, 0 rows affected (0.00 sec) mysql> SELECT @v1, @v2, @v3; +------+------+------+ | @v1 | @v2 | @v3 | +------+------+------+ | A | 65 | 65 | +------+------+------+ 1 row in set (0.00 sec) If you refer to a user-defined variable that has not been initialized, it has a value of NULL and a type of string.mysql> select @not_exist; +------------+ | @not_exist | +------------+ | NULL | +------------+ 1 row in set (0.00 sec) The user-defined variables cannot be used as an identifier in the SQL statement. For example:mysql> select * from t; +------+ | a | +------+ | 1 | +------+ 1 row in set (0.00 sec) mysql> SET @col = "a"; Query OK, 0 rows affected (0.00 sec) mysql> SELECT @col FROM t; +------+ | @col | +------+ | a | +------+ 1 row in set (0.00 sec) mysql> SELECT `@col` FROM t; ERROR 1054 (42S22): Unknown column '@col' in 'field list' mysql> SET @col = "`a`"; Query OK, 0 rows affected (0.00 sec) mysql> SELECT @col FROM t; +------+ | @col | +------+ | `a` | +------+ 1 row in set (0.01 sec) An exception is that when you are constructing a string for use as a prepared statement to execute later:mysql> PREPARE stmt FROM "SELECT @c FROM t"; Query OK, 0 rows affected (0.00 sec) mysql> EXECUTE stmt; +------+ | @c | +------+ | a | +------+ 1 row in set (0.01 sec) mysql> DEALLOCATE PREPARE stmt; Query OK, 0 rows affected (0.00 sec) For more information, see User-Defined Variables in MySQL."}, {"url": "https://pingcap.com/docs/sql/util/", "title": "Utility Statements", "content": " Utility Statements This document describes the utility statements, including the DESCRIBE, EXPLAIN, and USE statements.DESCRIBE statement The DESCRIBE and EXPLAIN statements are synonyms, which can also be abbreviated as DESC. See the usage of the EXPLAIN statement.EXPLAIN statement {EXPLAIN | DESCRIBE | DESC} tbl_name [col_name] {EXPLAIN | DESCRIBE | DESC} [explain_type] explainable_stmt explain_type: FORMAT = format_name format_name: "DOT" explainable_stmt: { SELECT statement | DELETE statement | INSERT statement | REPLACE statement | UPDATE statement } For more information about the EXPLAIN statement, see Understand the Query Execution Plan.In addition to the MySQL standard result format, TiDB also supports DotGraph and you need to specify FORMAT = "dot" as in the following example:create table t(a bigint, b bigint); desc format = "dot" select A.a, B.b from t A join t B on A.a > B.b where A.a < 10; TiDB > desc format = "dot" select A.a, B.b from t A join t B on A.a > B.b where A.a < 10;desc format = "dot" select A.a, B.b from t A join t B on A.a > B.b where A.a < 10; +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | dot contents | +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | digraph HashRightJoin_7 { subgraph cluster7{ node [style=filled, color=lightgrey] color=black label = "root" "HashRightJoin_7" -> "TableReader_10" "HashRightJoin_7" -> "TableReader_12" } subgraph cluster9{ node [style=filled, color=lightgrey] color=black label = "cop" "Selection_9" -> "TableScan_8" } subgraph cluster11{ node [style=filled, color=lightgrey] color=black label = "cop" "TableScan_11" } "TableReader_10" -> "Selection_9" "TableReader_12" -> "TableScan_11" } | +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 1 row in set (0.00 sec) If the dot program (in the graphviz package) is installed on your computer, you can generate a PNG file using the following method:dot xx.dot -T png -O The xx.dot is the result returned by the above statement. If the dot program is not installed on your computer, copy the result to this website to get a tree diagram:USE statement USE db_name The USE statement is used to switch the default database. If the table in SQL statements does not display the specified database, then use the default database."}, {"url": "https://pingcap.com/docs/v1.0/sql/util/", "title": "Utility Statements", "content": " Utility Statements DESCRIBE statement The DESCRIBE and EXPLAIN statements are synonyms, which can also be abbreviated as DESC. See the usage of the EXPLAIN statement.EXPLAIN statement {EXPLAIN | DESCRIBE | DESC} tbl_name [col_name] {EXPLAIN | DESCRIBE | DESC} [explain_type] explainable_stmt explain_type: FORMAT = format_name format_name: "DOT" explainable_stmt: { SELECT statement | DELETE statement | INSERT statement | REPLACE statement | UPDATE statement } For more information about the EXPLAIN statement, see Understand the Query Execution Plan.In addition to the MySQL standard result format, TiDB also supports DotGraph and you need to specify FORMAT = "dot" as in the following example:create table t(a bigint, b bigint); desc format = "dot" select A.a, B.b from t A join t B on A.a > B.b where A.a < 10; TiDB > desc format = "dot" select A.a, B.b from t A join t B on A.a > B.b where A.a < 10;desc format = "dot" select A.a, B.b from t A join t B on A.a > B.b where A.a < 10; +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | dot contents | +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | digraph HashRightJoin_7 { subgraph cluster7{ node [style=filled, color=lightgrey] color=black label = "root" "HashRightJoin_7" -> "TableReader_10" "HashRightJoin_7" -> "TableReader_12" } subgraph cluster9{ node [style=filled, color=lightgrey] color=black label = "cop" "Selection_9" -> "TableScan_8" } subgraph cluster11{ node [style=filled, color=lightgrey] color=black label = "cop" "TableScan_11" } "TableReader_10" -> "Selection_9" "TableReader_12" -> "TableScan_11" } | +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 1 row in set (0.00 sec) If the dot program (in the graphviz package) is installed on your computer, you can generate a PNG file using the following method:dot xx.dot -T png -O The xx.dot is the result returned by the above statement. If the dot program is not installed on your computer, copy the result to this website to get a tree diagram:USE statement USE db_name The USE statement is used to switch the default database. If the table in SQL statements does not display the specified database, then use the default database."}, {"url": "https://pingcap.com/docs/v2.0/sql/util/", "title": "Utility Statements", "content": " Utility Statements This document describes the utility statements, including the DESCRIBE, EXPLAIN, and USE statements.DESCRIBE statement The DESCRIBE and EXPLAIN statements are synonyms, which can also be abbreviated as DESC. See the usage of the EXPLAIN statement.EXPLAIN statement {EXPLAIN | DESCRIBE | DESC} tbl_name [col_name] {EXPLAIN | DESCRIBE | DESC} [explain_type] explainable_stmt explain_type: FORMAT = format_name format_name: "DOT" explainable_stmt: { SELECT statement | DELETE statement | INSERT statement | REPLACE statement | UPDATE statement } For more information about the EXPLAIN statement, see Understand the Query Execution Plan.In addition to the MySQL standard result format, TiDB also supports DotGraph and you need to specify FORMAT = "dot" as in the following example:create table t(a bigint, b bigint); desc format = "dot" select A.a, B.b from t A join t B on A.a > B.b where A.a < 10; TiDB > desc format = "dot" select A.a, B.b from t A join t B on A.a > B.b where A.a < 10;desc format = "dot" select A.a, B.b from t A join t B on A.a > B.b where A.a < 10; +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | dot contents | +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | digraph HashRightJoin_7 { subgraph cluster7{ node [style=filled, color=lightgrey] color=black label = "root" "HashRightJoin_7" -> "TableReader_10" "HashRightJoin_7" -> "TableReader_12" } subgraph cluster9{ node [style=filled, color=lightgrey] color=black label = "cop" "Selection_9" -> "TableScan_8" } subgraph cluster11{ node [style=filled, color=lightgrey] color=black label = "cop" "TableScan_11" } "TableReader_10" -> "Selection_9" "TableReader_12" -> "TableScan_11" } | +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 1 row in set (0.00 sec) If the dot program (in the graphviz package) is installed on your computer, you can generate a PNG file using the following method:dot xx.dot -T png -O The xx.dot is the result returned by the above statement. If the dot program is not installed on your computer, copy the result to this website to get a tree diagram:USE statement USE db_name The USE statement is used to switch the default database. If the table in SQL statements does not display the specified database, then use the default database."}, {"url": "https://pingcap.com/tidb-planet/village/", "title": "Village", "content": ""}, {"url": "https://pingcap.com/weekly/", "title": "Weeklies", "content": ""}, {"url": "https://pingcap.com/tidb-planet/", "title": "Welcome", "content": ""}, {"url": "https://pingcap.com/tidb-academy/mysql_dbas/conclusion/whats-next/", "title": "What's Next?", "content": " What’s Next? Resources Course Survey TiDB on GKE Marketplace (Coming Soon) Official TiDB Certification Exam Sign Up Form Private TiDB Training Transcript You’ve now completed TiDB Academy’s “TiDB for MySQL DBAs” course. You might be wondering, what’s next?First things first, we’d love to get your feedback on your experience with this course. Please take this 2-minute survey and you’ll enter a raffle automatically for a $40 Amazon gift card. The link is in the resources section.Next, you are now more than equipped to run TiDB in a production environment, try it on Google’s Kubernetes Engine (GKE) Marketplace. You can deploy TiDB in production with just a few clicks to handle real workloads, and our support team is ready to help you.Third, you can certify your newly acquired TiDB skills by taking the official TiDB certification exam. Check the resources section for more details.Finally, if you enjoyed this course and would like to book a private, in-person instructor-led course with me and other database experts at PingCAP, please fill out the form in the sources section and our team will follow up to get a session organized.Alright, class is complete. Congratulations, you’ve made it to the end :).Hope to see you again soon! And if you have any questions, you can always email us at academy@pingcap.com."}, {"url": "https://pingcap.com/tidb-academy/mysql_dbas/_google_shell_tutorials/template/", "title": "XXXX", "content": " XXXXX Introduction Using your previously deployed Kubernetes Cluster, we will complete the following steps: XXX XXXX Restore from backup Recheck Configuration You should already have a .bashrc file configuring your defaults. Create a tunnel to TiDB:establish-port-forward If you see -bash: establish-port-forward: command not found, reload the setup tutorial and make sure your environment is configured correctly.XXX "}, {"url": "https://pingcap.com/docs/tools/mydumper/", "title": "mydumper Instructions", "content": " mydumper Instructions What is mydumper? mydumper is a fork of the mydumper project with additional functionality specific to TiDB. It is the recommended method to use for logical backups of TiDB.Download the Binary.What enhancements does this contain over regular mydumper? Uses tidb_snapshot to provide backup consistency instead of FLUSH TABLES WITH READ LOCK Allows tidb_snapshot to be configurable (i.e. backup data as it appeared at an earlier point in time) New parameter description -z, --tidb-snapshot: Set the tidb_snapshot to be used for the backup. Default: The current TSO (UniqueID from SHOW MASTER STATUS). Accepts either a TSO or valid datetime. For example: -z "2016-10-08 16:45:26" Usage example Command line parameter:./bin/mydumper -h 127.0.0.1 -u root -P 4000 FAQ Is the source code for these changes available? Source code for PingCAP’s mydumper is available on GitHub.Do you plan to make these changes available to upstream mydumper? Yes, we intend to make our changes available to upstream mydumper. See PR #155."}, {"url": "https://pingcap.com/docs-cn/tools/mydumper/", "title": "mydumper 使用文档", "content": " mydumper 使用文档 mydumper 简介 mydumper 是 mydumper 的 fork 项目,并添加了一些针对 TiDB 的功能。推荐使用此工具对 TiDB 进行逻辑备份。下载 Binary。相比于普通的 mydumper,此工具有哪些改进之处? 使用 tidb_snapshot 而非 FLUSH TABLES WITH READ LOCK 提供备份一致性 允许设置 tidb_snapshot 的值(即可备份不同时间点的数据) 新添参数 -z, --tidb-snapshot: 设置 tidb_snapshot 用于备份 默认值:当前 TSO(SHOW MASTER STATUS 输出的 UniqueID) 此参数可设为 TSO 时间或有效的 datetime 时间。例如:-z "2016-10-08 16:45:26" 使用举例 命令行参数:./bin/mydumper -h 127.0.0.1 -u root -P 4000 FAQ PingCAP 的 mydumper 的源码是否可获取? PingCAP 的 mydumper 源码 位于 GitHub。未来是否计划让 PingCAP 对 mydumper 的改动合并到上游? 是的,PingCAP 团队计划将对 mydumper 的改动合并到上游。参见 PR #155。"}, {"url": "https://pingcap.com/docs/tools/sync-diff-inspector/", "title": "sync-diff-inspector User Guide", "content": " sync-diff-inspector User Guide sync-diff-inspector is a tool used to compare the data that is stored in databases with the MySQL protocol. For example, it can compare the data in MySQL with that in TiDB, the data in MySQL with that in MySQL, or the data in TiDB with that in TiDB. In addition, you can also use this tool to repair data in the scenario where a small amount of data is inconsistent.This guide introduces the key features of sync-diff-inspector and describes how to configure and use this tool. You can download it at sync-diff-inspector-linux-amd64.tar.gz. Notes: TiDB uses the utf8_bin collation. If you need to compare the data in MySQL with that in TiDB, pay attention to the collation configuration of MySQL tables. If the primary key or unique key is the varchar type and the collation configuration in MySQL differs from that in TiDB, then the final check result might be incorrect because of the collation issue. You need to add collation to the sync-diff-inspector configuration file. Key features Compare the table schema and data Generate the SQL statements used to repair data if the data inconsistency exists Support comparing the data of multiple tables with the data of a single table (for the scenario of synchronizing data from sharded tables into the combined table) Support comparing the data of different schemas or tables with different names Description of common configuration # Diff configuration # The log level. You can set it to "info" or "debug". log-level = "info" # sync-diff-inspector divides the data into multiple chunks based on the primary key, # unique key, or the index, and then compares the data of each chunk. # Use "chunk-size" to set the size of a chunk. chunk-size = 1000 # The number of goroutines created to check data check-thread-count = 4 # The proportion of sampling check. If you set it to 100, all the data is checked. sample-percent = 100 # If enabled, the chunk's checksum is calculated and data is compared by checksum. # If disabled, data is compared line by line. use-checksum = true # If set to true, data check is ignored. If set false, data is checked. ignore-data-check = false # If set to true, the table struct comparison is ignored. # If set to false, the table struct is compared. ignore-struct-check = false # The name of the file which saves the SQL statements used to repair data fix-sql-file = "fix.sql" # Configure the tables of the target databases that need to be checked. [[check-tables]] # The name of the schema in the target database schema = "test" # The list of tables that need to be checked in the target database tables = ["test1", "test2", "test3"] # Supports using regular expressions to configure tables to be checked # You need to start with '~'. For example, the following configuration checks # all the tables with the prefix 'test' in the table name. # tables = ["~^test.*"] # The following configuration checks all the tables in the database. # tables = ["~^"] # Special configuration for some tables # The configured table must be included in "check-tables'. [[table-config]] # The name of the schema in the target database schema = "test" # The table name table = "test3" # Specifies the column used to divide data into chunks. If you do not configure it, # sync-diff-inspector chooses an appropriate column (primary key, unique key, or a field with index). index-field = "id" # Specifies the range of the data to be checked # It needs to comply with the syntax of the WHERE clause in SQL. range = "age > 10 AND age < 20" # Set it to "true" when comparing the data of multiple sharded tables # with the data of the combined table. is-sharding = false # The collation of the string type of data might be inconsistent in some conditions. # You can specify "collation" to guarantee the order consistency. # You need to keep it corresponding to the "charset" setting in the database. # collation = "latin1_bin" # Ignores checking some columns. But these columns can still be used to # divide chunks and sort the checked data. # ignore-columns = ["name"] # Removes some columns. During checking, these columns are removed from the table struct. # These columns are neither checked nor used to divide chunks or sort data. # remove-columns = ["name"] # Configuration example of comparing two tables with different database names and table names. [[table-config]] # The name of the target schema schema = "test" # The name of the target table table = "test2" # Set it to "false" in non-sharding scenarios. is-sharding = false # Configuration of the source data [[table-config.source-tables]] # The instance ID of the source schema instance-id = "source-1" # The name of the source schema schema = "test" # The name of the source table table = "test1" # Configuration of the instance in the source database [[source-db]] host = "127.0.0.1" port = 3306 user = "root" password = "" # The ID of the instance in the source database, the unique identifier of a database instance instance-id = "source-1" # Use the snapshot function of TiDB. # If enabled, the history data is used for comparison. # snapshot = "2016-10-08 16:45:26" # Configuration of the instance in the target database [target-db] host = "127.0.0.1" port = 4000 user = "root" password = "" # Use the snapshot function of TiDB. # If enabled, the history data is used for comparison. # snapshot = "2016-10-08 16:45:26" Configuration of data comparison in the sharding scenario Assuming that you have two MySQL instances, use a synchronization tool to synchronize the data into TiDB as shown below:If you need to check the data consistency after synchronization, you can use the following configuration to compare data:# Diff Configuration # Configure the tables in the target databases to be compared. [[check-tables]] # The name of the schema schema = "test" # The list of tables which need check in the target database # In the sharding mode, you must set config for each table in "table-config", otherwise the table is not checked. # The name of the table to be checked tables = ["test"] # Configure the sharded tables corresponding to this table. [[table-config]] # The name of the target schema schema = "test" # The name of the table in the target schema table = "test" # Set it to "true" in the sharding scenario. is-sharding = true # Configuration of the source tables [[table-config.source-tables]] # The ID of the instance in the source database instance-id = "source-1" schema = "test" table = "test1" [[table-config.source-tables]] # The ID of the instance in the source database instance-id = "source-1" schema = "test" table = "test2" [[table-config.source-tables]] # The ID of the instance in the source database instance-id = "source-2" schema = "test" table = "test3" # Configuration of the instance in the source database [[source-db]] host = "127.0.0.1" port = 3306 user = "root" password = "" instance-id = "source-1" # Configuration of the instance in the source database [[source-db]] host = "127.0.0.2" port = 3306 user = "root" password = "" instance-id = "source-2" # Configuration of the instance in the source database [target-db] host = "127.0.0.3" port = 4000 user = "root" password = "" Run sync-diff-inspector Run the following command:./bin/sync_diff_inspector --config=./config.toml The above command outputs a check report to the log and describes the check result of each table. If data inconsistency exists, the SQL statements used to fix inconsistency are stored to the …"}, {"url": "https://pingcap.com/docs-cn/tools/sync-diff-inspector/", "title": "sync-diff-inspector 用户文档", "content": " sync-diff-inspector 用户文档 sync-diff-inspector 简介 sync-diff-inspector 是一个用于校验 MySQL/TiDB 中两份数据是否一致的工具,该工具提供了修复数据的功能(适用于修复少量不一致的数据)。主要功能: 对比表结构和数据 如果数据不一致,则生成用于修复数据的 SQL 支持多个表的数据与单个表数据的比较(针对分库分表同步数据到总表的场景) 支持不同库名/表名的数据的比较 GitHub 地址:sync-diff-inspector下载地址:sync-diff-inspector-linux-amd64.tar.gzsync-diff-inspector 的使用 通用配置文件说明 # diff Configuration. # 日志级别,可以设置为 info、debug log-level = "info" # sync-diff-inspector 根据主键/唯一键/索引将数据划分为多个 chunk, # 对每一个 chunk 的数据进行对比。使用 chunk-size 设置 chunk 的大小 chunk-size = 1000 # 检查数据的线程数量 check-thread-count = 4 # 抽样检查的比例,如果设置为 100 则检查全部数据 sample-percent = 100 # 通过计算 chunk 的 checksum 来对比数据,如果不开启则逐行对比数据 use-checksum = true # 不对比数据 ignore-data-check = false # 不对比表结构 ignore-struct-check = false # 保存用于修复数据的 sql 的文件名称 fix-sql-file = "fix.sql" # 配置需要对比的目标数据库中的表 [[check-tables]] # 目标库中数据库的名称 schema = "test" # 需要检查的表 tables = ["test1", "test2", "test3"] # 支持使用正则表达式配置检查的表,需要以‘~’开始, # 下面的配置会检查所有表名以‘test’为前缀的表 # tables = ["~^test.*"] # 下面的配置会检查配置库中所有的表 # tables = ["~^"] # 对部分表进行特殊的配置,配置的表必须包含在 check-tables 中 [[table-config]] # 目标库中数据库的名称 schema = "test" # 表名 table = "test3" # 指定用于划分 chunk 的列,如果不配置该项,sync-diff-inspector 会选取一个合适的列(主键/唯一键/索引) index-field = "id" # 指定检查的数据的范围,需要符合 sql 中 where 条件的语法 range = "age > 10 AND age < 20" # 如果是对比多个分表与总表的数据,则设置为 true is-sharding = false # 在某些情况下字符类型的数据的排序会不一致,通过指定 collation 来保证排序的一致, # 需要与数据库中 charset 的设置相对应 # collation = "latin1_bin" # 忽略某些列的检查,但是这些列仍然可以用于划分 chunk、对检查的数据进行排序 # ignore-columns = ["name"] # 移除某些列,检查时会将这些列从表结构中移除,既不会检查这些列的数据, # 也不会用这些列做 chunk 的划分,或者用于对数据进行排序 # remove-columns = ["name"] # 下面是一个对比不同库名和表名的两个表的配置示例 [[table-config]] # 目标库名 schema = "test" # 目标表名 table = "test2" # 非分库分表场景,设置为 false is-sharding = false # 源数据的配置 [[table-config.source-tables]] # 源库的实例 id instance-id = "source-1" # 源数据库的名称 schema = "test" # 源表的名称 table = "test1" # 源数据库实例的配置 [[source-db]] host = "127.0.0.1" port = 3306 user = "root" password = "" # 源数据库实例的 id,唯一标识一个数据库实例 instance-id = "source-1" # 使用 TiDB 的 snapshot 功能,如果开启的话会使用历史数据进行对比 # snapshot = "2016-10-08 16:45:26" # 目标数据库实例的配置 [target-db] host = "127.0.0.1" port = 4000 user = "root" password = "" # 使用 TiDB 的 snapshot 功能,如果开启的话会使用历史数据进行对比 # snapshot = "2016-10-08 16:45:26" 分库分表场景下数据对比的配置示例 假设有两个 MySQL 实例,使用同步工具同步到一个 TiDB 中,场景如图所示:如果需要检查同步后数据是否一致,可以使用如下的配置对比数据:# diff Configuration. # 配置需要对比的目标数据库中的表 [[check-tables]] # 库的名称 schema = "test" # table list which need check in target database. # in sharding mode, you must set config for every table in table-config, otherwise will not check the table. # 需要检查的表的名称 tables = ["test"] # 配置该表对应的分表的相关配置 [[table-config]] # 目标库的名称 schema = "test" # 目标库中表的名称 table = "test" # 为分库分表场景下数据的对比,设置为 true is-sharding = true # 源数据表的配置 [[table-config.source-tables]] # 源数据库实例的 id instance-id = "source-1" schema = "test" table = "test1" [[table-config.source-tables]] # 源数据库实例的 id instance-id = "source-1" schema = "test" table = "test2" [[table-config.source-tables]] # 源数据库实例的 id instance-id = "source-2" schema = "test" table = "test3" # 源数据库实例的配置 [[source-db]] host = "127.0.0.1" port = 3306 user = "root" password = "" instance-id = "source-1" # 源数据库实例的配置 [[source-db]] host = "127.0.0.2" port = 3306 user = "root" password = "" instance-id = "source-2" # 目标数据库实例的配置 [target-db] host = "127.0.0.3" port = 4000 user = "root" password = "" 运行 sync-diff-inspector 执行如下命令:./bin/sync_diff_inspector --config=./config.toml 该命令最终会在日志中输出一个检查报告,说明每个表的检查情况。如果数据存在不一致的情况,sync-diff-inspector 会生成 SQL 修复不一致的数据,并将这些 SQL 语句保存到 fix.sql 文件中。注意 TiDB 使用的 collation 为 utf8_bin,如果对 MySQL 和 TiDB 的数据进行对比,需要注意 MySQL 中表的 collation 设置。如果表的主键/唯一键为 varchar 类型,且 MySQL 中 collation 设置与 TiDB 不同,可能会因为排序问题导致最终校验结果不正确,需要在 sync-diff-inspector 的配置文件中增加 collation 设置。"}, {"url": "https://pingcap.com/docs-cn/sql/mysql-compatibility/", "title": "与 MySQL 兼容性对比", "content": " 与 MySQL 兼容性对比 TiDB 支持包括跨行事务、JOIN 及子查询在内的绝大多数 MySQL 5.7 的语法,用户可以直接使用现有的 MySQL 客户端连接。如果现有的业务已经基于 MySQL 开发,大多数情况不需要修改代码即可直接替换单机的 MySQL。包括现有的大多数 MySQL 运维工具(如 PHPMyAdmin, Navicat, MySQL Workbench 等),以及备份恢复工具(如 mysqldump, mydumper/myloader)等都可以直接使用。不过一些特性由于在分布式环境下没法很好的实现,目前暂时不支持或者是表现与 MySQL 有差异。一些 MySQL 语法在 TiDB 中可以解析通过,但是不会做任何后续的处理,例如 Create Table 语句中 Engine 以及 Partition 选项,都是解析并忽略。更多兼容性差异请参考具体的文档。不支持的特性 存储过程与函数 视图 触发器 事件 自定义函数 外键约束 全文函数与索引 空间函数与索引 非 utf8 字符集 BINARY 之外的排序规则 增加主键 删除主键 SYS schema MySQL 追踪优化器 XML 函数 X Protocol Savepoints 列级权限 与 MySQL 有差异的特性 自增 ID TiDB 的自增 ID (Auto Increment ID) 只保证自增且唯一,并不保证连续分配。TiDB 目前采用批量分配的方式,所以如果在多台 TiDB 上同时插入数据,分配的自增 ID 会不连续。在集群中有多个 tidb-server 实例时,如果表结构中有自增 ID,建议不要混用缺省值和自定义值,否则在如下情况下会遇到问题。假设有这样一个带有自增 ID 的表:create table t(id int unique key auto_increment, c int); TiDB 实现自增 ID 的原理是每个 tidb-server 实例缓存一段 ID 值用于分配(目前会缓存 30000 个 ID),用完这段值再去取下一段。假设集群中有两个 tidb-server 实例 A 和 B(A 缓存 [1,30000] 的自增 ID,B 缓存 [30001,60000] 的自增 ID),依次执行如下操作: 客户端向 B 插入一条将 id 设置为 1 的语句 insert into t values (1, 1),并执行成功。 客户端向 A 发送 Insert 语句 insert into t (c) (1),这条语句中没有指定 id 的值,所以会由 A 分配,当前 A 缓存了 [1, 30000] 这段 ID,所以会分配 1 为自增 ID 的值,并把本地计数器加 1。而此时数据库中已经存在 id 为 1 的数据,最终返回 Duplicated Error 错误。 Performance schema Performance schema 表在 TiDB 中返回结果为空。TiDB 使用 Prometheus 和 Grafana 来监测性能指标。内建函数 TiDB 支持常用的 MySQL 内建函数,但是不是所有的函数都已经支持,具体请参考语法文档。DDL TiDB 实现了 F1 的异步 Schema 变更算法,DDL 执行过程中不会阻塞线上的 DML 操作。目前已经支持的 DDL 包括: Create Database Drop Database Create Table Drop Table Add Index Drop Index Add Column Drop Column Alter Column Change Column Modify Column Truncate Table Rename Table Create Table Like 以上语句还有一些支持不完善的地方,具体包括如下: Add/Drop primary key 操作目前不支持。 Add Index/Column 操作不支持同时创建多个索引或列。 Drop Column 操作不支持删除的列为主键列或索引列。 Add Column 操作不支持同时将新添加的列设为主键或唯一索引,也不支持将此列设成 auto_increment 属性。 Change/Modify Column 操作目前支持部分语法,细节如下: 在修改类型方面,只支持整数类型之间修改,字符串类型之间修改和 Blob 类型之间的修改,且只能使原类型长度变长。此外,不能改变列的 unsigned/charset/collate 属性。这里的类型分类如下: 具体支持的整型类型有:TinyInt,SmallInt,MediumInt,Int,BigInt。 具体支持的字符串类型有:Char,Varchar,Text,TinyText,MediumText,LongText。 具体支持的 Blob 类型有:Blob,TinyBlob,MediumBlob,LongBlob。 在修改类型定义方面,支持的包括 default value,comment,null,not null 和 OnUpdate。 支持 LOCK [=] {DEFAULT|NONE|SHARED|EXCLUSIVE} 语法,但是不做任何事情(pass through)。 不支持对enum类型的列进行修改 事务模型 TiDB 使用乐观事务模型,在执行 Update、Insert、Delete 等语句时,只有在提交过程中才会检查写写冲突,而不是像 MySQL 一样使用行锁来避免写写冲突。类似的,诸如 GET_LOCK() 和 RELEASE_LOCK() 等函数以及 SELECT .. FOR UPDATE 之类的语句在 TiDB 和 MySQL 中的执行方式并不相同。所以业务端在执行 SQL 语句后,需要注意检查 commit 的返回值,即使执行时没有出错,commit 的时候也可能会出错。大事务 由于 TiDB 分布式两阶段提交的要求,修改数据的大事务可能会出现一些问题。因此,TiDB 特意对事务大小设置了一些限制以减少这种影响: 每个键值对不超过 6MB 键值对的总数不超过 300,000 键值对的总大小不超过 100MB 小事务 由于 TiDB 中的每个事务都需要跟 PD leader 进行两次 round trip,TiDB 中的小事务相比于 MySQL 中的小事务延迟更高。以如下的 query 为例,用显示事务代替 auto_commit,可优化该 query 的性能。# 使用 auto_commit 的原始版本 UPDATE my_table SET a='new_value' WHERE id = 1; UPDATE my_table SET a='newer_value' WHERE id = 2; UPDATE my_table SET a='newest_value' WHERE id = 3; # 优化后的版本 START TRANSACTION; UPDATE my_table SET a='new_value' WHERE id = 1; UPDATE my_table SET a='newer_value' WHERE id = 2; UPDATE my_table SET a='newest_value' WHERE id = 3; COMMIT; 单线程的 workload 由于 TiDB 中的 workload 是分布式的,TiDB 中单线程的 workload 性能相比于单实例部署的 MySQL 较低。这与 TiDB 中的小事务延迟较高的情況类似。Load data 语法:LOAD DATA LOCAL INFILE 'file_name' INTO TABLE table_name {FIELDS | COLUMNS} TERMINATED BY 'string' ENCLOSED BY 'char' ESCAPED BY 'char' LINES STARTING BY 'string' TERMINATED BY 'string' IGNORE n LINES (col_name ...); 其中 ESCAPED BY 目前只支持 ‘//‘。 事务的处理:TiDB 在执行 load data 时,默认每 2 万行记录作为一个事务进行持久化存储。如果一次 load data 操作插入的数据超过 2 万行,那么会分为多个事务进行提交。如果某个事务出错,这个事务会提交失败,但它前面的事务仍然会提交成功,在这种情况下一次 load data 操作会有部分数据插入成功,部分数据插入失败。而 MySQL 中会将一次 load data 操作视为一个事务,如果其中发生失败情况,将会导致整个 load data 操作失败。 存储引擎 出于兼容性原因,TiDB 支持使用备用存储引擎创建表的语法。元数据命令将表描述为 InnoDB 存储引擎:mysql> CREATE TABLE t1 (a INT) ENGINE=MyISAM; Query OK, 0 rows affected (0.14 sec) mysql> SHOW CREATE TABLE t1G *************************** 1. row *************************** Table: t1 Create Table: CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin 1 row in set (0.00 sec) 从架构上讲,TiDB 确实支持类似 MySQL 的存储引擎抽象,在启动 TiDB(通常是 tikv)时 --store 选项指定的引擎中创建用户表。SQL 模式 TiDB 支持 MySQL 5.7 中 绝大多数的 SQL 模式,以下几种模式除外: TiDB 暂不支持 ALLOW_INVALID_DATES 模式。详情参见 TiDB #8263。 TiDB 不支持兼容模式(例如 ORACLE 和 POSTGRESQL)。MySQL 5.7 已弃用兼容模式,MySQL 8.0 已移除兼容模式。 TiDB 中的 ONLY_FULL_GROUP_BY 与 MySQL 5.7 相比有细微的 语义差别,此问题日后将予以解决。 NO_DIR_IN_CREATE 和 NO_ENGINE_SUBSTITUTION 这两种 SQL 模式用于解决兼容问题,但并不适用于 TiDB。 EXPLAIN TiDB 的 EXPLAIN 命令返回的查询执行计划的输出与 MySQL 不同。更多内容参见 理解 TiDB 执行计划。默认设置的区别 默认字符集不同: TiDB 中为 utf8,相当于 MySQL 的 utf8mb4 MySQL 5.7 中为 latin1,但在 MySQL 8.0 中修改为 utf8mb4 默认排序规则不同: MySQL 5.7 中使用 latin1_swedish_ci TiDB 使用 binary 默认 SQL mode 不同: TiDB 中为 STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION MySQL 中为 ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION lower_case_table_names 的默认值不同: TiDB 中该值默认为 2,并且目前 TiDB 只支持设置该值为 2 MySQL 中默认设置: Linux 系统中该值为 0 Windows 系统中该值为 1 macOS 系统中该值为 2 "}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/mysql-compatibility/", "title": "与 MySQL 兼容性对比", "content": " 与 MySQL 兼容性对比 TiDB 支持包括跨行事务,JOIN 及子查询在内的绝大多数 MySQL 的语法,用户可以直接使用现有的 MySQL 客户端连接。如果现有的业务已经基于 MySQL 开发,大多数情况不需要修改代码即可直接替换单机的 MySQL。包括现有的大多数 MySQL 运维工具(如 PHPMyAdmin, Navicat, MySQL Workbench 等),以及备份恢复工具(如 mysqldump, mydumper/myloader)等都可以直接使用。不过一些特性由于在分布式环境下没法很好的实现,目前暂时不支持或者是表现与 MySQL 有差异。一些 MySQL 语法在 TiDB 中可以解析通过,但是不会做任何后续的处理,例如 Create Table 语句中 Engine 以及 Partition 选项,都是解析并忽略。更多兼容性差异请参考具体的文档。不支持的特性 存储过程 视图 触发器 自定义函数 外键约束 全文索引 空间索引 非 UTF8 字符集 与 MySQL 有差异的特性 自增 ID TiDB 的自增 ID (Auto Increment ID) 只保证自增且唯一,并不保证连续分配。TiDB 目前采用批量分配的方式,所以如果在多台 TiDB 上同时插入数据,分配的自增 ID 会不连续。 注意:在有多台 TiDB 使用自增 ID 时,建议不要混用缺省值和自定义值。因为目前在如下情况下会报错:在有两个 TiDB(TiDB A 缓存 [1,5000] 的自增 ID,TiDB B 缓存 [5001,10000] 的自增 ID)的集群,使用如下 SQL 语句创建一个带有自增 ID 的表:create table t(id int unique key auto_increment, c int); 该语句执行如下: 客户端向 TiDB B 插入一条将 id 设置为 1 的语句,并执行成功。 客户端向 TiDB A 发送插入一条记录,且记录中 id 使用缺省值即 1,最终返回 Duplicated Error。 该问题近期会解决。 内建函数 TiDB 支持常用的 MySQL 内建函数,但是不是所有的函数都已经支持,具体请参考语法文档。DDL TiDB 实现了 F1 的异步 Schema 变更算法,DDL 执行过程中不会阻塞线上的 DML 操作。目前已经支持的 DDL 包括: Create Database Drop Database Create Table Drop Table Add Index Drop Index Add Column Drop Column Alter Column Change Column Modify Column Truncate Table Rename Table Create Table Like 以上语句还有一些支持不完善的地方,具体包括如下: Add/Drop primary key 操作目前不支持。 Add Index/Column 操作不支持同时创建多个索引或列。 Drop Column 操作不支持删除的列为主键列或索引列。 Add Column 操作不支持同时将新添加的列设为主键或唯一索引,也不支持将此列设成 auto_increment 属性。 Change/Modify Column 操作目前支持部分语法,细节如下: 在修改类型方面,只支持整数类型之间修改,字符串类型之间修改和 Blob 类型之间的修改,且只能使原类型长度变长。此外,不能改变列的 unsigned/charset/collate 属性。这里的类型分类如下: 具体支持的整型类型有:TinyInt,SmallInt,MediumInt,Int,BigInt。 具体支持的字符串类型有:Char,Varchar,Text,TinyText,MediumText,LongText。 具体支持的 Blob 类型有:Blob,TinyBlob,MediumBlob,LongBlob。 在修改类型定义方面,支持的包括 default value,comment,null,not null 和 OnUpdate,但是不支持从 null 到 not null 的修改。 支持 LOCK [=] {DEFAULT|NONE|SHARED|EXCLUSIVE} 语法,但是不做任何事情(pass through)。 不支持对enum类型的列进行修改 事务 TiDB 使用乐观事务模型,在执行 Update、Insert、Delete 等语句时,只有在提交过程中才会检查写写冲突,而不是像 MySQL 一样使用行锁来避免写写冲突。所以业务端在执行 SQL 语句后,需要注意检查 commit 的返回值,即使执行时没有出错,commit的时候也可能会出错。Load data 语法:LOAD DATA LOCAL INFILE 'file_name' INTO TABLE table_name {FIELDS | COLUMNS} TERMINATED BY 'string' ENCLOSED BY 'char' ESCAPED BY 'char' LINES STARTING BY 'string' TERMINATED BY 'string' (col_name ...); 其中 ESCAPED BY 目前只支持 ‘//‘。 事务的处理:TiDB 在执行 load data 时,默认每 2 万行记录作为一个事务进行持久化存储。如果一次 load data 操作插入的数据超过 2 万行,那么会分为多个事务进行提交。如果某个事务出错,这个事务会提交失败,但它前面的事务仍然会提交成功,在这种情况下一次 load data 操作会有部分数据插入成功,部分数据插入失败。而 MySQL 中会将一次 load data 操作视为一个事务,如果其中发生失败情况,将会导致整个 load data 操作失败。 "}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/mysql-compatibility/", "title": "与 MySQL 兼容性对比", "content": " 与 MySQL 兼容性对比 TiDB 支持包括跨行事务,JOIN 及子查询在内的绝大多数 MySQL 的语法,用户可以直接使用现有的 MySQL 客户端连接。如果现有的业务已经基于 MySQL 开发,大多数情况不需要修改代码即可直接替换单机的 MySQL。包括现有的大多数 MySQL 运维工具(如 PHPMyAdmin, Navicat, MySQL Workbench 等),以及备份恢复工具(如 mysqldump, mydumper/myloader)等都可以直接使用。不过一些特性由于在分布式环境下没法很好的实现,目前暂时不支持或者是表现与 MySQL 有差异。一些 MySQL 语法在 TiDB 中可以解析通过,但是不会做任何后续的处理,例如 Create Table 语句中 Engine 以及 Partition 选项,都是解析并忽略。更多兼容性差异请参考具体的文档。不支持的特性 存储过程 视图 触发器 自定义函数 外键约束 全文索引 空间索引 非 UTF8 字符集 与 MySQL 有差异的特性 自增 ID TiDB 的自增 ID (Auto Increment ID) 只保证自增且唯一,并不保证连续分配。TiDB 目前采用批量分配的方式,所以如果在多台 TiDB 上同时插入数据,分配的自增 ID 会不连续。 注意:在有多台 TiDB 使用自增 ID 时,建议不要混用缺省值和自定义值。因为目前在如下情况下会报错:在有两个 TiDB(TiDB A 缓存 [1,5000] 的自增 ID,TiDB B 缓存 [5001,10000] 的自增 ID)的集群,使用如下 SQL 语句创建一个带有自增 ID 的表:create table t(id int unique key auto_increment, c int); 该语句执行如下: 客户端向 TiDB B 插入一条将 id 设置为 1 的语句,并执行成功。 客户端向 TiDB A 发送插入一条记录,且记录中 id 使用缺省值即 1,最终返回 Duplicated Error。 该问题近期会解决。 内建函数 TiDB 支持常用的 MySQL 内建函数,但是不是所有的函数都已经支持,具体请参考语法文档。DDL TiDB 实现了 F1 的异步 Schema 变更算法,DDL 执行过程中不会阻塞线上的 DML 操作。目前已经支持的 DDL 包括: Create Database Drop Database Create Table Drop Table Add Index Drop Index Add Column Drop Column Alter Column Change Column Modify Column Truncate Table Rename Table Create Table Like 以上语句还有一些支持不完善的地方,具体包括如下: Add/Drop primary key 操作目前不支持。 Add Index/Column 操作不支持同时创建多个索引或列。 Drop Column 操作不支持删除的列为主键列或索引列。 Add Column 操作不支持同时将新添加的列设为主键或唯一索引,也不支持将此列设成 auto_increment 属性。 Change/Modify Column 操作目前支持部分语法,细节如下: 在修改类型方面,只支持整数类型之间修改,字符串类型之间修改和 Blob 类型之间的修改,且只能使原类型长度变长。此外,不能改变列的 unsigned/charset/collate 属性。这里的类型分类如下: 具体支持的整型类型有:TinyInt,SmallInt,MediumInt,Int,BigInt。 具体支持的字符串类型有:Char,Varchar,Text,TinyText,MediumText,LongText。 具体支持的 Blob 类型有:Blob,TinyBlob,MediumBlob,LongBlob。 在修改类型定义方面,支持的包括 default value,comment,null,not null 和 OnUpdate,但是不支持从 null 到 not null 的修改。 支持 LOCK [=] {DEFAULT|NONE|SHARED|EXCLUSIVE} 语法,但是不做任何事情(pass through)。 不支持对enum类型的列进行修改 事务 TiDB 使用乐观事务模型,在执行 Update、Insert、Delete 等语句时,只有在提交过程中才会检查写写冲突,而不是像 MySQL 一样使用行锁来避免写写冲突。所以业务端在执行 SQL 语句后,需要注意检查 commit 的返回值,即使执行时没有出错,commit的时候也可能会出错。Load data 语法:LOAD DATA LOCAL INFILE 'file_name' INTO TABLE table_name {FIELDS | COLUMNS} TERMINATED BY 'string' ENCLOSED BY 'char' ESCAPED BY 'char' LINES STARTING BY 'string' TERMINATED BY 'string' (col_name ...); 其中 ESCAPED BY 目前只支持 ‘//‘。 事务的处理:TiDB 在执行 load data 时,默认每 2 万行记录作为一个事务进行持久化存储。如果一次 load data 操作插入的数据超过 2 万行,那么会分为多个事务进行提交。如果某个事务出错,这个事务会提交失败,但它前面的事务仍然会提交成功,在这种情况下一次 load data 操作会有部分数据插入成功,部分数据插入失败。而 MySQL 中会将一次 load data 操作视为一个事务,如果其中发生失败情况,将会导致整个 load data 操作失败。 "}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/transaction/", "title": "事务语句", "content": " TiDB 事务语句 TiDB 支持分布式事务。涉及到事务的语句包括 Autocommit 变量、 START TRANSACTION/BEGIN、 COMMIT 以及 ROLLBACK。自动提交 语法:SET autocommit = {0 | 1} 通过设置 autocommit 的值为 1,可以将当前 Session 设置为自动提交状态,0 则表示当前 Session 为非自动提交状态。默认情况下, autocommit 的值为 1。在自动提交状态,每条语句运行后,会将其修改自动提交到数据库中。否则,会等到运行 COMMIT 语句或者是 BEGIN 语句的时候,才会将之前的修改提交到数据库。另外 autocommit 也是一个 System Variable,所以可以通过变量赋值语句修改当前 Session 或者是 Global 的值。SET @@SESSION.autocommit = {0 | 1}; SET @@GLOBAL.autocommit = {0 | 1}; START TRANSACTION, Begin 语法:BEGIN; START TRANSACTION; START TRANSACTION WITH CONSISTENT SNAPSHOT; 上述三条语句都是事务开始语句,效果相同。通过事务开始语句可以显式地开始一个新的事务,如果这个时候当前 Session 正在一个事务中间过程中,会将当前事务提交后,开启一个新的事务。COMMIT 语法:COMMIT; 提交当前事务,包括从 BEGIN 到 COMMIT 之间的所有修改。ROLLBACK 语法:ROLLBACK; 回滚当前事务,撤销从 BEGIN 到 ROLLBACK 之间的所有修改。显式事务和隐式事务 TiDB 可以显式地使用事务(BEGIN/COMMIT) 或者隐式的使用事务 (SET autocommit = 1)。如果在 autocmmit = 1 的状态下,通过 BEGIN 语句开启一个新的事务,那么在 COMMIT/ROLLBACK 之前,会禁用 autocommit,也就是变成显式事务。对于 DDL 语句,会自动提交并且不能回滚。如果运行 DDL 的时候,正在一个事务的中间过程中,会先将当前的事务提交,再运行 DDL。事务隔离级别 TiDB 默认使用 SNAPSHOT ISOLATION,可以通过下面的语句将当前 Session 的隔离级别设置为 READ COMMITTED。SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;"}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/transaction/", "title": "事务语句", "content": " TiDB 事务语句 TiDB 支持分布式事务。涉及到事务的语句包括 Autocommit 变量、 START TRANSACTION/BEGIN、 COMMIT 以及 ROLLBACK。自动提交 语法:SET autocommit = {0 | 1} 通过设置 autocommit 的值为 1,可以将当前 Session 设置为自动提交状态,0 则表示当前 Session 为非自动提交状态。默认情况下, autocommit 的值为 1。在自动提交状态,每条语句运行后,会将其修改自动提交到数据库中。否则,会等到运行 COMMIT 语句或者是 BEGIN 语句的时候,才会将之前的修改提交到数据库。另外 autocommit 也是一个 System Variable,所以可以通过变量赋值语句修改当前 Session 或者是 Global 的值。SET @@SESSION.autocommit = {0 | 1}; SET @@GLOBAL.autocommit = {0 | 1}; START TRANSACTION, Begin 语法:BEGIN; START TRANSACTION; START TRANSACTION WITH CONSISTENT SNAPSHOT; 上述三条语句都是事务开始语句,效果相同。通过事务开始语句可以显式地开始一个新的事务,如果这个时候当前 Session 正在一个事务中间过程中,会将当前事务提交后,开启一个新的事务。COMMIT 语法:COMMIT; 提交当前事务,包括从 BEGIN 到 COMMIT 之间的所有修改。ROLLBACK 语法:ROLLBACK; 回滚当前事务,撤销从 BEGIN 到 ROLLBACK 之间的所有修改。显式事务和隐式事务 TiDB 可以显式地使用事务(BEGIN/COMMIT) 或者隐式的使用事务 (SET autocommit = 1)。如果在 autocmmit = 1 的状态下,通过 BEGIN 语句开启一个新的事务,那么在 COMMIT/ROLLBACK 之前,会禁用 autocommit,也就是变成显式事务。对于 DDL 语句,会自动提交并且不能回滚。如果运行 DDL 的时候,正在一个事务的中间过程中,会先将当前的事务提交,再运行 DDL。事务隔离级别 TiDB 默认使用 SNAPSHOT ISOLATION,可以通过下面的语句将当前 Session 的隔离级别设置为 READ COMMITTED。SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;"}, {"url": "https://pingcap.com/recruit-cn/campus/hr-intern/", "title": "人力资源实习生", "content": " 人力资源实习生 岗位职责: 协助实施招聘工作,发布招聘广告、进行简历筛选、组织面试,评估候选人并提供初步面试报告,出具综合评价意见; 协助设计优化招聘流程、面试标准、面试题库,组织实施招聘; 总结招聘工作中存在的问题,提出优化招聘制度和流程的合理化建议; 总结和统计招聘工作各项数据,完成招聘分析报告; 配合完成其它人力资源工作。 任职要求: 英语好,善于与人交流和收集信息,有计算机相关知识或互联网公司实习经验的优先; 认真努力学习,吃苦耐劳,Smart,学习能力强; 每周至少实习 3 天,可持续实习 3 个月以上。 待遇:200 元/天,餐补,零食水果,生日会,Team Building联系方式:hire@pingcap.com工作地点:北京"}, {"url": "https://pingcap.com/docs-cn/sql/bit-functions-and-operators/", "title": "位函数和操作符", "content": " 位函数和操作符 TiDB 中位函数和操作符的使用方法与 MySQL 基本一致,详情参见: Bit Functions and Operators。位函数和操作符表 函数和操作符名 功能描述 BIT_COUNT() 返回参数二进制表示中为 1 的个数 & 位与 ~ 按位取反 | 位或 0 位亦或 << 左移 >> 右移 "}, {"url": "https://pingcap.com/docs-cn/op-guide/docker-compose/", "title": "使用 Docker Compose 快速构建集群", "content": " 使用 Docker Compose 快速构建集群 本文档介绍如何在单机上通过 Docker Compose 快速一键部署一套 TiDB 测试集群。Docker Compose 可以通过一个 YAML 文件定义多个容器的应用服务,然后一键启动或停止。 注:对于生产环境,不要使用 Docker Compose 进行部署,而应使用 Ansible 部署 TiDB 集群。 准备环境 确保你的机器上已安装: Docker(17.06.0 及以上版本) Docker Compose Git 快速部署 下载 tidb-docker-composegit clone https://github.com/pingcap/tidb-docker-compose.git 创建并启动集群cd tidb-docker-compose && docker-compose pull # Get the latest Docker images docker-compose up -d 访问集群mysql -h 127.0.0.1 -P 4000 -u root 访问集群 Grafana 监控页面:http://localhost:3000 默认用户名和密码均为 admin。集群数据可视化:http://localhost:8010 自定义集群 在完成快速部署后,以下组件已默认部署:3 个 PD,3 个 TiKV,1 个 TiDB 和监控组件 Prometheus,Pushgateway,Grafana 以及 tidb-vision。如果想自定义集群,可以直接修改 docker-compose.yml,但是手动修改比较繁琐而且容易出错,强烈建议使用 Helm 模板引擎生成 docker-compose.yml 文件。 安装 HelmHelm 可以用作模板渲染引擎,只需要下载其 binary 文件即可以使用。curl https://raw.githubusercontent.com/kubernetes/helm/master/scripts/get | bash 如果是 Mac 系统,也可以通过 Homebrew 安装:brew install kubernetes-helm 下载 tidb-docker-composegit clone https://github.com/pingcap/tidb-docker-compose.git 自定义集群cd tidb-docker-compose cp compose/values.yaml values.yaml vim values.yaml 修改 values.yaml 里面的配置,例如集群规模,TiDB 镜像版本等。tidb-vision 是 TiDB 集群可视化页面,可以可视化地显示 PD 对 TiKV 数据的调度。如果不想部署该组件,可以将 tidbVision 项留空。PD,TiKV,TiDB 和 tidb-vision 支持从 GitHub 源码或本地文件构建 Docker 镜像,供开发测试使用。 如果希望从本地已编译好的 binary 文件构建 PD,TiKV 或 TiDB 镜像,需要将其 image 字段留空,并将已编译好的 binary 拷贝到对应的 pd/bin/pd-server,tikv/bin/tikv-server,tidb/bin/tidb-server。 如果希望从本地构建 tidb-vision 镜像,需要将其 image 字段留空,并将 tidb-vision 项目拷贝到 tidb-vision/tidb-vision。 生成 docker-compose.yml 文件helm template -f values.yaml compose > generated-docker-compose.yml 使用生成的 docker-compose.yml 创建并启动集群docker-compose -f generated-docker-compose.yml pull # Get the latest Docker images docker-compose -f generated-docker-compose.yml up -d 访问集群mysql -h 127.0.0.1 -P 4000 -u root 访问集群 Grafana 监控页面:http://localhost:3000 默认用户名和密码均为 admin。如果启用了 tidb-vision,可以通过 http://localhost:8010 查看。 访问 Spark shell 并加载 TiSpark 向 TiDB 集群中插入一些样本数据:$ docker-compose exec tispark-master bash $ cd /opt/spark/data/tispark-sample-data $ mysql -h tidb -P 4000 -u root < dss.ddl 当样本数据加载到 TiDB 集群之后,可以使用 docker-compose exec tispark-master /opt/spark/bin/spark-shell 来访问 Spark shell。$ docker-compose exec tispark-master /opt/spark/bin/spark-shell ... Spark context available as 'sc' (master = local[*], app id = local-1527045927617). Spark session available as 'spark'. Welcome to ____ __ / __/__ ___ _____/ /__ _ / _ / _ `/ __/ '_/ /___/ .__/_,_/_/ /_/_ version 2.1.1 /_/ Using Scala version 2.11.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_172) Type in expressions to have them evaluated. Type :help for more information. scala> import org.apache.spark.sql.TiContext ... scala> val ti = new TiContext(spark) ... scala> ti.tidbMapDatabase("TPCH_001") ... scala> spark.sql("select count(*) from lineitem").show +--------+ |count(1)| +--------+ | 60175| +--------+ 你也可以通过 Python 或 R 来访问 Spark:docker-compose exec tispark-master /opt/spark/bin/pyspark docker-compose exec tispark-master /opt/spark/bin/sparkR 更多关于 TiSpark 的信息,参见 TiSpark 的详细文档。"}, {"url": "https://pingcap.com/docs-cn/v1.0/op-guide/docker-compose/", "title": "使用 Docker Compose 构建集群", "content": " 使用 Docker Compose 快速构建集群 Docker Compose 可以通过一个 YAML 文件定义多个容器的应用服务,然后一键启动或停止。可以用来在单机上一键部署一套 TiDB 测试集群,使用 Docker Compose 部署 TiDB 集群要求 Docker 是 17.06.0 及以上版本。快速开始 下载 tidb-docker-composegit clone https://github.com/pingcap/tidb-docker-compose.git 创建并启动集群cd tidb-docker-compose && docker-compose up -d 访问集群mysql -h 127.0.0.1 -P 4000 -u root 访问集群 Grafana 监控页面:http://localhost:3000 默认用户名和密码都是 admin。集群数据可视化:http://localhost:8010 自定义集群 快速开始里面默认部署 3 个 PD,3 个 TiKV,1 个 TiDB 和监控组件 Prometheus,Pushgateway,Grafana 以及 tidb-vision。如果想自定义集群,可以直接修改 docker-compose.yml,但是手动修改比较繁琐而且容易出错,强烈建议使用 Helm 模板引擎生成 docker-compose.yml 文件。 安装 HelmHelm 可以用作模板渲染引擎,只需要下载其 binary 文件即可以使用。curl https://raw.githubusercontent.com/kubernetes/helm/master/scripts/get | bash 如果是 Mac 系统,也可以通过 Homebrew 安装:brew install kubernetes-helm 下载 tidb-docker-composegit clone https://github.com/pingcap/tidb-docker-compose.git 自定义集群cd tidb-docker-compose cp compose/values.yaml values.yaml vim values.yaml 修改 values.yaml 里面的配置,例如集群规模,TiDB 镜像版本等。tidb-vision 是 TiDB 集群可视化页面,可以可视化地显示 PD 对 TiKV 数据的调度。如果不想部署该组件,可以将 tidbVision 项留空。PD,TiKV,TiDB 和 tidb-vision 支持从 GitHub 源码或本地文件构建 Docker 镜像,供开发测试使用。 如果希望从 GitHub 源码构建某个组件的镜像,需要将其 image 字段留空,然后设置其 buildFrom 为 remote。 如果希望从本地已编译好的 binary 文件构建 PD,TiKV 或 TiDB 镜像,需要将其 image 字段留空,然后设置其 buildFrom 为 local,并将已编译好的 binary 拷贝到对应的 pd/bin/pd-server,tikv/bin/tikv-server,tidb/bin/tidb-server。 如果希望从本地构建 tidb-vision 镜像,需要将其 image 字段留空,然后设置其 buildFrom 为 local,并将 tidb-vision 项目拷贝到 tidb-vision/tidb-vision。 生成 docker-compose.yml 文件helm template -f values.yaml compose > generated-docker-compose.yml 使用生成的 docker-compose.yml 创建并启动集群docker-compose -f generated-docker-compose.yml up -d 访问集群mysql -h 127.0.0.1 -P 4000 -u root 访问集群 Grafana 监控页面:http://localhost:3000 默认用户名和密码都是 admin。如果启用了 tidb-vision,可以通过 http://localhost:8010 查看。 "}, {"url": "https://pingcap.com/docs-cn/v2.0/op-guide/docker-compose/", "title": "使用 Docker Compose 构建集群", "content": " 使用 Docker Compose 快速构建集群 本文档介绍如何通过 Docker Compose 快速部署 TiDB 集群。Docker Compose 可以通过一个 YAML 文件定义多个容器的应用服务,然后一键启动或停止。可以用来在单机上一键部署一套 TiDB 测试集群,使用 Docker Compose 部署 TiDB 集群要求 Docker 是 17.06.0 及以上版本。快速部署 下载 tidb-docker-composegit clone https://github.com/pingcap/tidb-docker-compose.git 创建并启动集群cd tidb-docker-compose && docker-compose up -d 访问集群mysql -h 127.0.0.1 -P 4000 -u root 访问集群 Grafana 监控页面:http://localhost:3000 默认用户名和密码均为 admin。集群数据可视化:http://localhost:8010 自定义集群 在完成快速部署后,以下组件已默认部署:3 个 PD,3 个 TiKV,1 个 TiDB 和监控组件 Prometheus,Pushgateway,Grafana 以及 tidb-vision。如果想自定义集群,可以直接修改 docker-compose.yml,但是手动修改比较繁琐而且容易出错,强烈建议使用 Helm 模板引擎生成 docker-compose.yml 文件。 安装 HelmHelm 可以用作模板渲染引擎,只需要下载其 binary 文件即可以使用。curl https://raw.githubusercontent.com/kubernetes/helm/master/scripts/get | bash 如果是 Mac 系统,也可以通过 Homebrew 安装:brew install kubernetes-helm 下载 tidb-docker-composegit clone https://github.com/pingcap/tidb-docker-compose.git 自定义集群cd tidb-docker-compose cp compose/values.yaml values.yaml vim values.yaml 修改 values.yaml 里面的配置,例如集群规模,TiDB 镜像版本等。tidb-vision 是 TiDB 集群可视化页面,可以可视化地显示 PD 对 TiKV 数据的调度。如果不想部署该组件,可以将 tidbVision 项留空。PD,TiKV,TiDB 和 tidb-vision 支持从 GitHub 源码或本地文件构建 Docker 镜像,供开发测试使用。 如果希望从 GitHub 源码构建某个组件的镜像,需要将其 image 字段留空,然后设置其 buildFrom 为 remote。 如果希望从本地已编译好的 binary 文件构建 PD,TiKV 或 TiDB 镜像,需要将其 image 字段留空,然后设置其 buildFrom 为 local,并将已编译好的 binary 拷贝到对应的 pd/bin/pd-server,tikv/bin/tikv-server,tidb/bin/tidb-server。 如果希望从本地构建 tidb-vision 镜像,需要将其 image 字段留空,然后设置其 buildFrom 为 local,并将 tidb-vision 项目拷贝到 tidb-vision/tidb-vision。 生成 docker-compose.yml 文件helm template -f values.yaml compose > generated-docker-compose.yml 使用生成的 docker-compose.yml 创建并启动集群docker-compose -f generated-docker-compose.yml up -d 访问集群mysql -h 127.0.0.1 -P 4000 -u root 访问集群 Grafana 监控页面:http://localhost:3000 默认用户名和密码都是 admin。如果启用了 tidb-vision,可以通过 http://localhost:8010 查看。 "}, {"url": "https://pingcap.com/docs-cn/op-guide/ansible-deployment-rolling-update/", "title": "使用 TiDB-Ansible 升级 TiDB 集群", "content": " 使用 TiDB-Ansible 升级 TiDB 集群 滚动升级 TiDB 集群时,会串行关闭服务,更新服务 binary 和配置文件,再启动服务。在前端配置负载均衡的情况下,滚动升级期间不影响业务运行(最小环境 :pd * 3、tidb * 2、tikv * 3)。 注:如果 TiDB 集群开启了 binlog,部署了 Pump 和 Drainer 服务,升级 TiDB 服务时会升级 Pump,请先停止 Drainer 服务再执行滚动升级操作。 升级组件版本 跨大版本升级,必须更新 tidb-ansible,小版本升级,也建议更新 tidb-ansible,以获取最新的配置文件模板、特性及 bug 修复。从 TiDB 1.0 升级到 TiDB 2.0,参考 TiDB 2.0 升级操作指南;从 TiDB 2.0 升级到 TiDB 2.1,参考 TiDB 2.1 升级操作指南。自动下载 binary 修改 /home/tidb/tidb-ansible/inventory.ini 中的 tidb_version 参数值,指定需要升级的版本号,如从 v2.0.6 升级到 v2.0.7tidb_version = v2.0.7 注:如果使用 master 分支的 tidb-ansible,tidb_version = latest 保持不变即可,latest 版本的 TiDB 安装包会每日更新。 删除原有的 downloads 目录 /home/tidb/tidb-ansible/downloads/$ cd /home/tidb/tidb-ansible $ rm -rf downloads 使用 playbook 下载 TiDB binary,自动替换 binary 到 /home/tidb/tidb-ansible/resource/bin/$ ansible-playbook local_prepare.yml 手动下载 binary 除 “自动下载 binary” 中描述的方法之外,也可以手动下载 binary,解压后手动替换 binary 到 /home/tidb/tidb-ansible/resource/bin/,需注意替换链接中的版本号。$ wget http://download.pingcap.org/tidb-v2.0.7-linux-amd64.tar.gz 如果使用 master 分支的 tidb-ansible,使用以下命令下载 binary:$ wget http://download.pingcap.org/tidb-latest-linux-amd64.tar.gz 使用 Ansible 滚动升级 滚动升级 PD 节点(只升级单独 PD 服务)$ ansible-playbook rolling_update.yml --tags=pd 如果 PD 实例数大于等于 3,滚动升级 PD leader 实例时,Ansible 会先迁移 PD leader 到其他节点再关闭该实例。 滚动升级 TiKV 节点(只升级 TiKV 服务)$ ansible-playbook rolling_update.yml --tags=tikv 滚动升级 TiKV 实例时,Ansible 会迁移 region leader 到其他节点。具体逻辑为:调用 PD API 添加 evict leader scheduler,每 10 秒探测一次该 TiKV 实例 leader_count, 等待 leader_count 降到 1 以下或探测超 18 次后,即三分钟超时后,开始关闭 TiKV 升级,启动成功后再去除 evict leader scheduler,串行操作。如中途升级失败,请登录 pd-ctl 执行 scheduler show,查看是否有 evict-leader-scheduler, 如有需手工清除。{PD_IP} 和 {STORE_ID} 请替换为你的 PD IP 及 TiKV 实例的 store_id。$ /home/tidb/tidb-ansible/resources/bin/pd-ctl -u "http://{PD_IP}:2379" » scheduler show [ "label-scheduler", "evict-leader-scheduler-{STORE_ID}", "balance-region-scheduler", "balance-leader-scheduler", "balance-hot-region-scheduler" ] » scheduler remove evict-leader-scheduler-{STORE_ID} 滚动升级 TiDB 节点(只升级单独 TiDB 服务,如果 TiDB 集群开启了 binlog,升级 TiDB 服务时会升级 pump)$ ansible-playbook rolling_update.yml --tags=tidb 滚动升级所有服务(依次升级 PD,TiKV,TiDB 服务,如果 TiDB 集群开启了 binlog,升级 TiDB 服务时会升级 pump)$ ansible-playbook rolling_update.yml 滚动升级监控组件$ ansible-playbook rolling_update_monitor.yml 变更组件配置 更新组件配置模板TiDB 集群组件配置模板存储在 /home/tidb/tidb-ansible/conf 文件夹下。 组件 配置文件模板名 TiDB tidb.yml TiKV tikv.yml PD pd.yml 默认配置项是注释状态,使用默认值。如果需要修改,需取消注释,即去除 #,修改对应参数值。配置模板使用 yaml 格式,注意参数名及参数值之间使用 : 分隔,缩进为两个空格。如修改 TiKV 配置中 high-concurrency、normal-concurrency 和 low-concurrency 三个参数为 16:readpool: coprocessor: # Notice: if CPU_NUM > 8, default thread pool size for coprocessors # will be set to CPU_NUM * 0.8. high-concurrency: 16 normal-concurrency: 16 low-concurrency: 16 修改服务配置后,需使用 Ansible 滚动升级,参考使用 Ansible 滚动升级。 "}, {"url": "https://pingcap.com/docs-cn/op-guide/ansible-deployment-scale/", "title": "使用 TiDB-Ansible 扩容缩容 TiDB 集群", "content": " 使用 TiDB-Ansible 扩容缩容 TiDB 集群 TiDB 集群可以在不影响线上服务的情况下进行扩容和缩容。以下缩容示例中,被移除的节点没有混合部署其他服务;如果混合部署了其他服务,不能按如下操作。假设拓扑结构如下所示: Name Host IP Services node1 172.16.10.1 PD1 node2 172.16.10.2 PD2 node3 172.16.10.3 PD3, Monitor node4 172.16.10.4 TiDB1 node5 172.16.10.5 TiDB2 node6 172.16.10.6 TiKV1 node7 172.16.10.7 TiKV2 node8 172.16.10.8 TiKV3 node9 172.16.10.9 TiKV4 扩容 TiDB/TiKV 节点 例如,如果要添加两个 TiDB 节点(node101、node102),IP 地址为 172.16.10.101、172.16.10.102,可以进行如下操作: 编辑 inventory.ini 文件,添加节点信息:[tidb_servers] 172.16.10.4 172.16.10.5 172.16.10.101 172.16.10.102 [pd_servers] 172.16.10.1 172.16.10.2 172.16.10.3 [tikv_servers] 172.16.10.6 172.16.10.7 172.16.10.8 172.16.10.9 [monitored_servers] 172.16.10.1 172.16.10.2 172.16.10.3 172.16.10.4 172.16.10.5 172.16.10.6 172.16.10.7 172.16.10.8 172.16.10.9 172.16.10.101 172.16.10.102 [monitoring_servers] 172.16.10.3 [grafana_servers] 172.16.10.3 现在拓扑结构如下所示: Name Host IP Services node1 172.16.10.1 PD1 node2 172.16.10.2 PD2 node3 172.16.10.3 PD3, Monitor node4 172.16.10.4 TiDB1 node5 172.16.10.5 TiDB2 node101 172.16.10.101 TiDB3 node102 172.16.10.102 TiDB4 node6 172.16.10.6 TiKV1 node7 172.16.10.7 TiKV2 node8 172.16.10.8 TiKV3 node9 172.16.10.9 TiKV4 初始化新增节点:ansible-playbook bootstrap.yml -l 172.16.10.101,172.16.10.102 注: 如果 inventory.ini 中为节点配置了别名,如 node101 ansible_host=172.16.10.101,执行 ansible-playbook 时 -l 请指定别名,以下步骤类似。例如:ansible-playbook bootstrap.yml -l node101,node102 部署新增节点:ansible-playbook deploy.yml -l 172.16.10.101,172.16.10.102 启动新节点服务:ansible-playbook start.yml -l 172.16.10.101,172.16.10.102 更新 Prometheus 配置并重启:ansible-playbook rolling_update_monitor.yml --tags=prometheus 打开浏览器访问监控平台:http://172.16.10.3:3000,监控整个集群和新增节点的状态。可使用同样的步骤添加 TiKV 节点。但如果要添加 PD 节点,则需手动更新一些配置文件。 扩容 PD 节点 例如,如果要添加一个 PD 节点(node103),IP 地址为 172.16.10.103,可以进行如下操作: 编辑 inventory.ini 文件,添加节点信息置于 [pd_servers] 主机组最后一行:[tidb_servers] 172.16.10.4 172.16.10.5 [pd_servers] 172.16.10.1 172.16.10.2 172.16.10.3 172.16.10.103 [tikv_servers] 172.16.10.6 172.16.10.7 172.16.10.8 172.16.10.9 [monitored_servers] 172.16.10.4 172.16.10.5 172.16.10.1 172.16.10.2 172.16.10.3 172.16.10.103 172.16.10.6 172.16.10.7 172.16.10.8 172.16.10.9 [monitoring_servers] 172.16.10.3 [grafana_servers] 172.16.10.3 现在拓扑结构如下所示: Name Host IP Services node1 172.16.10.1 PD1 node2 172.16.10.2 PD2 node3 172.16.10.3 PD3, Monitor node103 172.16.10.103 PD4 node4 172.16.10.4 TiDB1 node5 172.16.10.5 TiDB2 node6 172.16.10.6 TiKV1 node7 172.16.10.7 TiKV2 node8 172.16.10.8 TiKV3 node9 172.16.10.9 TiKV4 初始化新增节点:ansible-playbook bootstrap.yml -l 172.16.10.103 部署新增节点:ansible-playbook deploy.yml -l 172.16.10.103 登录新增的 PD 节点,编辑启动脚本:{deploy_dir}/scripts/run_pd.sh 移除 --initial-cluster="xxxx" 配置。 添加 --join="http://172.16.10.1:2379" ,IP 地址 (172.16.10.1) 可以是集群内现有 PD IP 地址中的任意一个。 在新增 PD 节点中手动启动 PD 服务:{deploy_dir}/scripts/start_pd.sh 使用 pd-ctl 检查新节点是否添加成功:/home/tidb/tidb-ansible/resources/bin/pd-ctl -u "http://172.16.10.1:2379" -d member 滚动升级整个集群:ansible-playbook rolling_update.yml 更新 Prometheus 配置并重启:ansible-playbook rolling_update_monitor.yml --tags=prometheus 打开浏览器访问监控平台:http://172.16.10.3:3000,监控整个集群和新增节点的状态。 缩容 TiDB 节点 例如,如果要移除一个 TiDB 节点(node5),IP 地址为 172.16.10.5,可以进行如下操作: 停止 node5 节点上的服务:ansible-playbook stop.yml -l 172.16.10.5 编辑 inventory.ini 文件,移除节点信息:[tidb_servers] 172.16.10.4 #172.16.10.5 # 注释被移除节点 [pd_servers] 172.16.10.1 172.16.10.2 172.16.10.3 [tikv_servers] 172.16.10.6 172.16.10.7 172.16.10.8 172.16.10.9 [monitored_servers] 172.16.10.4 #172.16.10.5 # 注释被移除节点 172.16.10.1 172.16.10.2 172.16.10.3 172.16.10.6 172.16.10.7 172.16.10.8 172.16.10.9 [monitoring_servers] 172.16.10.3 [grafana_servers] 172.16.10.3 现在拓扑结构如下所示: Name Host IP Services node1 172.16.10.1 PD1 node2 172.16.10.2 PD2 node3 172.16.10.3 PD3, Monitor node4 172.16.10.4 TiDB1 node5 172.16.10.5 TiDB2 已删除 node6 172.16.10.6 TiKV1 node7 172.16.10.7 TiKV2 node8 172.16.10.8 TiKV3 node9 172.16.10.9 TiKV4 更新 Prometheus 配置并重启:ansible-playbook rolling_update_monitor.yml --tags=prometheus 打开浏览器访问监控平台:http://172.16.10.3:3000,监控整个集群的状态。 缩容 TiKV 节点 例如,如果要移除一个 TiKV 节点(node9),IP 地址为 172.16.10.9,可以进行如下操作: 使用 pd-ctl 从集群中移除节点: 查看 node9 节点的 store id:/home/tidb/tidb-ansible/resources/bin/pd-ctl -u "http://172.16.10.1:2379" -d store 从集群中移除 node9,假如 store id 为 10:/home/tidb/tidb-ansible/resources/bin/pd-ctl -u "http://172.16.10.1:2379" -d store delete 10 使用 Grafana 或者 pd-ctl 检查节点是否下线成功(下线需要一定时间,下线节点的状态变为 Tombstone 就说明下线成功了):/home/tidb/tidb-ansible/resources/bin/pd-ctl -u "http://172.16.10.1:2379" -d store 10 下线成功后,停止 node9 上的服务:ansible-playbook stop.yml -l 172.16.10.9 编辑 inventory.ini 文件,移除节点信息:[tidb_servers] 172.16.10.4 172.16.10.5 [pd_servers] 172.16.10.1 172.16.10.2 172.16.10.3 [tikv_servers] 172.16.10.6 172.16.10.7 172.16.10.8 #172.16.10.9 # 注释被移除节点 [monitored_servers] 172.16.10.4 172.16.10.5 172.16.10.1 172.16.10.2 172.16.10.3 172.16.10.6 172.16.10.7 172.16.10.8 #172.16.10.9 # 注释被移除节点 [monitoring_servers] 172.16.10.3 [grafana_servers] 172.16.10.3 现在拓扑结构如下所示: Name Host IP Services node1 172.16.10.1 PD1 node2 172.16.10.2 PD2 node3 172.16.10.3 PD3, Monitor node4 172.16.10.4 TiDB1 node5 172.16.10.5 TiDB2 node6 172.16.10.6 TiKV1 node7 172.16.10.7 TiKV2 node8 172.16.10.8 TiKV3 node9 172.16.10.9 TiKV4 已删除 更新 Prometheus 配置并重启:ansible-playbook rolling_update_monitor.yml --tags=prometheus 打开浏览器访问监控平台:http://172.16.10.3:3000,监控整个集群的状态。 缩容 PD 节点 例如,如果要移除一个 PD 节点(node2),IP 地址为 172.16.10.2,可以进行如下操作: 使用 pd-ctl 从集群中移除节点: 查看 node2 节点的 name:/home/tidb/tidb-ansible/resources/bin/pd-ctl -u "http://172.16.10.1:2379" -d member 从集群中移除 node2,假如 name 为 pd2:/home/tidb/tidb-ansible/resources/bin/pd-ctl -u "http://172.16.10.1:2379" -d member delete name pd2 使用 Grafana 或者 pd-ctl 检查节点是否下线成功(PD 下线会很快,结果中没有 node2 节点信息即为下线成功):/home/tidb/tidb-ansible/resources/bin/pd-ctl -u "http://172.16.10.1:2379" -d member 下线成功后,停止 node2 上的服务:ansible-playbook stop.yml -l 172.16.10.2 编辑 inventory.ini 文件,移除节点信息:[tidb_servers] 172.16.10.4 172.16.10.5 [pd_servers] 172.16.10.1 #172.16.10.2 # 注释被移除节点 172.16.10.3 [tikv_servers] 172.16.10.6 172.16.10.7 172.16.10.8 172.16.10.9 [monitored_servers] 172.16.10.4 172.16.10.5 172.16.10.1 #172.16.10.2 # 注释被移除节点 172.16.10.3 172.16.10.6 172.16.10.7 172.16.10.8 172.16.10.9 [monitoring_servers] 172.16.10.3 [grafana_servers] 172.16.10.3 现在拓扑结构如下所示: Name Host IP Services node1 172.16.10.1 PD1 node2 172.16.10.2 PD2 已删除 node3 172.16.10.3 PD3, Monitor node4 172.16.10.4 TiDB1 node5 172.16.10.5 TiDB2 node6 172.16.10.6 TiKV1 node7 172.16.10.7 TiKV2 node8 172.16.10.8 TiKV3 node9 172.16.10.9 TiKV4 滚动升级整个集群:ansible-playbook rolling_update.yml 更新 Prometheus 配置并重启:ansible-playbook rolling_update_monitor.yml --tags=prometheus 打开浏览器访问监控平台:http://172.16.10.3:3000,监控整个集群的状态。 "}, {"url": "https://pingcap.com/docs-cn/v1.0/op-guide/root-ansible-deployment/", "title": "使用 root 用户远程连接 TiDB Ansible 部署方案", "content": " 使用 root 用户远程连接 TiDB Ansible 部署方案 Ansible 远程连接用户(即 incentory.ini 文件中的 ansible_user),从中控机使用 root 用户 SSH 到部署目标机器部署,不推荐采用该方式安装。 修改 inventory.ini, 本例使用 tidb 帐户作为服务运行用户:取消 ansible_user = root 、ansible_become = true 及 ansible_become_user 注释,给 ansible_user = tidb 添加注释:## Connection # ssh via root: ansible_user = root ansible_become = true ansible_become_user = tidb # ssh via normal user # ansible_user = tidb 使用 local_prepare.yml playbook, 联网下载 TiDB binary 到中控机:ansible-playbook local_prepare.yml 初始化系统环境,修改内核参数 如服务运行用户尚未建立,此初始化操作会自动创建该用户。 ansible-playbook bootstrap.yml 如果 ansible 使用 root 用户远程连接需要密码, 使用 -k 参数,执行其他 playbook 同理:ansible-playbook bootstrap.yml -k 部署 TiDB 集群软件ansible-playbook deploy.yml -k 启动 TiDB 集群ansible-playbook start.yml -k "}, {"url": "https://pingcap.com/docs-cn/v2.0/op-guide/root-ansible-deployment/", "title": "使用 root 用户远程连接 TiDB Ansible 部署方案", "content": " 使用 root 用户远程连接 TiDB Ansible 部署方案 Ansible 远程连接用户(即 incentory.ini 文件中的 ansible_user),从中控机使用 root 用户 SSH 到部署目标机器部署,不推荐采用该方式安装。 修改 inventory.ini, 本例使用 tidb 帐户作为服务运行用户:取消 ansible_user = root 、ansible_become = true 及 ansible_become_user 注释,给 ansible_user = tidb 添加注释:## Connection # ssh via root: ansible_user = root ansible_become = true ansible_become_user = tidb # ssh via normal user # ansible_user = tidb 使用 local_prepare.yml playbook, 联网下载 TiDB binary 到中控机:ansible-playbook local_prepare.yml 初始化系统环境,修改内核参数 如服务运行用户尚未建立,此初始化操作会自动创建该用户。 ansible-playbook bootstrap.yml 如果 ansible 使用 root 用户远程连接需要密码, 使用 -k 参数,执行其他 playbook 同理:ansible-playbook bootstrap.yml -k 部署 TiDB 集群软件ansible-playbook deploy.yml -k 启动 TiDB 集群ansible-playbook start.yml -k "}, {"url": "https://pingcap.com/docs-cn/sql/encrypted-connections/", "title": "使用加密连接", "content": " 使用加密连接 TiDB 服务端默认采用非加密连接,因而具备监视信道流量能力的第三方可以知悉 TiDB 服务端与客户端之间发送和接受的数据,包括但不限于查询语句内容、查询结果等。若信道是不可信的,例如客户端是通过公网连接到 TiDB 服务端的,则非加密连接容易造成信息泄露,建议使用加密连接确保安全性。TiDB 服务端支持启用基于 TLS(传输层安全)协议的加密连接,协议与 MySQL 加密连接一致,现有 MySQL 客户端如 MySQL 运维工具和 MySQL 驱动等能直接支持。TLS 的前身是 SSL,因而 TLS 有时也被称为 SSL,但由于 SSL 协议有已知安全漏洞,TiDB 实际上并未支持。TiDB 支持的 TLS/SSL 协议版本为 TLS 1.0、TLS 1.1、TLS 1.2。使用加密连接后,连接将具有以下安全性质: 保密性:流量明文无法被窃听; 完整性:流量明文无法被篡改; 身份验证(可选):客户端和服务端能验证双方身份,避免中间人攻击。 TiDB 的加密连接支持默认是关闭的,必须在 TiDB 服务端通过配置开启加密连接的支持后,才能在客户端中使用加密连接。另外,与 MySQL 一致,TiDB 加密连接是以单个连接为单位的,并且是可选的,因而对于开启了加密连接支持的 TiDB 服务端,客户端既可以选择通过加密连接安全地连接到该 TiDB 服务端,也可以选择使用普通的非加密连接。大部分 MySQL 客户端默认不采用加密连接,因此一般还要显式地要求客户端使用加密连接。简单来说,要使用加密连接必须同时满足以下两个条件: TiDB 服务端配置开启加密连接的支持 客户端指定使用加密连接 配置 TiDB 启用加密连接支持 在启动 TiDB 时,至少需要在配置文件中同时指定 ssl-cert 和 ssl-key 参数,才能使 TiDB 服务端接受加密连接。还可以指定 ssl-ca 参数进行客户端身份验证(请参见配置启用身份验证章节)。 ssl-cert:指定 SSL 证书文件路径 ssl-key:指定证书文件对应的私钥 ssl-ca:可选,指定受信任的 CA 证书文件路径 参数指定的文件都为 PEM 格式。另外目前 TiDB 尚不支持加载有密码保护的私钥,因此必须提供一个没有密码的私钥文件。若提供的证书或私钥无效,则 TiDB 服务端将照常启动,但并不支持客户端加密连接到 TiDB 服务端。上述证书及密钥可以使用 OpenSSL 签发和生成,也可以使用 MySQL 自带的工具 mysql_ssl_rsa_setup 快捷生成:mysql_ssl_rsa_setup --datadir=./certs 以上命令将在 certs 目录下生成以下文件:certs ├── ca-key.pem ├── ca.pem ├── client-cert.pem ├── client-key.pem ├── private_key.pem ├── public_key.pem ├── server-cert.pem └── server-key.pem 对应的 TiDB 配置文件参数为:[security] ssl-cert = "certs/server-cert.pem" ssl-key = "certs/server-key.pem" 若证书参数无误,则 TiDB 在启动时将会输出 Secure connection is enabled,否则 TiDB 会输出 Secure connection is NOT ENABLED。配置 MySQL 客户端使用加密连接 MySQL 5.7 及以上版本自带的客户端默认尝试使用安全连接,若服务端不支持安全连接则自动退回到使用非安全连接;MySQL 5.7 以下版本自带的客户端默认采用非安全连接。可以通过命令行参数修改客户端的连接行为,包括: 强制使用安全连接,若服务端不支持安全连接则连接失败 (--ssl-mode=REQUIRED) 尝试使用安全连接,若服务端不支持安全连接则退回使用不安全连接 使用不安全连接 (--ssl-mode=DISABLED) 详细信息请参阅 MySQL 文档中关于客户端配置安全连接的部分。配置启用身份验证 若在 TiDB 服务端或 MySQL 客户端中未指定 ssl-ca 参数,则默认不会进行客户端或服务端身份验证,无法抵御中间人攻击,例如客户端可能会“安全地”连接到了一个伪装的服务端。可以在服务端和客户端中配置 ssl-ca 参数进行身份验证。一般情况下只需验证服务端身份,但也可以验证客户端身份进一步增强安全性。 若要使 MySQL 客户端验证 TiDB 服务端身份,TiDB 服务端需至少配置 ssl-cert 和 ssl-key 参数,客户端需至少指定 --ssl-ca 参数,且 --ssl-mode 至少为 VERIFY_IDENTITY。必须确保 TiDB 服务端配置的证书(ssl-cert)是由客户端 --ssl-ca 参数所指定的 CA 所签发的,否则身份验证失败。 若要使 TiDB 服务端验证 MySQL 客户端身份,TiDB 服务端需配置 ssl-cert、ssl-key、ssl-ca 参数,客户端需至少指定 --ssl-cert、--ssl-key 参数。必须确保服务端配置的证书和客户端配置的证书都是由服务端配置指定的 ssl-ca 签发的。 若要进行双向身份验证,请同时满足上述要求。 注:目前 TiDB 尚不支持强制验证客户端身份,即服务端对客户端的身份验证是可选的。若客户端在 TLS 握手时未出示自己的身份证书,也能正常建立 TLS 连接。检查当前连接是否是加密连接 可以通过 SHOW STATUS LIKE "%Ssl%"; 了解当前连接的详细情况,包括是否使用了安全连接、安全连接采用的加密协议、TLS 版本号等。以下是一个安全连接中执行该语句的结果。由于客户端支持的 TLS 版本号和加密协议会有所不同,执行结果相应地也会有所变化。mysql> SHOW STATUS LIKE "%Ssl%"; ...... | Ssl_verify_mode | 5 | | Ssl_version | TLSv1.2 | | Ssl_cipher | ECDHE-RSA-AES128-GCM-SHA256 | ...... 除此以外,对于 MySQL 自带客户端,还可以使用 STATUS 或 s 语句查看连接情况:mysql> s ... SSL: Cipher in use is ECDHE-RSA-AES128-GCM-SHA256 ... 支持的 TLS 版本及密钥交换协议和加密算法 TiDB 支持的 TLS 版本及密钥交换协议和加密算法由 Golang 官方库决定。支持的 TLS 版本 TLS 1.0 TLS 1.1 TLS 1.2 支持的密钥交换协议及加密算法 TLS_RSA_WITH_RC4_128_SHA TLS_RSA_WITH_3DES_EDE_CBC_SHA TLS_RSA_WITH_AES_128_CBC_SHA TLS_RSA_WITH_AES_256_CBC_SHA TLS_RSA_WITH_AES_128_CBC_SHA256 TLS_RSA_WITH_AES_128_GCM_SHA256 TLS_RSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_ECDSA_WITH_RC4_128_SHA TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA TLS_ECDHE_RSA_WITH_RC4_128_SHA TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305 TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 "}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/encrypted-connections/", "title": "使用加密连接", "content": " 使用加密连接 TiDB 服务端默认采用非加密连接,因而具备监视信道流量能力的第三方可以知悉 TiDB 服务端与客户端之间发送和接受的数据,包括但不限于查询语句内容、查询结果等。若信道是不可信的,例如客户端是通过公网连接到 TiDB 服务端的,则非加密连接容易造成信息泄露,建议使用加密连接确保安全性。TiDB 服务端支持启用基于 TLS(传输层安全)协议的加密连接,协议与 MySQL 加密连接一致,现有 MySQL 客户端如 MySQL 运维工具和 MySQL 驱动等能直接支持。TLS 的前身是 SSL,因而 TLS 有时也被称为 SSL,但由于 SSL 协议有已知安全漏洞,TiDB 实际上并未支持。TiDB 支持的 TLS/SSL 协议版本为 TLS 1.0、TLS 1.1、TLS 1.2。使用加密连接后,连接将具有以下安全性质: 保密性:流量明文无法被窃听; 完整性:流量明文无法被篡改; 身份验证(可选):客户端和服务端能验证双方身份,避免中间人攻击。 TiDB 的加密连接支持默认是关闭的,必须在 TiDB 服务端通过配置开启加密连接的支持后,才能在客户端中使用加密连接。另外,与 MySQL 一致,TiDB 加密连接是以单个连接为单位的,并且是可选的,因而对于开启了加密连接支持的 TiDB 服务端,客户端既可以选择通过加密连接安全地连接到该 TiDB 服务端,也可以选择使用普通的非加密连接。大部分 MySQL 客户端默认不采用加密连接,因此一般还要显式地要求客户端使用加密连接。简单来说,要使用加密连接必须同时满足以下两个条件: TiDB 服务端配置开启加密连接的支持 客户端指定使用加密连接 配置 TiDB 启用加密连接支持 在启动 TiDB 时,至少需要在配置文件中同时指定 ssl-cert 和 ssl-key 参数,才能使 TiDB 服务端接受加密连接。还可以指定 ssl-ca 参数进行客户端身份验证(请参见配置启用身份验证章节)。 ssl-cert:指定 SSL 证书文件路径 ssl-key:指定证书文件对应的私钥 ssl-ca:可选,指定受信任的 CA 证书文件路径 参数指定的文件都为 PEM 格式。另外目前 TiDB 尚不支持加载有密码保护的私钥,因此必须提供一个没有密码的私钥文件。若提供的证书或私钥无效,则 TiDB 服务端将照常启动,但并不支持客户端加密连接到 TiDB 服务端。上述证书及密钥可以使用 OpenSSL 签发和生成,也可以使用 MySQL 自带的工具 mysql_ssl_rsa_setup 快捷生成:mysql_ssl_rsa_setup --datadir=./certs 以上命令将在 certs 目录下生成以下文件:certs ├── ca-key.pem ├── ca.pem ├── client-cert.pem ├── client-key.pem ├── private_key.pem ├── public_key.pem ├── server-cert.pem └── server-key.pem 对应的 TiDB 配置文件参数为:[security] ssl-cert = "certs/server-cert.pem" ssl-key = "certs/server-key.pem" 若证书参数无误,则 TiDB 在启动时将会输出 Secure connection is enabled,否则 TiDB 会输出 Secure connection is NOT ENABLED。配置 MySQL 客户端使用加密连接 MySQL 5.7 及以上版本自带的客户端默认尝试使用安全连接,若服务端不支持安全连接则自动退回到使用非安全连接;MySQL 5.7 以下版本自带的客户端默认采用非安全连接。可以通过命令行参数修改客户端的连接行为,包括: 强制使用安全连接,若服务端不支持安全连接则连接失败 (--ssl-mode=REQUIRED) 尝试使用安全连接,若服务端不支持安全连接则退回使用不安全连接 使用不安全连接 (--ssl-mode=DISABLED) 详细信息请参阅 MySQL 文档中关于客户端配置安全连接的部分。配置启用身份验证 若在 TiDB 服务端或 MySQL 客户端中未指定 ssl-ca 参数,则默认不会进行客户端或服务端身份验证,无法抵御中间人攻击,例如客户端可能会“安全地”连接到了一个伪装的服务端。可以在服务端和客户端中配置 ssl-ca 参数进行身份验证。一般情况下只需验证服务端身份,但也可以验证客户端身份进一步增强安全性。 若要使 MySQL 客户端验证 TiDB 服务端身份,TiDB 服务端需至少配置 ssl-cert 和 ssl-key 参数,客户端需至少指定 --ssl-ca 参数,且 --ssl-mode 至少为 VERIFY_IDENTITY。必须确保 TiDB 服务端配置的证书(ssl-cert)是由客户端 --ssl-ca 参数所指定的 CA 所签发的,否则身份验证失败。 若要使 TiDB 服务端验证 MySQL 客户端身份,TiDB 服务端需配置 ssl-cert、ssl-key、ssl-ca 参数,客户端需至少指定 --ssl-cert、--ssl-key 参数。必须确保服务端配置的证书和客户端配置的证书都是由服务端配置指定的 ssl-ca 签发的。 若要进行双向身份验证,请同时满足上述要求。 注:目前 TiDB 尚不支持强制验证客户端身份,即服务端对客户端的身份验证是可选的。若客户端在 TLS 握手时未出示自己的身份证书,也能正常建立 TLS 连接。检查当前连接是否是加密连接 可以通过 SHOW STATUS LIKE "%Ssl%"; 了解当前连接的详细情况,包括是否使用了安全连接、安全连接采用的加密协议、TLS 版本号等。以下是一个安全连接中执行该语句的结果。由于客户端支持的 TLS 版本号和加密协议会有所不同,执行结果相应地也会有所变化。mysql> SHOW STATUS LIKE "%Ssl%"; ...... | Ssl_verify_mode | 5 | | Ssl_version | TLSv1.2 | | Ssl_cipher | ECDHE-RSA-AES128-GCM-SHA256 | ...... 除此以外,对于 MySQL 自带客户端,还可以使用 STATUS 或 s 语句查看连接情况:mysql> s ... SSL: Cipher in use is ECDHE-RSA-AES128-GCM-SHA256 ... 支持的 TLS 版本及密钥交换协议和加密算法 TiDB 支持的 TLS 版本及密钥交换协议和加密算法由 Golang 官方库决定。支持的 TLS 版本 TLS 1.0 TLS 1.1 TLS 1.2 支持的密钥交换协议及加密算法 TLS_RSA_WITH_RC4_128_SHA TLS_RSA_WITH_3DES_EDE_CBC_SHA TLS_RSA_WITH_AES_128_CBC_SHA TLS_RSA_WITH_AES_256_CBC_SHA TLS_RSA_WITH_AES_128_CBC_SHA256 TLS_RSA_WITH_AES_128_GCM_SHA256 TLS_RSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_ECDSA_WITH_RC4_128_SHA TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA TLS_ECDHE_RSA_WITH_RC4_128_SHA TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305 TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 "}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/encrypted-connections/", "title": "使用加密连接", "content": " 使用加密连接 TiDB 服务端默认采用非加密连接,因而具备监视信道流量能力的第三方可以知悉 TiDB 服务端与客户端之间发送和接受的数据,包括但不限于查询语句内容、查询结果等。若信道是不可信的,例如客户端是通过公网连接到 TiDB 服务端的,则非加密连接容易造成信息泄露,建议使用加密连接确保安全性。TiDB 服务端支持启用基于 TLS(传输层安全)协议的加密连接,协议与 MySQL 加密连接一致,现有 MySQL 客户端如 MySQL 运维工具和 MySQL 驱动等能直接支持。TLS 的前身是 SSL,因而 TLS 有时也被称为 SSL,但由于 SSL 协议有已知安全漏洞,TiDB 实际上并未支持。TiDB 支持的 TLS/SSL 协议版本为 TLS 1.0、TLS 1.1、TLS 1.2。使用加密连接后,连接将具有以下安全性质: 保密性:流量明文无法被窃听; 完整性:流量明文无法被篡改; 身份验证(可选):客户端和服务端能验证双方身份,避免中间人攻击。 TiDB 的加密连接支持默认是关闭的,必须在 TiDB 服务端通过配置开启加密连接的支持后,才能在客户端中使用加密连接。另外,与 MySQL 一致,TiDB 加密连接是以单个连接为单位的,并且是可选的,因而对于开启了加密连接支持的 TiDB 服务端,客户端既可以选择通过加密连接安全地连接到该 TiDB 服务端,也可以选择使用普通的非加密连接。大部分 MySQL 客户端默认不采用加密连接,因此一般还要显式地要求客户端使用加密连接。简单来说,要使用加密连接必须同时满足以下两个条件: TiDB 服务端配置开启加密连接的支持 客户端指定使用加密连接 配置 TiDB 启用加密连接支持 在启动 TiDB 时,至少需要在配置文件中同时指定 ssl-cert 和 ssl-key 参数,才能使 TiDB 服务端接受加密连接。还可以指定 ssl-ca 参数进行客户端身份验证(请参见配置启用身份验证章节)。 ssl-cert:指定 SSL 证书文件路径 ssl-key:指定证书文件对应的私钥 ssl-ca:可选,指定受信任的 CA 证书文件路径 参数指定的文件都为 PEM 格式。另外目前 TiDB 尚不支持加载有密码保护的私钥,因此必须提供一个没有密码的私钥文件。若提供的证书或私钥无效,则 TiDB 服务端将照常启动,但并不支持客户端加密连接到 TiDB 服务端。上述证书及密钥可以使用 OpenSSL 签发和生成,也可以使用 MySQL 自带的工具 mysql_ssl_rsa_setup 快捷生成:mysql_ssl_rsa_setup --datadir=./certs 以上命令将在 certs 目录下生成以下文件:certs ├── ca-key.pem ├── ca.pem ├── client-cert.pem ├── client-key.pem ├── private_key.pem ├── public_key.pem ├── server-cert.pem └── server-key.pem 对应的 TiDB 配置文件参数为:[security] ssl-cert = "certs/server-cert.pem" ssl-key = "certs/server-key.pem" 若证书参数无误,则 TiDB 在启动时将会输出 Secure connection is enabled,否则 TiDB 会输出 Secure connection is NOT ENABLED。配置 MySQL 客户端使用加密连接 MySQL 5.7 及以上版本自带的客户端默认尝试使用安全连接,若服务端不支持安全连接则自动退回到使用非安全连接;MySQL 5.7 以下版本自带的客户端默认采用非安全连接。可以通过命令行参数修改客户端的连接行为,包括: 强制使用安全连接,若服务端不支持安全连接则连接失败 (--ssl-mode=REQUIRED) 尝试使用安全连接,若服务端不支持安全连接则退回使用不安全连接 使用不安全连接 (--ssl-mode=DISABLED) 详细信息请参阅 MySQL 文档中关于客户端配置安全连接的部分。配置启用身份验证 若在 TiDB 服务端或 MySQL 客户端中未指定 ssl-ca 参数,则默认不会进行客户端或服务端身份验证,无法抵御中间人攻击,例如客户端可能会“安全地”连接到了一个伪装的服务端。可以在服务端和客户端中配置 ssl-ca 参数进行身份验证。一般情况下只需验证服务端身份,但也可以验证客户端身份进一步增强安全性。 若要使 MySQL 客户端验证 TiDB 服务端身份,TiDB 服务端需至少配置 ssl-cert 和 ssl-key 参数,客户端需至少指定 --ssl-ca 参数,且 --ssl-mode 至少为 VERIFY_IDENTITY。必须确保 TiDB 服务端配置的证书(ssl-cert)是由客户端 --ssl-ca 参数所指定的 CA 所签发的,否则身份验证失败。 若要使 TiDB 服务端验证 MySQL 客户端身份,TiDB 服务端需配置 ssl-cert、ssl-key、ssl-ca 参数,客户端需至少指定 --ssl-cert、--ssl-key 参数。必须确保服务端配置的证书和客户端配置的证书都是由服务端配置指定的 ssl-ca 签发的。 若要进行双向身份验证,请同时满足上述要求。 注:目前 TiDB 尚不支持强制验证客户端身份,即服务端对客户端的身份验证是可选的。若客户端在 TLS 握手时未出示自己的身份证书,也能正常建立 TLS 连接。检查当前连接是否是加密连接 可以通过 SHOW STATUS LIKE "%Ssl%"; 了解当前连接的详细情况,包括是否使用了安全连接、安全连接采用的加密协议、TLS 版本号等。以下是一个安全连接中执行该语句的结果。由于客户端支持的 TLS 版本号和加密协议会有所不同,执行结果相应地也会有所变化。mysql> SHOW STATUS LIKE "%Ssl%"; ...... | Ssl_verify_mode | 5 | | Ssl_version | TLSv1.2 | | Ssl_cipher | ECDHE-RSA-AES128-GCM-SHA256 | ...... 除此以外,对于 MySQL 自带客户端,还可以使用 STATUS 或 s 语句查看连接情况:mysql> s ... SSL: Cipher in use is ECDHE-RSA-AES128-GCM-SHA256 ... 支持的 TLS 版本及密钥交换协议和加密算法 TiDB 支持的 TLS 版本及密钥交换协议和加密算法由 Golang 官方库决定。支持的 TLS 版本 TLS 1.0 TLS 1.1 TLS 1.2 支持的密钥交换协议及加密算法 TLS_RSA_WITH_RC4_128_SHA TLS_RSA_WITH_3DES_EDE_CBC_SHA TLS_RSA_WITH_AES_128_CBC_SHA TLS_RSA_WITH_AES_256_CBC_SHA TLS_RSA_WITH_AES_128_CBC_SHA256 TLS_RSA_WITH_AES_128_GCM_SHA256 TLS_RSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_ECDSA_WITH_RC4_128_SHA TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA TLS_ECDHE_RSA_WITH_RC4_128_SHA TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305 TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 "}, {"url": "https://pingcap.com/docs-cn/sql/information-functions/", "title": "信息函数", "content": " 信息函数 TiDB 中信息函数的使用方法与 MySQL 基本一致,详情参见:Information Functions。信息函数表 函数名 功能描述 CONNECTION_ID() 返回当前连接的连接 ID (线程 ID) CURRENT_USER(), CURRENT_USER 返回当前用户的用户名和主机名 DATABASE() 返回默认(当前)的数据库名 FOUND_ROWS() 该函数返回对于一个包含 LIMIT 的 SELECT 查询语句,在不包含 LIMIT 的情况下回返回的记录数 LAST_INSERT_ID() 返回最后一条 INSERT 语句中自增列的值 SCHEMA() 与 DATABASE() 同义 SESSION_USER() 与 USER() 同义 SYSTEM_USER() 与 USER() 同义 USER() 返回客户端提供的用户名和主机名 VERSION() 返回当前 MySQL 服务器的版本信息 TIDB_VERSION() 返回当前 TiDB 服务器的版本信息 "}, {"url": "https://pingcap.com/cloud-tidb-agreement/", "title": "公有云用户 TiDB 数据库服务协议", "content": " 公有云用户 TiDB 数据库服务协议 甲方:公有云用户(以下简称“用户”)乙方:北京平凯星辰科技发展有限公司甲乙双方经过平等协商,特达成本协议。本协议为甲方与乙方就使用乙方提供的公有云 TiDB 数据库服务达成的协议。1. 协议的生效 1.1 本协议生效以用户在公有云 TiDB 页面点击购买或者使用生效。2. 知识产权 2.1 乙方提供的本产品的版权或所有权,归乙方所有。3. 费用 3.1 费用及结算方式以公有云 TiDB 页面公布的为准。4. 甲方的权利义务 4.1 甲方应保证使用乙方产品的各项行为均符合国家法律法规的规定。4.2 甲方有义务为本协议中所涉及产品内容、数据信息及服务内容、销售价格等相关信息严格保密,不得向任何第三方透露。4.3 甲方同意,若使用乙方产品为第三方服务,乙方不承担甲方和任何第三方的纠纷。5. 乙方的权利义务 5.1 乙方应为甲方按约提供产品服务。5.2 乙方有义务为本协议中所涉及产品内容、数据信息及服务内容、销售价格等相关信息严格保密,不得向任何第三方透露。6. 终止 6.1 出现下列情况之一的,乙方有权在不经事先通知的情况下,立即终止甲方使用乙方产品服务的权利,而无需承担任何责任: 甲方购买乙方的产品服务且未在规定时间内续费的 甲方严重违反本协议下其他条款之约定,且在乙方通知后尚未纠正的 7. 发票 7.1 乙方承诺为甲方所采购的乙方之产品服务开据增值税发票。"}, {"url": "https://pingcap.com/about-cn/", "title": "关于", "content": ""}, {"url": "https://pingcap.com/docs-cn/sql/keywords-and-reserved-words/", "title": "关键字和保留字", "content": " 关键字和保留字 关键字在 SQL 中有特殊的意义, 例如 SELECT,UPDATE,DELETE,在作为表名跟函数名的时候,需要特殊对待,例如作为表名,保留字需要被反引号包住:mysql> CREATE TABLE select (a INT); ERROR 1105 (HY000): line 0 column 19 near " (a INT)" (total length 27) mysql> CREATE TABLE `select` (a INT); Query OK, 0 rows affected (0.09 sec) BEGIN 和 END 是关键字, 但不是保留字,所以不需要反引号:mysql> CREATE TABLE `select` (BEGIN int, END int); Query OK, 0 rows affected (0.09 sec) 有一种特殊情况, 如果使用了限定符 .,那么也不需要用反引号:mysql> CREATE TABLE test.select (BEGIN int, END int); Query OK, 0 rows affected (0.08 sec) 下表列出了在 TiDB 中的关键字跟保留字,保留字用 ® 来标识: ACTION ADD ® ADDDATE ADMIN AFTER ALL ® ALTER ® ALWAYS ANALYZE® AND ® ANY AS ® ASC ® ASCII AUTO_INCREMENT AVG AVG_ROW_LENGTH BEGIN BETWEEN ® BIGINT ® BINARY ® BINLOG BIT BIT_XOR BLOB ® BOOL BOOLEAN BOTH ® BTREE BY ® BYTE CASCADE ® CASE ® CAST CHANGE ® CHAR ® CHARACTER ® CHARSET CHECK ® CHECKSUM COALESCE COLLATE ® COLLATION COLUMN ® COLUMNS COMMENT COMMIT COMMITTED COMPACT COMPRESSED COMPRESSION CONNECTION CONSISTENT CONSTRAINT ® CONVERT ® COUNT CREATE ® CROSS ® CURRENT_DATE ® CURRENT_TIME ® CURRENT_TIMESTAMP ® CURRENT_USER ® CURTIME DATA DATABASE ® DATABASES ® DATE DATE_ADD DATE_SUB DATETIME DAY DAY_HOUR ® DAY_MICROSECOND ® DAY_MINUTE ® DAY_SECOND ® DDL DEALLOCATE DEC DECIMAL ® DEFAULT ® DELAY_KEY_WRITE DELAYED ® DELETE ® DESC ® DESCRIBE ® DISABLE DISTINCT ® DISTINCTROW ® DIV ® DO DOUBLE ® DROP ® DUAL ® DUPLICATE DYNAMIC ELSE ® ENABLE ENCLOSED END ENGINE ENGINES ENUM ESCAPE ESCAPED EVENTS EXCLUSIVE EXECUTE EXISTS EXPLAIN ® EXTRACT FALSE ® FIELDS FIRST FIXED FLOAT ® FLUSH FOR ® FORCE ® FOREIGN ® FORMAT FROM ® FULL FULLTEXT ® FUNCTION GENERATED ® GET_FORMAT GLOBAL GRANT ® GRANTS GROUP ® GROUP_CONCAT HASH HAVING ® HIGH_PRIORITY ® HOUR HOUR_MICROSECOND ® HOUR_MINUTE ® HOUR_SECOND ® IDENTIFIED IF ® IGNORE ® IN ® INDEX ® INDEXES INFILE ® INNER ® INSERT ® INT ® INTEGER ® INTERVAL ® INTO ® IS ® ISOLATION JOBS JOIN ® JSON KEY ® KEY_BLOCK_SIZE KEYS ® KILL ® LEADING ® LEFT ® LESS LEVEL LIKE ® LIMIT ® LINES ® LOAD ® LOCAL LOCALTIME ® LOCALTIMESTAMP ® LOCK ® LONGBLOB ® LONGTEXT ® LOW_PRIORITY ® MAX MAX_ROWS MAXVALUE ® MEDIUMBLOB ® MEDIUMINT ® MEDIUMTEXT ® MICROSECOND MIN MIN_ROWS MINUTE MINUTE_MICROSECOND ® MINUTE_SECOND ® MIN MIN_ROWS MINUTE MINUTE_MICROSECOND MINUTE_SECOND MOD ® MODE MODIRY MONTH NAMES NATIONAL NATURAL ® NO NO_WRITE_TO_BINLOG ® NONE NOT ® NOW NULL ® NUMERIC ® NVARCHAR ® OFFSET ON ® ONLY OPTION ® OR ® ORDER ® OUTER ® PARTITION ® PARTITIONS PASSWORD PLUGINS POSITION PRECISION ® PREPARE PRIMARY ® PRIVILEGES PROCEDURE ® PROCESS PROCESSLIST QUARTER QUERY QUICK RANGE ® READ ® REAL ® REDUNDANT REFERENCES ® REGEXP ® RENAME ® REPEAT ® REPEATABLE REPLACE ® RESTRICT ® REVERSE REVOKE ® RIGHT ® RLIKE ® ROLLBACK ROW ROW_COUNT ROW_FORMAT SCHEMA SCHEMAS SECOND SECOND_MICROSECOND ® SELECT ® SERIALIZABLE SESSION SET ® SHARE SHARED SHOW ® SIGNED SMALLINT ® SNAPSHOT SOME SQL_CACHE SQL_CALC_FOUND_ROWS ® SQL_NO_CACHE START STARTING ® STATS STATS_BUCKETS STATS_HISTOGRAMS STATS_META STATS_PERSISTENT STATUS STORED ® SUBDATE SUBSTR SUBSTRING SUM SUPER TABLE ® TABLES TERMINATED ® TEXT THAN THEN ® TIDB TIDB_INLJ TIDB_SMJ TIME TIMESTAMP TIMESTAMPADD TIMESTAMPDIFF TINYBLOB ® TINYINT ® TINYTEXT ® TO ® TRAILING ® TRANSACTION TRIGGER ® TRIGGERS TRIM TRUE ® TRUNCATE UNCOMMITTED UNION ® UNIQUE ® UNKNOWN UNLOCK ® UNSIGNED ® UPDATE ® USE ® USER USING ® UTC_DATE ® UTC_TIME ® UTC_TIMESTAMP ® VALUE VALUES ® VARBINARY ® VARCHAR ® VARIABLES VIEW VIRTUAL ® WARNINGS WEEK WHEN ® WHERE ® WITH ® WRITE ® XOR ® YEAR YEAR_MONTH ® ZEROFILL ® "}, {"url": "https://pingcap.com/docs-cn/sql/miscellaneous-functions/", "title": "其他函数", "content": " 其他函数 函数名 功能描述 ANY_VALUE() 在 ONLY_FULL_GROUP_BY 模式下,防止带有 GROUP BY 的语句报错 SLEEP() 休眠指定秒数 UUID() 返回通用唯一识别码 (UUID) VALUES() 定义 INSERT 过程中要用到的值 INET_ATON() 将 IP 地址转换为数值 INET_NTOA() 将数值转换为 IP 地址 INET6_ATON() 将 IPv6 地址转换为数值 INET6_NTOA() 将数值转换为 IPv6 地址 IS_IPV4() 判断参数是否为 IPv4 地址 IS_IPV4_COMPAT() 判断参数是否为兼容 IPv4 的地址 IS_IPV4_MAPPED() 判断参数是否为 IPv4 映射的地址 IS_IPV6() 判断参数是否为 IPv6 地址 GET_LOCK() 获取命名锁,TiDB 出于兼容性支持这个函数,实际上不会做任何操作,这点和 MySQL 有区别 RELEASE_LOCK() 释放命名锁 "}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/miscellaneous-functions/", "title": "其他函数", "content": " 其他函数 函数名 功能描述 ANY_VALUE() 在 ONLY_FULL_GROUP_BY 模式下,防止带有 GROUP BY 的语句报错 SLEEP() 休眠指定秒数 UUID() 返回通用唯一识别码 (UUID) VALUES() 定义 INSERT 过程中要用到的值 INET_ATON() 将 IP 地址转换为数值 INET_NTOA() 将数值转换为 IP 地址 INET6_ATON() 将 IPv6 地址转换为数值 INET6_NTOA() 将数值转换为 IPv6 地址 IS_IPV4() 判断参数是否为 IPv4 地址 IS_IPV4_COMPAT() 判断参数是否为兼容 IPv4 的地址 IS_IPV4_MAPPED() 判断参数是否为 IPv4 映射的地址 IS_IPV6() 判断参数是否为 IPv6 地址 GET_LOCK() 获取命名锁,TiDB 出于兼容性支持这个函数,实际上不会做任何操作,这点和 MySQL 有区别 RELEASE_LOCK() 释放命名锁 "}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/miscellaneous-functions/", "title": "其他函数", "content": " 其他函数 函数名 功能描述 ANY_VALUE() 在 ONLY_FULL_GROUP_BY 模式下,防止带有 GROUP BY 的语句报错 SLEEP() 休眠指定秒数 UUID() 返回通用唯一识别码 (UUID) VALUES() 定义 INSERT 过程中要用到的值 INET_ATON() 将 IP 地址转换为数值 INET_NTOA() 将数值转换为 IP 地址 INET6_ATON() 将 IPv6 地址转换为数值 INET6_NTOA() 将数值转换为 IPv6 地址 IS_IPV4() 判断参数是否为 IPv4 地址 IS_IPV4_COMPAT() 判断参数是否为兼容 IPv4 的地址 IS_IPV4_MAPPED() 判断参数是否为 IPv4 映射的地址 IS_IPV6() 判断参数是否为 IPv6 地址 GET_LOCK() 获取命名锁,TiDB 出于兼容性支持这个函数,实际上不会做任何操作,这点和 MySQL 有区别 RELEASE_LOCK() 释放命名锁 "}, {"url": "https://pingcap.com/docs-cn/sql/functions-and-operators-reference/", "title": "函数和操作符概述", "content": " 函数和操作符概述 TiDB 中函数和操作符使用方法与 MySQL 基本一致,详情参见: Functions and Operators。在 SQL 语句中,表达式可用于诸如 SELECT 语句的 ORDER BY 或 HAVING 子句,SELECT/DELETE/UPDATE 语句的 WHERE 子句,或 SET 语句之类的地方。可使用字面值,列名,NULL,内置函数,操作符等来书写表达式。"}, {"url": "https://pingcap.com/recruit-cn/general-administrative/office-admin/", "title": "分公司行政主管", "content": " 分公司行政主管 岗位职责: 负责 Office 日常事务性工作,保障办公区域日常运转; 负责 Office 内部环境维护以及到访人员的接待; 负责公司办公场地租赁费用,水、电、宽带网络等费用结算、管理工作; 负责组织公司活动、对活动所需物品进行询价对比、采购工作; 负责 Office 相关人事工作,如新员工入离职手续办理,五险一金缴纳等; 完成上级领导安排的其他事项。 任职要求: 本科及以上学历,2 年以上互联网 / 软件 / IT企业人事行政相关经验; 学习能力强,工作细致认真,有较强的责任感; 可以接受周末 Oncall。 待遇:5K - 10K,13薪 + 奖金,优秀者可面议联系方式:hire@pingcap.com工作地点:杭州,深圳"}, {"url": "https://pingcap.com/docs-cn/sql/encryption-and-compression-functions/", "title": "加密和压缩函数", "content": " 加密和压缩函数 函数名 功能描述 MD5() 计算字符串的 MD5 校验和 PASSWORD() 计算并返回密码字符串 RANDOM_BYTES() 返回随机字节向量 SHA1(), SHA() 计算 SHA-1 160 位校验和 SHA2() 计算 SHA-2 校验和 AES_DECRYPT() 使用 AES 解密 AES_ENCRYPT() 使用 AES 加密 COMPRESS() 返回经过压缩的二进制字符串 UNCOMPRESS() 解压缩字符串 UNCOMPRESSED_LENGTH() 返回字符串解压后的长度 CREATE_ASYMMETRIC_PRIV_KEY() 创建私钥 CREATE_ASYMMETRIC_PUB_KEY() 创建公钥 CREATE_DH_PARAMETERS() 创建 DH 共享密钥 CREATE_DIGEST() 从字符串创建摘要 ASYMMETRIC_DECRYPT() 使用公钥或私钥解密密文 ASYMMETRIC_DERIVE() 从非对称密钥导出对称密钥 ASYMMETRIC_ENCRYPT() 使用公钥或私钥加密明文 ASYMMETRIC_SIGN() 从摘要创建签名 ASYMMETRIC_VERIFY() 验证签名字符串是否匹配摘要字符串 "}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/encryption-and-compression-functions/", "title": "加密和压缩函数", "content": " 加密和压缩函数 函数名 功能描述 MD5() 计算字符串的 MD5 校验和 PASSWORD()(在 MySQL 5.7.6 中已弃用) 计算并返回密码字符串 RANDOM_BYTES() 返回随机字节向量 SHA1(), SHA() 计算 SHA-1 160 位校验和 SHA2() 计算 SHA-2 校验和 AES_DECRYPT() 使用 AES 解密 AES_ENCRYPT() 使用 AES 加密 COMPRESS() 返回经过压缩的二进制字符串 UNCOMPRESS() 解压缩字符串 UNCOMPRESSED_LENGTH() 返回字符串解压后的长度 CREATE_ASYMMETRIC_PRIV_KEY() 创建私钥 CREATE_ASYMMETRIC_PUB_KEY() 创建公钥 CREATE_DH_PARAMETERS() 创建 DH 共享密钥 CREATE_DIGEST() 从字符串创建摘要 ASYMMETRIC_DECRYPT() 使用公钥或私钥解密密文 ASYMMETRIC_DERIVE() 从非对称密钥导出对称密钥 ASYMMETRIC_ENCRYPT() 使用公钥或私钥加密明文 ASYMMETRIC_SIGN() 从摘要创建签名 ASYMMETRIC_VERIFY() 验证签名字符串是否匹配摘要字符串 "}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/encryption-and-compression-functions/", "title": "加密和压缩函数", "content": " 加密和压缩函数 函数名 功能描述 MD5() 计算字符串的 MD5 校验和 PASSWORD()(在 MySQL 5.7.6 中已弃用) 计算并返回密码字符串 RANDOM_BYTES() 返回随机字节向量 SHA1(), SHA() 计算 SHA-1 160 位校验和 SHA2() 计算 SHA-2 校验和 AES_DECRYPT() 使用 AES 解密 AES_ENCRYPT() 使用 AES 加密 COMPRESS() 返回经过压缩的二进制字符串 UNCOMPRESS() 解压缩字符串 UNCOMPRESSED_LENGTH() 返回字符串解压后的长度 CREATE_ASYMMETRIC_PRIV_KEY() 创建私钥 CREATE_ASYMMETRIC_PUB_KEY() 创建公钥 CREATE_DH_PARAMETERS() 创建 DH 共享密钥 CREATE_DIGEST() 从字符串创建摘要 ASYMMETRIC_DECRYPT() 使用公钥或私钥解密密文 ASYMMETRIC_DERIVE() 从非对称密钥导出对称密钥 ASYMMETRIC_ENCRYPT() 使用公钥或私钥加密明文 ASYMMETRIC_SIGN() 从摘要创建签名 ASYMMETRIC_VERIFY() 验证签名字符串是否匹配摘要字符串 "}, {"url": "https://pingcap.com/docs-cn/sql/literal-value-hex-decimal/", "title": "十六进制字面值", "content": " 十六进制字面值 十六进制字面值是有 X 和 0x 前缀的字符串,后接表示十六进制的数字。注意 0x 是大小写敏感的,不能表示为 0X。例:X'ac12' X'12AC' x'ac12' x'12AC' 0xac12 0x12AC 以下是不合法的十六进制字面值:X'1z' (z 不是合法的十六进制值) 0X12AC (0X 必须用小写的 0x) 对于使用 X'val' 格式的十六进制字面值,val 必须要有一个数字,可以在前面补一个 0 来避免语法错误。mysql> select X'aff'; ERROR 1105 (HY000): line 0 column 13 near ""hex literal: invalid hexadecimal format, must even numbers, but 3 (total length 13) mysql> select X'0aff'; +---------+ | X'0aff' | +---------+ | | +---------+ 1 row in set (0.00 sec) 默认情况,十六进制字面值是一个二进制字符串。如果需要将一个字符串或者数字转换为十六进制字面值,可以使用内建函数 HEX():mysql> SELECT HEX('TiDB'); +-------------+ | HEX('TiDB') | +-------------+ | 54694442 | +-------------+ 1 row in set (0.01 sec) mysql> SELECT X'54694442'; +-------------+ | X'54694442' | +-------------+ | TiDB | +-------------+ 1 row in set (0.00 sec)"}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/literal-value-hex-decimal/", "title": "十六进制的字面值", "content": " Hexadecimal Literals 十六进制字面值是有 X 和 0x 前缀的字符串,后接表示十六进制的数字。注意 0x 是大小写敏感的,不能表示为 0X。例:X'ac12' X'12AC' x'ac12' x'12AC' 0xac12 0x12AC 以下是不合法的十六进制字面值:X'1z' (z 不是合法的十六进制值) 0X12AC (0X 必须用小写的 0x) 对于使用 X'val' 格式的十六进制字面值,val 必须要有一个数字,可以在前面补一个 0 来避免语法错误。mysql> select X'aff'; ERROR 1105 (HY000): line 0 column 13 near ""hex literal: invalid hexadecimal format, must even numbers, but 3 (total length 13) mysql> select X'0aff'; +---------+ | X'0aff' | +---------+ | | +---------+ 1 row in set (0.00 sec) 默认情况,十六进制字面值是一个二进制字符串。如果需要将一个字符串或者数字转换为十六进制字面值,可以使用内建函数 HEX():mysql> SELECT HEX('TiDB'); +-------------+ | HEX('TiDB') | +-------------+ | 54694442 | +-------------+ 1 row in set (0.01 sec) mysql> SELECT X'54694442'; +-------------+ | X'54694442' | +-------------+ | TiDB | +-------------+ 1 row in set (0.00 sec)"}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/literal-value-hex-decimal/", "title": "十六进制的字面值", "content": " Hexadecimal Literals 十六进制字面值是有 X 和 0x 前缀的字符串,后接表示十六进制的数字。注意 0x 是大小写敏感的,不能表示为 0X。例:X'ac12' X'12AC' x'ac12' x'12AC' 0xac12 0x12AC 以下是不合法的十六进制字面值:X'1z' (z 不是合法的十六进制值) 0X12AC (0X 必须用小写的 0x) 对于使用 X'val' 格式的十六进制字面值,val 必须要有一个数字,可以在前面补一个 0 来避免语法错误。mysql> select X'aff'; ERROR 1105 (HY000): line 0 column 13 near ""hex literal: invalid hexadecimal format, must even numbers, but 3 (total length 13) mysql> select X'0aff'; +---------+ | X'0aff' | +---------+ | | +---------+ 1 row in set (0.00 sec) 默认情况,十六进制字面值是一个二进制字符串。如果需要将一个字符串或者数字转换为十六进制字面值,可以使用内建函数 HEX():mysql> SELECT HEX('TiDB'); +-------------+ | HEX('TiDB') | +-------------+ | 54694442 | +-------------+ 1 row in set (0.01 sec) mysql> SELECT X'54694442'; +-------------+ | X'54694442' | +-------------+ | TiDB | +-------------+ 1 row in set (0.00 sec)"}, {"url": "https://pingcap.com/docs-cn/op-guide/configuration/", "title": "参数解释", "content": " 参数解释 TiDB -V 输出 TiDB 的版本 默认: “” --config 配置文件 默认: “” 如果你指定了配置文件,TiDB 会首先读取配置文件的配置。然后如果对应的配置在命令行参数里面也存在,TiDB 就会使用命令行参数的配置来覆盖配置文件里面的。详细的配置项可以看看这里 --store 用来指定 TiDB 底层使用的存储引擎 默认: “mocktikv” 你可以选择 “mocktikv” 或者 “tikv”。(mocktikv 是本地存储引擎,而 tikv 是一个分布式存储引擎) --path 对于本地存储引擎 “mocktikv” 来说,path 指定的是实际的数据存放路径 对于 --store = tikv 时必须指定path,--store = mocktikv 时,如果不指定 path,会使用默认值。 对于 “TiKV” 存储引擎来说,path 指定的是实际的 PD 地址。假设我们在 192.168.100.113:2379, 192.168.100.114:2379 和 192.168.100.115:2379 上面部署了 PD,那么 path 为 “192.168.100.113:2379, 192.168.100.114:2379, 192.168.100.115:2379” 默认: “/tmp/tidb” 我们可以通过 tidb-server --store=mocktikv --path="" 来启动一个纯内存引擎的 TiDB。 --advertise-address 登录 TiDB 的 IP 地址 默认: “” 这个 IP 地址必须确保用户和集群中的其他机器都能够访问到。 --host TiDB 服务监听 host 默认: “0.0.0.0” TiDB 服务会监听这个 host 0.0.0.0 默认会监听所有的网卡 address。如果有多块网卡,可以指定对外提供服务的网卡,譬如192.168.100.113 -P TiDB 服务监听端口 默认: “4000” TiDB 服务将会使用这个端口接受 MySQL 客户端发过来的请求 --socket string TiDB 服务使用 unix socket file 方式接受外部连接 默认: “” 譬如我们可以使用 “/tmp/tidb.sock” 来打开 unix socket file --binlog-socket TiDB 服务使用 unix socket file 方式接受内部连接,如 PUMP 服务 默认: “” 譬如我们可以使用 “/tmp/pump.sock” 来接受 PUMP unix socket file 通信 --run-ddl tidb-server 是否运行 DDL 语句,集群内大于两台以上 tidb-server 时设置 默认: true 值可以为 (true) 或者 (false). (true) 表明自身会运行 DDL. (false) 表明自身不会运行 DDL -L Log 级别 默认: “info” 我们能选择 debug, info, warn, error 或者 fatal --log-file Log 文件 默认: “” 如果没设置这个参数,log 会默认输出到 “stderr”,如果设置了,log 就会输出到对应的文件里面,在每天凌晨,log 会自动轮转使用一个新的文件,并且将以前的文件改名备份 --log-slow-query 慢查询日志文件路径 默认: “” 如果没有设置这个参数,log 会默认输出到 --log-file 指定的文件中。 --report-status 打开 (true) 或者关闭 (false) 服务状态监听端口 默认: true 值可以为 (true) 或者 (false). (true) 表明我们开启状态监听端口。 (false) 表明关闭 --status TiDB 服务状态监听端口 默认: “10080” 这个端口是为了展示 TiDB 内部数据用的。包括 prometheus 统计 以及 pprof Prometheus 统计可以通过 “http://host:status_port/metrics" 访问 Pprof 数据可以通过 “http://host:status_port/debug/pprof" 访问 --metrics-addr Prometheus Pushgateway 地址 默认: “” 如果为空,TiDB 不会将统计信息推送给 Pushgateway,参数格式 如 --metrics-addr=192.168.100.115:9091 --metrics-interval 推送统计信息到 Prometheus Pushgateway 的时间间隔 默认: 15s 设置为 0 表明不推送统计信息给 Pushgateway,如: --metrics-interval=2 是每两秒推送到 Pushgateway --token-limit TiDB 中同时允许运行的 Session 数量,用于流量控制。 默认: 1000 如果当前运行的连接多余这个 token-limit,那么请求会阻塞等待已经完成的操作释放 Token。 --proxy-protocol-networks PROXY Protocol 允许的代理服务器地址列表,如果需要配置多个地址用,分隔。 默认: “” 如果为空,TiDB 会禁用 PROXY Protocol 功能。地址可以使用 IP 地址(192.168.1.50)或者 CIDR (192.168.1.0/24),* 代表所有地址。 --proxy-protocol-header-timeout PROXY Protocol 请求头读取超时时间。 默认: 5 单位为秒。注意:请不要配置成0,除非特殊情况,一般使用默认值即可。 Placement Driver (PD) --advertise-client-urls 对外客户端访问 URL 列表 默认: ${client-urls} 在某些情况下,譬如 docker,或者 NAT 网络环境,客户端并不能通过 PD 自己监听的 client URLs 来访问到 PD,这时候,你就可以设置 advertise urls 来让客户端访问 例如,docker 内部 IP 地址为 172.17.0.1,而宿主机的 IP 地址为 192.168.100.113 并且设置了端口映射 -p 2379:2379,那么可以设置为 --advertise-client-urls=“http://192.168.100.113:2379",客户端可以通过 http://192.168.100.113:2379 来找到这个服务 --advertise-peer-urls 对外其他 PD 节点访问 URL 列表。 默认: ${peer-urls} 在某些情况下,譬如 docker,或者 NAT 网络环境,其他节点并不能通过 PD 自己监听的 peer URLs 来访问到 PD,这时候,你就可以设置 advertise urls 来让其他节点访问 例如,docker 内部 IP 地址为 172.17.0.1,而宿主机的 IP 地址为 192.168.100.113 并且设置了端口映射 -p 2380:2380,那么可以设置为 --advertise-peer-urls=“http://192.168.100.113:2380",其他 PD 节点可以通过 http://192.168.100.113:2380 来找到这个服务 --client-urls 处理客户端请求监听 URL 列表 默认: “http://127.0.0.1:2379" 如果部署一个集群,--client-urls 必须指定当前主机的 IP 地址,例如 “http://192.168.100.113:2379",如果是运行在 docker 则需要指定为 “http://0.0.0.0:2379" --peer-urls 处理其他 PD 节点请求监听 URL 列表。 default: “http://127.0.0.1:2380" 如果部署一个集群,--peer-urls 必须指定当前主机的 IP 地址,例如 “http://192.168.100.113:2380",如果是运行在 docker 则需要指定为 “http://0.0.0.0:2380" --config 配置文件 默认: “” 如果你指定了配置文件,PD 会首先读取配置文件的配置。然后如果对应的配置在命令行参数里面也存在,PD 就会使用命令行参数的配置来覆盖配置文件里面的 --data-dir PD 存储数据路径 默认: “default.${name}” --initial-cluster 初始化 PD 集群配置。 默认: “{name}=http://{advertise-peer-url}” 例如,如果 name 是 “pd”, 并且 advertise-peer-urls 是 “http://192.168.100.113:2380", 那么 initial-cluster 就是 pd=http://192.168.100.113:2380 如果你需要启动三台 PD,那么 initial-cluster 可能就是 pd1=http://192.168.100.113:2380, pd2=http://192.168.100.114:2380, pd3=192.168.100.115:2380 --join 动态加入 PD 集群 默认: “” 如果你想动态将一台 PD 加入集群,你可以使用 --join="${advertise-client-urls}", advertise-client-url 是当前集群里面任意 PD 的 advertise-client-url,你也可以使用多个 PD 的,需要用逗号分隔 -L Log 级别 默认: “info” 我们能选择 debug, info, warn, error 或者 fatal --log-file Log 文件 默认: “” 如果没设置这个参数,log 会默认输出到 “stderr”,如果设置了,log 就会输出到对应的文件里面,在每天凌晨,log 会自动轮转使用一个新的文件,并且将以前的文件改名备份 --log-rotate 是否开启日志切割 默认:true 当值为 true 时,按照 PD 配置文件中 [log.file] 信息执行。 --name 当前 PD 的名字 默认: “pd” 如果你需要启动多个 PD,一定要给 PD 使用不同的名字 --cacert CA 文件路径,用于开启 TLS。 默认: “” --cert 包含 X509 证书的 PEM 文件路径,用户开启 TLS。 默认: “” --key 包含 X509 key 的 PEM 文件路径,用于开启 TLS。 默认: “” --namespace-classifier 指定 PD 使用的 namespace 分类器。 默认: “table” 如果 TiKV 不与 TiDB 集群配合运行,建议配置为 ‘default’。 TiKV TiKV 在命令行参数上面支持一些可读性好的单位转换。 文件大小(以 bytes 为单位): KB, MB, GB, TB, PB(也可以全小写) 时间(以毫秒为单位): ms, s, m, h -A, --addr TiKV 监听地址 默认: “127.0.0.1:20160” 如果部署一个集群,--addr 必须指定当前主机的 IP 地址,例如 “192.168.100.113:20160”,如果是运行在 docker 则需要指定为 “0.0.0.0:20160” --advertise-addr TiKV 对外访问地址。 默认: ${addr} 在某些情况下,譬如 docker,或者 NAT 网络环境,客户端并不能通过 TiKV 自己监听的地址来访问到 TiKV,这时候,你就可以设置 advertise addr 来让 客户端访问 例如,docker 内部 IP 地址为 172.17.0.1,而宿主机的 IP 地址为 192.168.100.113 并且设置了端口映射 -p 20160:20160,那么可以设置为 --advertise-addr=“192.168.100.113:20160”,客户端可以通过 192.168.100.113:20160 来找到这个服务 -C, --config 配置文件 默认: “” 如果你指定了配置文件,TiKV 会首先读取配置文件的配置。然后如果对应的配置在命令行参数里面也存在,TiKV 就会使用命令行参数的配置来覆盖配置文件里面的 --capacity TiKV 存储数据的容量 默认: 0 (无限) PD 需要使用这个值来对整个集群做 balance 操作。(提示:你可以使用 10GB 来替代 10737418240,从而简化参数的传递) --data-dir TiKV 数据存储路径 默认: “/tmp/tikv/store” -L, --log Log 级别 默认: “info” 我们能选择 trace, debug, info, warn, error, 或者 off --log-file Log 文件 默认: “” 如果没设置这个参数,log 会默认输出到 “stderr”,如果设置了,log 就会输出到对应的文件里面,在每天凌晨,log 会自动轮转使用一个新的文件,并且将以前的文件改名备份 --pd PD 地址列表。 默认: “” TiKV 必须使用这个值连接 PD,才能正常工作。使用逗号来分隔多个 PD 地址,例如: 192.168.100.113:2379, 192.168.100.114:2379, 192.168.100.115:2379 "}, {"url": "https://pingcap.com/docs-cn/v1.0/op-guide/configuration/", "title": "参数解释", "content": " 参数解释 TiDB --binlog-socket TiDB 服务使用 unix socket file 方式接受内部连接,如 PUMP 服务 默认: “” 譬如我们可以使用 “/tmp/pump.sock” 来接受 PUMP unix socket file 通信 --cross-join 默认: true 在做 join 的时候,两边表没有任何条件(where 字段),默认可以执行这样的语句。但是设置为 false,则如有这样的 join 语句出现,server 会拒绝执行 --host TiDB 服务监听 host 默认: “0.0.0.0” TiDB 服务会监听这个 host 0.0.0.0 默认会监听所有的网卡 address。如果有多块网卡,可以指定对外提供服务的网卡,譬如192.168.100.113 --join-concurrency int join-concurrency 并发执行 join 的 goroutine 数量 默认: 5 看数据量和数据分布情况,一般情况下是越多越好,数值越大对 CPU 开销越大 -L Log 级别 默认: “info” 我们能选择 debug, info, warn, error 或者 fatal --lease Schema 的租约时间,单位:秒 默认: “10” Schema 的 lease 主要用在 online schema changes 上面。这个值会影响到实际的 DDL 语句的执行时间。千万不要随便改动这个值,除非你能知道相关的内部机制 --log-file Log 文件 默认: “” 如果没设置这个参数,log 会默认输出到 “stderr”,如果设置了,log 就会输出到对应的文件里面,在每天凌晨,log 会自动轮转使用一个新的文件,并且将以前的文件改名备份 --metrics-addr Prometheus Push Gateway 地址 默认: “” 如果为空,TiDB 不会将统计信息推送给 Push Gateway,参数格式 如 --metrics-addr=192.168.100.115:9091 --metrics-intervel 推送统计信息到 Prometheus Push Gateway 的时间间隔 默认: 15s 设置为 0 表明不推送统计信息给 Push Gateway,如: --metrics-interval=2 是每两秒推送到 Push Gataway -P TiDB 服务监听端口 默认: “4000” TiDB 服务将会使用这个端口接受 MySQL 客户端发过来的请求 --path 对于本地存储引擎 “goleveldb”, “BoltDB” 来说,path 指定的是实际的数据存放路径 对于 “memory” 存储引擎来说,path 不用设置 对于 “TiKV” 存储引擎来说,path 指定的是实际的 PD 地址。假设我们在 192.168.100.113:2379, 192.168.100.114:2379 和 192.168.100.115:2379 上面部署了 PD,那么 path 为 “192.168.100.113:2379, 192.168.100.114:2379, 192.168.100.115:2379” 默认: “/tmp/tidb” --perfschema 使用 true/false 来打开或者关闭性能 schema 默认: false 值可以是 (true) or (false)。性能 Schema 可以帮助我们在运行时检测内部的执行情况。可以通过 performance schema 获取更多信息。但需要注意,开启性能 Schema,会影响 TiDB 的性能 --privilege 使用 true/false 来打开或者关闭权限功能(用于开发调试) 默认: true 值可以是(true) or (false)。当前版本的权限控制还在完善中,将来会去掉此选项 --query-log-max-len int 日志中记录最大 sql 语句长度 默认: 2048 过长的请求输出到 log 时会被截断 --report-status 打开 (true) 或者关闭 (false) 服务状态监听端口 默认: true 值可以为 (true) 或者 (false). (true) 表明我们开启状态监听端口。 (false) 表明关闭 --retry-limit int 事务遇见冲突时,提交事物最大重试次数 默认: 10 设置较大的重试次数会影响 TiDB 集群性能 --run-ddl tidb-server 是否运行 DDL 语句,集群内大于两台以上 tidb-server 时设置 默认: true 值可以为 (true) 或者 (false). (true) 表明自身会运行 DDL. (false) 表明自身不会运行 DDL --proxy-protocol-networks PROXY Protocol 允许的代理服务器地址列表,如果需要配置多个地址用,分隔。 默认: “” 如果为空,TiDB 会禁用 PROXY Protocol 功能。地址可以使用 IP 地址(192.168.1.50)或者 CIDR (192.168.1.0/24),* 代表所有地址。 --proxy-protocol-header-timeout PROXY Protocol 请求头读取超时时间。 默认: 5 单位为秒。注意:请不要配置成0,除非特殊情况,一般使用默认值即可。 --skip-grant-table 允许任何人不带密码连接,并且所有的操作不检查权限 默认: false 值可以是(true) or (false)。启用此选项需要有本机的root权限,一般用于忘记密码时重置 --slow-threshold int 大于这个值得 sql 语句将被记录 默认: 300 值只能是一个整数 (int) ,单位是毫秒 --socket string TiDB 服务使用 unix socket file 方式接受外部连接 默认: “” 譬如我们可以使用 “/tmp/tidb.sock” 来打开 unix socket file --ssl-ca PEM 格式的受信任 CA 的证书文件路径 默认: “” 当同时设置了该选项和 --ssl-cert、--ssl-key 选项时,TiDB 将在客户端出示证书的情况下根据该选项指定的受信任的 CA 列表验证客户端证书。若验证失败,则连接会被终止。 即使设置了该选项,若客户端没有出示证书,则安全连接仍然继续,不会进行客户端证书验证。 --ssl-cert PEM 格式的 SSL 证书文件路径 默认: “” 当同时设置了该选项和 --ssl-key 选项时,TiDB 将接受(但不强制)客户端使用 TLS 安全地连接到 TiDB。 若指定的证书或私钥无效,则 TiDB 会照常启动,但无法接受安全连接。 --ssl-key PEM 格式的 SSL 证书密钥文件路径,即 --ssl-cert 所指定的证书的私钥 默认: “” 目前 TiDB 不支持加载由密码保护的私钥。 --status TiDB 服务状态监听端口 默认: “10080” 这个端口是为了展示 TiDB 内部数据用的。包括 prometheus 统计 以及 pprof Prometheus 统计可以通过 “http://host:status_port/metrics" 访问 Pprof 数据可以通过 “http://host:status_port/debug/pprof" 访问 --statsLease string 增量扫描全表并分析表的数据量 索引等一些信息 默认: 3s 使用此参数需要先手动执行 analyze table name; 自动更新统计信息,持久化存储到tikv,会耗费一些内存开销, --store 用来指定 TiDB 底层使用的存储引擎 默认: “goleveldb” 你可以选择 “memory”, “goleveldb”, “BoltDB” 或者 “TiKV”。(前面三个是本地存储引擎,而 TiKV 是一个分布式存储引擎) 例如,如果我们可以通过 tidb-server --store=memory 来启动一个纯内存引擎的 TiDB --tcp-keep-alive TiDB 在 tcp 层开启 keepalive 默认: false Placement Driver (PD) --advertise-client-urls 对外客户端访问 URL 列表 默认: ${client-urls} 在某些情况下,譬如 docker,或者 NAT 网络环境,客户端并不能通过 PD 自己监听的 client URLs 来访问到 PD,这时候,你就可以设置 advertise urls 来让客户端访问 例如,docker 内部 IP 地址为 172.17.0.1,而宿主机的 IP 地址为 192.168.100.113 并且设置了端口映射 -p 2379:2379,那么可以设置为 --advertise-client-urls=“http://192.168.100.113:2379",客户端可以通过 http://192.168.100.113:2379 来找到这个服务 --advertise-peer-urls 对外其他 PD 节点访问 URL 列表。 默认: ${peer-urls} 在某些情况下,譬如 docker,或者 NAT 网络环境,其他节点并不能通过 PD 自己监听的 peer URLs 来访问到 PD,这时候,你就可以设置 advertise urls 来让其他节点访问 例如,docker 内部 IP 地址为 172.17.0.1,而宿主机的 IP 地址为 192.168.100.113 并且设置了端口映射 -p 2380:2380,那么可以设置为 --advertise-peer-urls=“http://192.168.100.113:2380",其他 PD 节点可以通过 http://192.168.100.113:2380 来找到这个服务 --client-urls 处理客户端请求监听 URL 列表 默认: “http://127.0.0.1:2379" 如果部署一个集群,--client-urls 必须指定当前主机的 IP 地址,例如 “http://192.168.100.113:2379",如果是运行在 docker 则需要指定为 “http://0.0.0.0:2379" --config 配置文件 默认: “” 如果你指定了配置文件,PD 会首先读取配置文件的配置。然后如果对应的配置在命令行参数里面也存在,PD 就会使用命令行参数的配置来覆盖配置文件里面的 --data-dir PD 存储数据路径 默认: “default.${name}” --initial-cluster 初始化 PD 集群配置。 默认: “{name}=http://{advertise-peer-url}” 例如,如果 name 是 “pd”, 并且 advertise-peer-urls 是 “http://192.168.100.113:2380", 那么 initial-cluster 就是 pd=http://192.168.100.113:2380 如果你需要启动三台 PD,那么 initial-cluster 可能就是 pd1=http://192.168.100.113:2380, pd2=http://192.168.100.114:2380, pd3=192.168.100.115:2380 --join 动态加入 PD 集群 默认: “” 如果你想动态将一台 PD 加入集群,你可以使用 --join="${advertise-client-urls}", advertise-client-url 是当前集群里面任意 PD 的 advertise-client-url,你也可以使用多个 PD 的,需要用逗号分隔 -L Log 级别 默认: “info” 我们能选择 debug, info, warn, error 或者 fatal --log-file Log 文件 默认: “” 如果没设置这个参数,log 会默认输出到 “stderr”,如果设置了,log 就会输出到对应的文件里面,在每天凌晨,log 会自动轮转使用一个新的文件,并且将以前的文件改名备份 --log-rotate 是否开启日志切割 默认:true 当值为 true 时,按照 PD 配置文件中 [log.file] 信息执行。 --name 当前 PD 的名字 默认: “pd” 如果你需要启动多个 PD,一定要给 PD 使用不同的名字 --peer-urls 处理其他 PD 节点请求监听 URL 列表。 default: “http://127.0.0.1:2380" 如果部署一个集群,--peer-urls 必须指定当前主机的 IP 地址,例如 “http://192.168.100.113:2380",如果是运行在 docker 则需要指定为 “http://0.0.0.0:2380" TiKV TiKV 在命令行参数上面支持一些可读性好的单位转换。 文件大小(以 bytes 为单位): KB, MB, GB, TB, PB(也可以全小写) 时间(以毫秒为单位): ms, s, m, h -A, --addr TiKV 监听地址 默认: “127.0.0.1:20160” 如果部署一个集群,--addr 必须指定当前主机的 IP 地址,例如 “192.168.100.113:20160”,如果是运行在 docker 则需要指定为 “0.0.0.0:20160” --advertise-addr TiKV 对外访问地址。 默认: ${addr} 在某些情况下,譬如 docker,或者 NAT 网络环境,客户端并不能通过 TiKV 自己监听的地址来访问到 TiKV,这时候,你就可以设置 advertise addr 来让 客户端访问 例如,docker 内部 IP 地址为 172.17.0.1,而宿主机的 IP 地址为 192.168.100.113 并且设置了端口映射 -p 20160:20160,那么可以设置为 --advertise-addr=“192.168.100.113:20160”,客户端可以通过 192.168.100.113:20160 来找到这个服务 -C, --config 配置文件 默认: “” 如果你指定了配置文件,TiKV 会首先读取配置文件的配置。然后如果对应的配置在命令行参数里面也存在,TiKV 就会使用命令行参数的配置来覆盖配置文件里面的 --capacity TiKV 存储数据的容量 默认: 0 (无限) PD 需要使用这个值来对整个集群做 balance 操作。(提示:你可以使用 10GB 来替代 10737418240,从而简化参数的传递) --data-dir TiKV 数据存储路径 默认: “/tmp/tikv/store” -L, --log Log 级别 默认: “info” 我们能选择 trace, debug, info, warn, error, 或者 off --log-file Log 文件 默认: “” 如果没设置这个参数,log 会默认输出到 “stderr”,如果设置了,log 就会输出到对应的文件里面,在每天凌晨,log 会自动轮转使用一个新的文件,并且将以前的文件改名备份 --pd PD 地址列表。 默认: “” TiKV 必须使用这个值连接 PD,才能正常工作。使用逗号来分隔多个 PD 地址,例如: 192.168.100.113:2379, 192.168.100.114:2379, 192.168.100.115:2379 "}, {"url": "https://pingcap.com/docs-cn/v2.0/op-guide/configuration/", "title": "参数解释", "content": " 参数解释 TiDB --binlog-socket TiDB 服务使用 unix socket file 方式接受内部连接,如 PUMP 服务 默认: “” 譬如我们可以使用 “/tmp/pump.sock” 来接受 PUMP unix socket file 通信 --cross-join 默认: true 在做 join 的时候,两边表没有任何条件(where 字段),默认可以执行这样的语句。但是设置为 false,则如有这样的 join 语句出现,server 会拒绝执行 --host TiDB 服务监听 host 默认: “0.0.0.0” TiDB 服务会监听这个 host 0.0.0.0 默认会监听所有的网卡 address。如果有多块网卡,可以指定对外提供服务的网卡,譬如192.168.100.113 --join-concurrency int join-concurrency 并发执行 join 的 goroutine 数量 默认: 5 看数据量和数据分布情况,一般情况下是越多越好,数值越大对 CPU 开销越大 -L Log 级别 默认: “info” 我们能选择 debug, info, warn, error 或者 fatal --lease Schema 的租约时间,单位:秒 默认: “10” Schema 的 lease 主要用在 online schema changes 上面。这个值会影响到实际的 DDL 语句的执行时间。千万不要随便改动这个值,除非你能知道相关的内部机制 --log-file Log 文件 默认: “” 如果没设置这个参数,log 会默认输出到 “stderr”,如果设置了,log 就会输出到对应的文件里面,在每天凌晨,log 会自动轮转使用一个新的文件,并且将以前的文件改名备份 --metrics-addr Prometheus Push Gateway 地址 默认: “” 如果为空,TiDB 不会将统计信息推送给 Push Gateway,参数格式 如 --metrics-addr=192.168.100.115:9091 --metrics-intervel 推送统计信息到 Prometheus Push Gateway 的时间间隔 默认: 15s 设置为 0 表明不推送统计信息给 Push Gateway,如: --metrics-interval=2 是每两秒推送到 Push Gataway -P TiDB 服务监听端口 默认: “4000” TiDB 服务将会使用这个端口接受 MySQL 客户端发过来的请求 --path 对于本地存储引擎 “goleveldb”, “BoltDB” 来说,path 指定的是实际的数据存放路径 对于 “memory” 存储引擎来说,path 不用设置 对于 “TiKV” 存储引擎来说,path 指定的是实际的 PD 地址。假设我们在 192.168.100.113:2379, 192.168.100.114:2379 和 192.168.100.115:2379 上面部署了 PD,那么 path 为 “192.168.100.113:2379, 192.168.100.114:2379, 192.168.100.115:2379” 默认: “/tmp/tidb” --perfschema 使用 true/false 来打开或者关闭性能 schema 默认: false 值可以是 (true) or (false)。性能 Schema 可以帮助我们在运行时检测内部的执行情况。可以通过 performance schema 获取更多信息。但需要注意,开启性能 Schema,会影响 TiDB 的性能 --privilege 使用 true/false 来打开或者关闭权限功能(用于开发调试) 默认: true 值可以是(true) or (false)。当前版本的权限控制还在完善中,将来会去掉此选项 --query-log-max-len int 日志中记录最大 sql 语句长度 默认: 2048 过长的请求输出到 log 时会被截断 --report-status 打开 (true) 或者关闭 (false) 服务状态监听端口 默认: true 值可以为 (true) 或者 (false). (true) 表明我们开启状态监听端口。 (false) 表明关闭 --retry-limit int 事务遇见冲突时,提交事物最大重试次数 默认: 10 设置较大的重试次数会影响 TiDB 集群性能 --run-ddl tidb-server 是否运行 DDL 语句,集群内大于两台以上 tidb-server 时设置 默认: true 值可以为 (true) 或者 (false). (true) 表明自身会运行 DDL. (false) 表明自身不会运行 DDL --proxy-protocol-networks PROXY Protocol 允许的代理服务器地址列表,如果需要配置多个地址用,分隔。 默认: “” 如果为空,TiDB 会禁用 PROXY Protocol 功能。地址可以使用 IP 地址(192.168.1.50)或者 CIDR (192.168.1.0/24),* 代表所有地址。 --proxy-protocol-header-timeout PROXY Protocol 请求头读取超时时间。 默认: 5 单位为秒。注意:请不要配置成0,除非特殊情况,一般使用默认值即可。 --skip-grant-table 允许任何人不带密码连接,并且所有的操作不检查权限 默认: false 值可以是(true) or (false)。启用此选项需要有本机的root权限,一般用于忘记密码时重置 --slow-threshold int 大于这个值得 sql 语句将被记录 默认: 300 值只能是一个整数 (int) ,单位是毫秒 --socket string TiDB 服务使用 unix socket file 方式接受外部连接 默认: “” 譬如我们可以使用 “/tmp/tidb.sock” 来打开 unix socket file --ssl-ca PEM 格式的受信任 CA 的证书文件路径 默认: “” 当同时设置了该选项和 --ssl-cert、--ssl-key 选项时,TiDB 将在客户端出示证书的情况下根据该选项指定的受信任的 CA 列表验证客户端证书。若验证失败,则连接会被终止。 即使设置了该选项,若客户端没有出示证书,则安全连接仍然继续,不会进行客户端证书验证。 --ssl-cert PEM 格式的 SSL 证书文件路径 默认: “” 当同时设置了该选项和 --ssl-key 选项时,TiDB 将接受(但不强制)客户端使用 TLS 安全地连接到 TiDB。 若指定的证书或私钥无效,则 TiDB 会照常启动,但无法接受安全连接。 --ssl-key PEM 格式的 SSL 证书密钥文件路径,即 --ssl-cert 所指定的证书的私钥 默认: “” 目前 TiDB 不支持加载由密码保护的私钥。 --status TiDB 服务状态监听端口 默认: “10080” 这个端口是为了展示 TiDB 内部数据用的。包括 prometheus 统计 以及 pprof Prometheus 统计可以通过 “http://host:status_port/metrics" 访问 Pprof 数据可以通过 “http://host:status_port/debug/pprof" 访问 --statsLease string 增量扫描全表并分析表的数据量 索引等一些信息 默认: 3s 使用此参数需要先手动执行 analyze table name; 自动更新统计信息,持久化存储到tikv,会耗费一些内存开销, --store 用来指定 TiDB 底层使用的存储引擎 默认: “goleveldb” 你可以选择 “memory”, “goleveldb”, “BoltDB” 或者 “TiKV”。(前面三个是本地存储引擎,而 TiKV 是一个分布式存储引擎) 例如,如果我们可以通过 tidb-server --store=memory 来启动一个纯内存引擎的 TiDB --tcp-keep-alive TiDB 在 tcp 层开启 keepalive 默认: false Placement Driver (PD) --advertise-client-urls 对外客户端访问 URL 列表 默认: ${client-urls} 在某些情况下,譬如 docker,或者 NAT 网络环境,客户端并不能通过 PD 自己监听的 client URLs 来访问到 PD,这时候,你就可以设置 advertise urls 来让客户端访问 例如,docker 内部 IP 地址为 172.17.0.1,而宿主机的 IP 地址为 192.168.100.113 并且设置了端口映射 -p 2379:2379,那么可以设置为 --advertise-client-urls=“http://192.168.100.113:2379",客户端可以通过 http://192.168.100.113:2379 来找到这个服务 --advertise-peer-urls 对外其他 PD 节点访问 URL 列表。 默认: ${peer-urls} 在某些情况下,譬如 docker,或者 NAT 网络环境,其他节点并不能通过 PD 自己监听的 peer URLs 来访问到 PD,这时候,你就可以设置 advertise urls 来让其他节点访问 例如,docker 内部 IP 地址为 172.17.0.1,而宿主机的 IP 地址为 192.168.100.113 并且设置了端口映射 -p 2380:2380,那么可以设置为 --advertise-peer-urls=“http://192.168.100.113:2380",其他 PD 节点可以通过 http://192.168.100.113:2380 来找到这个服务 --client-urls 处理客户端请求监听 URL 列表 默认: “http://127.0.0.1:2379" 如果部署一个集群,--client-urls 必须指定当前主机的 IP 地址,例如 “http://192.168.100.113:2379",如果是运行在 docker 则需要指定为 “http://0.0.0.0:2379" --config 配置文件 默认: “” 如果你指定了配置文件,PD 会首先读取配置文件的配置。然后如果对应的配置在命令行参数里面也存在,PD 就会使用命令行参数的配置来覆盖配置文件里面的 --data-dir PD 存储数据路径 默认: “default.${name}” --initial-cluster 初始化 PD 集群配置。 默认: “{name}=http://{advertise-peer-url}” 例如,如果 name 是 “pd”, 并且 advertise-peer-urls 是 “http://192.168.100.113:2380", 那么 initial-cluster 就是 pd=http://192.168.100.113:2380 如果你需要启动三台 PD,那么 initial-cluster 可能就是 pd1=http://192.168.100.113:2380, pd2=http://192.168.100.114:2380, pd3=192.168.100.115:2380 --join 动态加入 PD 集群 默认: “” 如果你想动态将一台 PD 加入集群,你可以使用 --join="${advertise-client-urls}", advertise-client-url 是当前集群里面任意 PD 的 advertise-client-url,你也可以使用多个 PD 的,需要用逗号分隔 -L Log 级别 默认: “info” 我们能选择 debug, info, warn, error 或者 fatal --log-file Log 文件 默认: “” 如果没设置这个参数,log 会默认输出到 “stderr”,如果设置了,log 就会输出到对应的文件里面,在每天凌晨,log 会自动轮转使用一个新的文件,并且将以前的文件改名备份 --log-rotate 是否开启日志切割 默认:true 当值为 true 时,按照 PD 配置文件中 [log.file] 信息执行。 --name 当前 PD 的名字 默认: “pd” 如果你需要启动多个 PD,一定要给 PD 使用不同的名字 --peer-urls 处理其他 PD 节点请求监听 URL 列表。 default: “http://127.0.0.1:2380" 如果部署一个集群,--peer-urls 必须指定当前主机的 IP 地址,例如 “http://192.168.100.113:2380",如果是运行在 docker 则需要指定为 “http://0.0.0.0:2380" TiKV TiKV 在命令行参数上面支持一些可读性好的单位转换。 文件大小(以 bytes 为单位): KB, MB, GB, TB, PB(也可以全小写) 时间(以毫秒为单位): ms, s, m, h -A, --addr TiKV 监听地址 默认: “127.0.0.1:20160” 如果部署一个集群,--addr 必须指定当前主机的 IP 地址,例如 “192.168.100.113:20160”,如果是运行在 docker 则需要指定为 “0.0.0.0:20160” --advertise-addr TiKV 对外访问地址。 默认: ${addr} 在某些情况下,譬如 docker,或者 NAT 网络环境,客户端并不能通过 TiKV 自己监听的地址来访问到 TiKV,这时候,你就可以设置 advertise addr 来让 客户端访问 例如,docker 内部 IP 地址为 172.17.0.1,而宿主机的 IP 地址为 192.168.100.113 并且设置了端口映射 -p 20160:20160,那么可以设置为 --advertise-addr=“192.168.100.113:20160”,客户端可以通过 192.168.100.113:20160 来找到这个服务 -C, --config 配置文件 默认: “” 如果你指定了配置文件,TiKV 会首先读取配置文件的配置。然后如果对应的配置在命令行参数里面也存在,TiKV 就会使用命令行参数的配置来覆盖配置文件里面的 --capacity TiKV 存储数据的容量 默认: 0 (无限) PD 需要使用这个值来对整个集群做 balance 操作。(提示:你可以使用 10GB 来替代 10737418240,从而简化参数的传递) --data-dir TiKV 数据存储路径 默认: “/tmp/tikv/store” -L, --log Log 级别 默认: “info” 我们能选择 trace, debug, info, warn, error, 或者 off --log-file Log 文件 默认: “” 如果没设置这个参数,log 会默认输出到 “stderr”,如果设置了,log 就会输出到对应的文件里面,在每天凌晨,log 会自动轮转使用一个新的文件,并且将以前的文件改名备份 --pd PD 地址列表。 默认: “” TiKV 必须使用这个值连接 PD,才能正常工作。使用逗号来分隔多个 PD 地址,例如: 192.168.100.113:2379, 192.168.100.114:2379, 192.168.100.115:2379 "}, {"url": "https://pingcap.com/docs-cn/op-guide/backup-restore/", "title": "备份与恢复", "content": " 备份与恢复 概述 该文档详细介绍了如何对 TiDB 进行备份恢复。本文档暂时只考虑全量备份与恢复。这里我们假定 TiDB 服务信息如下: Name Address Port User Password TiDB 127.0.0.1 4000 root * 在这个备份恢复过程中,我们会用到下面的工具: mydumper 从 TiDB 导出数据 loader 导入数据到 TiDB 下载 TiDB 工具集 (Linux) # 下载 tool 压缩包 wget http://download.pingcap.org/tidb-enterprise-tools-latest-linux-amd64.tar.gz wget http://download.pingcap.org/tidb-enterprise-tools-latest-linux-amd64.sha256 # 检查文件完整性,返回 ok 则正确 sha256sum -c tidb-enterprise-tools-latest-linux-amd64.sha256 # 解开压缩包 tar -xzf tidb-enterprise-tools-latest-linux-amd64.tar.gz cd tidb-enterprise-tools-latest-linux-amd64 使用 mydumper/loader 全量备份恢复数据 mydumper 是一个强大的数据备份工具,具体可以参考 https://github.com/maxbube/mydumper。可使用 mydumper 从 TiDB 导出数据进行备份,然后用 loader 将其导入到 TiDB 里面进行恢复。 注意:必须使用企业版工具集包的 mydumper,不要使用你的操作系统的包管理工具提供的 mydumper。mydumper 的上游版本并不能对 TiDB 进行正确处理 (#155)。由于使用 mysqldump 进行数据备份和恢复都要耗费许多时间,这里也并不推荐。 mydumper/loader 全量备份恢复最佳实践 为了快速的备份恢复数据 (特别是数据量巨大的库), 可以参考以下建议: 使用 mydumper 导出来的数据文件尽可能的小, 最好不要超过 64M, 可以设置参数 -F 64 loader的 -t 参数可以根据 tikv 的实例个数以及负载进行评估调整,例如 3个 tikv 的场景, 此值可以设为 3 *(1 ~ n);当 tikv 负载过高,loader 以及 tidb 日志中出现大量 backoffer.maxSleep 15000ms is exceeded 可以适当调小该值,当 tikv 负载不是太高的时候,可以适当调大该值。 某次数据恢复示例,以及相关的配置 mydumper 导出后总数据量 214G,单表 8 列,20 亿行数据 集群拓扑 TIKV * 12 TIDB * 4 PD * 3 mydumper -F 设置为 16, loader -t 参数 64 结果:导入时间 11 小时左右,19.4 G/小时从 TiDB 备份数据 我们使用 mydumper 从 TiDB 备份数据,如下:./bin/mydumper -h 127.0.0.1 -P 4000 -u root -t 16 -F 64 -B test -T t1,t2 --skip-tz-utc -o ./var/test 上面,我们使用 -B test 表明是对 test 这个 database 操作,然后用 -T t1,t2 表明只导出 t1,t2 两张表。-t 16 表明使用 16 个线程去导出数据。-F 64 是将实际的 table 切分成多大的 chunk,这里就是 64MB 一个 chunk。--skip-tz-utc 添加这个参数忽略掉 TiDB 与导数据的机器之间时区设置不一致的情况,禁止自动转换。向 TiDB 恢复数据 我们使用 loader 将之前导出的数据导入到 TiDB,完成恢复操作。Loader 的下载和具体的使用方法见 Loader 使用文档./bin/loader -h 127.0.0.1 -u root -P 4000 -t 32 -d ./var/test 导入成功之后,我们可以用 MySQL 官方客户端进入 TiDB,查看:mysql -h127.0.0.1 -P4000 -uroot mysql> show tables; +----------------+ | Tables_in_test | +----------------+ | t1 | | t2 | +----------------+ mysql> select * from t1; +----+------+ | id | age | +----+------+ | 1 | 1 | | 2 | 2 | | 3 | 3 | +----+------+ mysql> select * from t2; +----+------+ | id | name | +----+------+ | 1 | a | | 2 | b | | 3 | c | +----+------+"}, {"url": "https://pingcap.com/docs-cn/v1.0/op-guide/backup-restore/", "title": "备份与恢复", "content": " 备份与恢复 概述 该文档详细介绍了如何对 TiDB 进行备份恢复。本文档暂时只考虑全量备份与恢复。这里我们假定 TiDB 服务信息如下: Name Address Port User Password TiDB 127.0.0.1 4000 root * 在这个备份恢复过程中,我们会用到下面的工具: mydumper 从 TiDB 导出数据 loader 导入数据到 TiDB 下载 TiDB 工具集 (Linux) # 下载 tool 压缩包 wget http://download.pingcap.org/tidb-enterprise-tools-latest-linux-amd64.tar.gz wget http://download.pingcap.org/tidb-enterprise-tools-latest-linux-amd64.sha256 # 检查文件完整性,返回 ok 则正确 sha256sum -c tidb-enterprise-tools-latest-linux-amd64.sha256 # 解开压缩包 tar -xzf tidb-enterprise-tools-latest-linux-amd64.tar.gz cd tidb-enterprise-tools-latest-linux-amd64 使用 mydumper/loader 全量备份恢复数据 mydumper 是一个强大的数据备份工具,具体可以参考 https://github.com/maxbube/mydumper。我们使用 mydumper 从 TiDB 导出数据进行备份,然后用 loader 将其导入到 TiDB 里面进行恢复。 注意:虽然 TiDB 也支持使用 MySQL 官方的 mysqldump 工具来进行数据的备份恢复工作,但相比于 mydumper / loader,性能会慢很多,大量数据的备份恢复会花费很多时间,这里我们并不推荐。 mydumper/loader 全量备份恢复最佳实践 为了快速的备份恢复数据 (特别是数据量巨大的库), 可以参考下面建议 使用 mydumper 导出来的数据文件尽可能的小, 最好不要超过 64M, 可以设置参数 -F 64 loader的 -t 参数可以根据 tikv 的实例个数以及负载进行评估调整,例如 3个 tikv 的场景, 此值可以设为 3 *(1 ~ n);当 tikv 负载过高,loader 以及 tidb 日志中出现大量 backoffer.maxSleep 15000ms is exceeded 可以适当调小该值,当 tikv 负载不是太高的时候,可以适当调大该值。 某次数据恢复示例,以及相关的配置 mydumper 导出后总数据量 214G,单表 8 列,20 亿行数据 集群拓扑 TIKV * 12 TIDB * 4 PD * 3 mydumper -F 设置为 16, loader -t 参数 64 结果:导入时间 11 小时左右,19.4 G/小时从 TiDB 备份数据 我们使用 mydumper 从 TiDB 备份数据,如下:./bin/mydumper -h 127.0.0.1 -P 4000 -u root -t 16 -F 64 -B test -T t1,t2 --skip-tz-utc -o ./var/test 上面,我们使用 -B test 表明是对 test 这个 database 操作,然后用 -T t1,t2 表明只导出 t1,t2 两张表。-t 16 表明使用 16 个线程去导出数据。-F 64 是将实际的 table 切分成多大的 chunk,这里就是 64MB 一个 chunk。--skip-tz-utc 添加这个参数忽略掉 TiDB 与导数据的机器之间时区设置不一致的情况,禁止自动转换。向 TiDB 恢复数据 我们使用 loader 将之前导出的数据导入到 TiDB,完成恢复操作。Loader 的下载和具体的使用方法见 Loader 使用文档./bin/loader -h 127.0.0.1 -u root -P 4000 -t 32 -d ./var/test 导入成功之后,我们可以用 MySQL 官方客户端进入 TiDB,查看:mysql -h127.0.0.1 -P4000 -uroot mysql> show tables; +----------------+ | Tables_in_test | +----------------+ | t1 | | t2 | +----------------+ mysql> select * from t1; +----+------+ | id | age | +----+------+ | 1 | 1 | | 2 | 2 | | 3 | 3 | +----+------+ mysql> select * from t2; +----+------+ | id | name | +----+------+ | 1 | a | | 2 | b | | 3 | c | +----+------+"}, {"url": "https://pingcap.com/docs-cn/v2.0/op-guide/backup-restore/", "title": "备份与恢复", "content": " 备份与恢复 概述 该文档详细介绍了如何对 TiDB 进行备份恢复。本文档暂时只考虑全量备份与恢复。这里我们假定 TiDB 服务信息如下: Name Address Port User Password TiDB 127.0.0.1 4000 root * 在这个备份恢复过程中,我们会用到下面的工具: mydumper 从 TiDB 导出数据 loader 导入数据到 TiDB 下载 TiDB 工具集 (Linux) # 下载 tool 压缩包 wget http://download.pingcap.org/tidb-enterprise-tools-latest-linux-amd64.tar.gz wget http://download.pingcap.org/tidb-enterprise-tools-latest-linux-amd64.sha256 # 检查文件完整性,返回 ok 则正确 sha256sum -c tidb-enterprise-tools-latest-linux-amd64.sha256 # 解开压缩包 tar -xzf tidb-enterprise-tools-latest-linux-amd64.tar.gz cd tidb-enterprise-tools-latest-linux-amd64 使用 mydumper/loader 全量备份恢复数据 mydumper 是一个强大的数据备份工具,具体可以参考 https://github.com/maxbube/mydumper。我们使用 mydumper 从 TiDB 导出数据进行备份,然后用 loader 将其导入到 TiDB 里面进行恢复。 注意:虽然 TiDB 也支持使用 MySQL 官方的 mysqldump 工具来进行数据的备份恢复工作,但相比于 mydumper / loader,性能会慢很多,大量数据的备份恢复会花费很多时间,这里我们并不推荐。 mydumper/loader 全量备份恢复最佳实践 为了快速的备份恢复数据 (特别是数据量巨大的库), 可以参考下面建议 使用 mydumper 导出来的数据文件尽可能的小, 最好不要超过 64M, 可以设置参数 -F 64 loader的 -t 参数可以根据 tikv 的实例个数以及负载进行评估调整,例如 3个 tikv 的场景, 此值可以设为 3 *(1 ~ n);当 tikv 负载过高,loader 以及 tidb 日志中出现大量 backoffer.maxSleep 15000ms is exceeded 可以适当调小该值,当 tikv 负载不是太高的时候,可以适当调大该值。 某次数据恢复示例,以及相关的配置 mydumper 导出后总数据量 214G,单表 8 列,20 亿行数据 集群拓扑 TIKV * 12 TIDB * 4 PD * 3 mydumper -F 设置为 16, loader -t 参数 64 结果:导入时间 11 小时左右,19.4 G/小时从 TiDB 备份数据 我们使用 mydumper 从 TiDB 备份数据,如下:./bin/mydumper -h 127.0.0.1 -P 4000 -u root -t 16 -F 64 -B test -T t1,t2 --skip-tz-utc -o ./var/test 上面,我们使用 -B test 表明是对 test 这个 database 操作,然后用 -T t1,t2 表明只导出 t1,t2 两张表。-t 16 表明使用 16 个线程去导出数据。-F 64 是将实际的 table 切分成多大的 chunk,这里就是 64MB 一个 chunk。--skip-tz-utc 添加这个参数忽略掉 TiDB 与导数据的机器之间时区设置不一致的情况,禁止自动转换。向 TiDB 恢复数据 我们使用 loader 将之前导出的数据导入到 TiDB,完成恢复操作。Loader 的下载和具体的使用方法见 Loader 使用文档./bin/loader -h 127.0.0.1 -u root -P 4000 -t 32 -d ./var/test 导入成功之后,我们可以用 MySQL 官方客户端进入 TiDB,查看:mysql -h127.0.0.1 -P4000 -uroot mysql> show tables; +----------------+ | Tables_in_test | +----------------+ | t1 | | t2 | +----------------+ mysql> select * from t1; +----+------+ | id | age | +----+------+ | 1 | 1 | | 2 | 2 | | 3 | 3 | +----+------+ mysql> select * from t2; +----+------+ | id | name | +----+------+ | 1 | a | | 2 | b | | 3 | c | +----+------+"}, {"url": "https://pingcap.com/docs-cn/sql/string-functions/", "title": "字符串函数", "content": " 字符串函数 函数名 功能描述 ASCII() 返回最左字符的数值 CHAR() 返回由整数的代码值所给出的字符组成的字符串 BIN() 返回一个数的二进制值的字符串表示 HEX() 返回十进制值或字符串值的十六进制表示 OCT() 返回一个数的八进制值的字符串表示 UNHEX() 返回 HEX 表示的数字所代表的字符串 TO_BASE64() 返回转换为 BASE64 的字符串参数 FROM_BASE64() 解码为 BASE64 的字符串并返回结果 LOWER() 返回小写字母的字符 LCASE() 与 LOWER() 功能相同 UPPER() 返回大写字母的字符 UCASE() 与 UPPER() 功能相同 LPAD() 返回左边由指定字符串填充的字符串参数 RPAD() 返回右边由指定字符串填充的字符串参数 TRIM() 删除字符串的前缀和后缀 LTRIM() 删除前面的空格字符 RTRIM() 删除结尾的空格字符 BIT_LENGTH() 返回字符串的位长度 CHAR_LENGTH() 返回字符串的字符长度 CHARACTER_LENGTH() 与 CHAR_LENGTH() 功能相同 LENGTH() 返回字符串的字节长度 OCTET_LENGTH() 与 LENGTH() 功能相同 INSERT() 在指定位置插入一个子字符串,直到指定的字符数 REPLACE() 替换指定的字符串 SUBSTR() 返回指定的子字符串 SUBSTRING() 返回指定的子字符串 SUBSTRING_INDEX() 返回最终定界符左边或右边的子字符串 MID() 返回从指定位置开始的子字符串 LEFT() 返回指定的最左字符 RIGHT() 返回指定的最右字符 INSTR() 返回子字符串的第一个出现位置 LOCATE() 返回子字符串的第一个出现位置,与 INSTR() 的参数位置相反 POSITION() 与 LOCATE() 功能相同 REPEAT() 返回重复指定次数的字符串 CONCAT() 返回连接的字符串 CONCAT_WS() 返回由分隔符连接的字符串 REVERSE() 返回和字符顺序相反的字符串 SPACE() 返回指定数目的空格组成的字符串 FIELD() 返回参数在后续参数中出现的第一个位置 ELT() 返回指定位置的字符串 EXPORT_SET() 返回一个字符串,其中值位中设置的每个位,可以得到一个 on 字符串,而每个未设置的位,可以得到一个 off 字符串 MAKE_SET() 返回一组逗号分隔的字符串,由位集合中具有相应位的字符串组成 FIND_IN_SET() 返回第一个参数在第二个参数中出现的位置 FORMAT() 返回指定小数位数格式的数字 ORD() 返回参数中最左字符的字符代码 QUOTE() 引用一个字符串,返回一个在 SQL 语句中可用作正确转义的数据值的结果 字符串比较函数 函数名 功能描述 LIKE 进行简单模式匹配 NOT LIKE 否定简单模式匹配 STRCMP() 比较两个字符串 正则表达式 表达式名 功能描述 REGEXP 使用正则表达式进行模式匹配 RLIKE 与 REGEXP 功能相同 NOT REGEXP 否定 REGEXP "}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/string-functions/", "title": "字符串函数", "content": " 字符串函数 函数名 功能描述 ASCII() 返回最左字符的数值 CHAR() 返回由整数的代码值所给出的字符组成的字符串 BIN() 返回一个数的二进制值的字符串表示 HEX() 返回十进制值或字符串值的十六进制表示 OCT() 返回一个数的八进制值的字符串表示 UNHEX() 返回 HEX 表示的数字所代表的字符串 TO_BASE64() 返回转换为 BASE64 的字符串参数 FROM_BASE64() 解码为 BASE64 的字符串并返回结果 LOWER() 返回小写字母的字符 LCASE() 与 LOWER() 功能相同 UPPER() 返回大写字母的字符 UCASE() 与 UPPER() 功能相同 LPAD() 返回左边由指定字符串填充的字符串参数 RPAD() 返回右边由指定字符串填充的字符串参数 TRIM() 删除字符串的前缀和后缀 LTRIM() 删除前面的空格字符 RTRIM() 删除结尾的空格字符 BIT_LENGTH() 返回字符串的位长度 CHAR_LENGTH() 返回字符串的字符长度 CHARACTER_LENGTH() 与 CHAR_LENGTH() 功能相同 LENGTH() 返回字符串的字节长度 OCTET_LENGTH() 与 LENGTH() 功能相同 INSERT() 在指定位置插入一个子字符串,直到指定的字符数 REPLACE() 替换指定的字符串 SUBSTR() 返回指定的子字符串 SUBSTRING() 返回指定的子字符串 SUBSTRING_INDEX() 返回最终定界符左边或右边的子字符串 MID() 返回从指定位置开始的子字符串 LEFT() 返回指定的最左字符 RIGHT() 返回指定的最右字符 INSTR() 返回子字符串的第一个出现位置 LOCATE() 返回子字符串的第一个出现位置,与 INSTR() 的参数位置相反 POSITION() 与 LOCATE() 功能相同 REPEAT() 返回重复指定次数的字符串 CONCAT() 返回连接的字符串 CONCAT_WS() 返回由分隔符连接的字符串 REVERSE() 返回和字符顺序相反的字符串 SPACE() 返回指定数目的空格组成的字符串 FIELD() 返回参数在后续参数中出现的第一个位置 ELT() 返回指定位置的字符串 EXPORT_SET() 返回一个字符串,其中值位中设置的每个位,可以得到一个 on 字符串,而每个未设置的位,可以得到一个 off 字符串 MAKE_SET() 返回一组逗号分隔的字符串,由位集合中具有相应位的字符串组成 FIND_IN_SET() 返回第一个参数在第二个参数中出现的位置 FORMAT() 返回指定小数位数格式的数字 ORD() 返回参数中最左字符的字符代码 QUOTE() 引用一个字符串,返回一个在 SQL 语句中可用作正确转义的数据值的结果 SOUNDEX() 返回一个 soundex 字符串 SOUNDS LIKE 按发音比较字符串 字符串比较函数 函数名 功能描述 LIKE 进行简单模式匹配 NOT LIKE 否定简单模式匹配 STRCMP() 比较两个字符串 MATCH 执行全文搜索 正则表达式 表达式名 功能描述 REGEXP 使用正则表达式进行模式匹配 RLIKE 与 REGEXP 功能相同 NOT REGEXP 否定 REGEXP "}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/string-functions/", "title": "字符串函数", "content": " 字符串函数 函数名 功能描述 ASCII() 返回最左字符的数值 CHAR() 返回由整数的代码值所给出的字符组成的字符串 BIN() 返回一个数的二进制值的字符串表示 HEX() 返回十进制值或字符串值的十六进制表示 OCT() 返回一个数的八进制值的字符串表示 UNHEX() 返回 HEX 表示的数字所代表的字符串 TO_BASE64() 返回转换为 BASE64 的字符串参数 FROM_BASE64() 解码为 BASE64 的字符串并返回结果 LOWER() 返回小写字母的字符 LCASE() 与 LOWER() 功能相同 UPPER() 返回大写字母的字符 UCASE() 与 UPPER() 功能相同 LPAD() 返回左边由指定字符串填充的字符串参数 RPAD() 返回右边由指定字符串填充的字符串参数 TRIM() 删除字符串的前缀和后缀 LTRIM() 删除前面的空格字符 RTRIM() 删除结尾的空格字符 BIT_LENGTH() 返回字符串的位长度 CHAR_LENGTH() 返回字符串的字符长度 CHARACTER_LENGTH() 与 CHAR_LENGTH() 功能相同 LENGTH() 返回字符串的字节长度 OCTET_LENGTH() 与 LENGTH() 功能相同 INSERT() 在指定位置插入一个子字符串,直到指定的字符数 REPLACE() 替换指定的字符串 SUBSTR() 返回指定的子字符串 SUBSTRING() 返回指定的子字符串 SUBSTRING_INDEX() 返回最终定界符左边或右边的子字符串 MID() 返回从指定位置开始的子字符串 LEFT() 返回指定的最左字符 RIGHT() 返回指定的最右字符 INSTR() 返回子字符串的第一个出现位置 LOCATE() 返回子字符串的第一个出现位置,与 INSTR() 的参数位置相反 POSITION() 与 LOCATE() 功能相同 REPEAT() 返回重复指定次数的字符串 CONCAT() 返回连接的字符串 CONCAT_WS() 返回由分隔符连接的字符串 REVERSE() 返回和字符顺序相反的字符串 SPACE() 返回指定数目的空格组成的字符串 FIELD() 返回参数在后续参数中出现的第一个位置 ELT() 返回指定位置的字符串 EXPORT_SET() 返回一个字符串,其中值位中设置的每个位,可以得到一个 on 字符串,而每个未设置的位,可以得到一个 off 字符串 MAKE_SET() 返回一组逗号分隔的字符串,由位集合中具有相应位的字符串组成 FIND_IN_SET() 返回第一个参数在第二个参数中出现的位置 FORMAT() 返回指定小数位数格式的数字 ORD() 返回参数中最左字符的字符代码 QUOTE() 引用一个字符串,返回一个在 SQL 语句中可用作正确转义的数据值的结果 SOUNDEX() 返回一个 soundex 字符串 SOUNDS LIKE 按发音比较字符串 字符串比较函数 函数名 功能描述 LIKE 进行简单模式匹配 NOT LIKE 否定简单模式匹配 STRCMP() 比较两个字符串 MATCH 执行全文搜索 正则表达式 表达式名 功能描述 REGEXP 使用正则表达式进行模式匹配 RLIKE 与 REGEXP 功能相同 NOT REGEXP 否定 REGEXP "}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/literal-value-string-literals/", "title": "字符串字面值", "content": " String Literals String Literals 是一个 bytes 或者 characters 的序列,两端被单引号 ' 或者双引号 " 包围,例如:'example string' "example string" 如果字符串是连续的,会被合并为一个独立的 string。以下表示是一样的:'a string' 'a' ' ' 'string' "a" ' ' "string" 如果 ANSI_QUOTES SQL MODE 开启了,那么只有单引号内的会被认为是 String Literals,对于双引号内的字符串,会被认为是一个 identifier。binary string 是一串 bytes 组成的字符串,每一个 binary string 有一个叫做 binary 的 character set 和 collation。一个非二进制的字符串是一个由字符组成的字符串,它有除 binary 外的 character set和与之兼容的 collation。对于两种字符串类型,比较都是基于每个字符的数值。对于 binary string 而言,比较单元就是字节,对于非二进制的字符串,那么单元就是字符,而有的字符集支持多字节字符。一个 String Literal 可以拥有一个可选的 character set introducer 和 COLLATE clause,可以用来指派特定的字符集跟 collation(TiDB 对此只是做了语法上的兼容,并不实质做处理)。[_charset_name]'string' [COLLATE collation_name] 例如:SELECT _latin1'string'; SELECT _binary'string'; SELECT _utf8'string' COLLATE utf8_bin; 你可以使用 N’literal’ 或者 n’literal’ 来创建使用 national character set 的字符串,下列语句是一样的:SELECT N'some text'; SELECT n'some text'; SELECT _utf8'some text'; 转义字符:| 转义序列 | 意义 | | :——-: | :——-:| | 0 | ASCII NUL (X’00’) 字符 | | ’ | 单引号 | | ” | 双引号 | | b | 退格符号 | | n | 换行符 | | r | 回车符 | | t | tab 符(制表符)| | z | ASCII 26 (Ctrl + Z) | | | 反斜杠 | | % | % | | _ | _ |如果要在 string literal 中使用 ' 或者 ",有以下几种办法: 在 ' 引用的字符串中,可以用 '' 来表示单引号。 在 " 引用的字符串中,可以用 "" 来表示双引号。 前面接转义符。 在 ' 中表示 " 或者在 " 中表示 ' 都不需要特别的处理。 更多细节。"}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/literal-value-string-literals/", "title": "字符串字面值", "content": " String Literals String Literals 是一个 bytes 或者 characters 的序列,两端被单引号 ' 或者双引号 " 包围,例如:'example string' "example string" 如果字符串是连续的,会被合并为一个独立的 string。以下表示是一样的:'a string' 'a' ' ' 'string' "a" ' ' "string" 如果 ANSI_QUOTES SQL MODE 开启了,那么只有单引号内的会被认为是 String Literals,对于双引号内的字符串,会被认为是一个 identifier。binary string 是一串 bytes 组成的字符串,每一个 binary string 有一个叫做 binary 的 character set 和 collation。一个非二进制的字符串是一个由字符组成的字符串,它有除 binary 外的 character set和与之兼容的 collation。对于两种字符串类型,比较都是基于每个字符的数值。对于 binary string 而言,比较单元就是字节,对于非二进制的字符串,那么单元就是字符,而有的字符集支持多字节字符。一个 String Literal 可以拥有一个可选的 character set introducer 和 COLLATE clause,可以用来指派特定的字符集跟 collation(TiDB 对此只是做了语法上的兼容,并不实质做处理)。[_charset_name]'string' [COLLATE collation_name] 例如:SELECT _latin1'string'; SELECT _binary'string'; SELECT _utf8'string' COLLATE utf8_bin; 你可以使用 N’literal’ 或者 n’literal’ 来创建使用 national character set 的字符串,下列语句是一样的:SELECT N'some text'; SELECT n'some text'; SELECT _utf8'some text'; 转义字符:| 转义序列 | 意义 | | :——-: | :——-:| | 0 | ASCII NUL (X’00’) 字符 | | ’ | 单引号 | | ” | 双引号 | | b | 退格符号 | | n | 换行符 | | r | 回车符 | | t | tab 符(制表符)| | z | ASCII 26 (Ctrl + Z) | | | 反斜杠 | | % | % | | _ | _ |如果要在 string literal 中使用 ' 或者 ",有以下几种办法: 在 ' 引用的字符串中,可以用 '' 来表示单引号。 在 " 引用的字符串中,可以用 "" 来表示双引号。 前面接转义符。 在 ' 中表示 " 或者在 " 中表示 ' 都不需要特别的处理。 更多细节。"}, {"url": "https://pingcap.com/docs-cn/sql/character-set-support/", "title": "字符集支持", "content": " 字符集支持 名词解释,下面的阐述中会交错使用中文或者英文,请互相对照: Character Set:字符集 Collation:排序规则 目前 TiDB 支持以下字符集:mysql> SHOW CHARACTER SET; +---------|---------------|-------------------|--------+ | Charset | Description | Default collation | Maxlen | +---------|---------------|-------------------|--------+ | utf8 | UTF-8 Unicode | utf8_bin | 3 | | utf8mb4 | UTF-8 Unicode | utf8mb4_bin | 4 | | ascii | US ASCII | ascii_bin | 1 | | latin1 | Latin1 | latin1_bin | 1 | | binary | binary | binary | 1 | +---------|---------------|-------------------|--------+ 5 rows in set (0.00 sec) 注意:在 TiDB 中实际上 utf8 被当做成了 utf8mb4 来处理。 对于字符集来说,至少会有一个 Collation(排序规则)与之对应。而大部分字符集实际上会有多个 Collation。利用以下的语句可以查看:mysql> SHOW COLLATION WHERE Charset = 'latin1'; +-------------------|---------|------|---------|----------|---------+ | Collation | Charset | Id | Default | Compiled | Sortlen | +-------------------|---------|------|---------|----------|---------+ | latin1_german1_ci | latin1 | 5 | | Yes | 1 | | latin1_swedish_ci | latin1 | 8 | Yes | Yes | 1 | | latin1_danish_ci | latin1 | 15 | | Yes | 1 | | latin1_german2_ci | latin1 | 31 | | Yes | 1 | | latin1_bin | latin1 | 47 | | Yes | 1 | | latin1_general_ci | latin1 | 48 | | Yes | 1 | | latin1_general_cs | latin1 | 49 | | Yes | 1 | | latin1_spanish_ci | latin1 | 94 | | Yes | 1 | +-------------------|---------|------|---------|----------|---------+ 8 rows in set (0.00 sec) latin1 Collation(排序规则)分别有以下含义: Collation 含义 latin1_bin latin1 编码的二进制表示 latin1_danish_ci 丹麦语/挪威语,不区分大小写 latin1_general_ci 多种语言的 (西欧),不区分大小写 latin1_general_cs 多种语言的 (ISO 西欧),区分大小写 latin1_german1_ci 德国 DIN-1 (字典序),不区分大小写 latin1_german2_ci 德国 DIN-2,不区分大小写 latin1_spanish_ci 现代西班牙语,不区分大小写 latin1_swedish_ci 瑞典语/芬兰语,不区分大小写 每一个字符集,都有一个默认的 Collation,例如 utf8 的默认 Collation 就为 utf8_bin。注意 TiDB 目前的 Collation 都是区分大小写的。Collation 命名规则 TiDB 的 Collation 遵循着如下的命名规则: Collation 的前缀是它相应的字符集,通常之后会跟着一个或者更多的后缀来表名其他的排序规则, 例如:utf8_general_ci 和 lation1_swedish_ci 是 utf8 和 latin1 字符集的 Collation。但是 binary 字符集只有一个 Collation,就是 binary。 一个语言对应的 Collation 会包含语言的名字,例如 utf8_turkish_ci 和 utf8_hungarian_ci 是依据 Turkish(土耳其语) 和 Hungarian(匈牙利语) 的排序规则来排序。 Collation 的后缀表示了 Collation 是否区分大小写和是否区分口音。下面的表展示了这些特性: 后缀 含义 _ai 口音不敏感(Accent insensitive) _as 口音敏感 (Accent sensitive) _ci 大小写不敏感 _cs 大小写敏感 注意:目前为止 TiDB 只支持部分以上提到的 Collation。 数据库 Character Set 和 Collation 每个数据库都有相应的 Character Set 和 Collation,CREATE DATABASE 可以指定数据库的字符集和排序规则:CREATE DATABASE db_name [[DEFAULT] CHARACTER SET charset_name] [[DEFAULT] COLLATE collation_name] 在这里 SCHEMA 可以跟 DATABASE 互换使用。不同的数据库之间可以使用不一样的字符集和排序规则。通过系统变量 character_set_database 和 collation_database 可以查看到当前数据库的字符集以及排序规则:mysql> create schema test1 character set utf8 COLLATE uft8_general_ci; Query OK, 0 rows affected (0.09 sec) mysql> use test1; Database changed mysql> SELECT @@character_set_database, @@collation_database; +--------------------------|----------------------+ | @@character_set_database | @@collation_database | +--------------------------|----------------------+ | utf8 | uft8_general_ci | +--------------------------|----------------------+ 1 row in set (0.00 sec) mysql> create schema test2 character set latin1 COLLATE latin1_general_ci; Query OK, 0 rows affected (0.09 sec) mysql> use test2; Database changed mysql> SELECT @@character_set_database, @@collation_database; +--------------------------|----------------------+ | @@character_set_database | @@collation_database | +--------------------------|----------------------+ | latin1 | latin1_general_ci | +--------------------------|----------------------+ 1 row in set (0.00 sec) 在 INFORMATION_SCHEMA 中也可以查看到这两个值:SELECT DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = 'db_name'; 表的 Character Set 和 Collation 表的 Character Set 和 Collation 可以通过以下语句来设置:CREATE TABLE tbl_name (column_list) [[DEFAULT] CHARACTER SET charset_name] [COLLATE collation_name]] ALTER TABLE tbl_name [[DEFAULT] CHARACTER SET charset_name] [COLLATE collation_name] 例如:mysql> CREATE TABLE t1(a int) CHARACTER SET utf8 COLLATE utf8_general_ci; Query OK, 0 rows affected (0.08 sec) 如果 Column 的字符集和排序规则没有设置,那么表的字符集和排序规则就作为其默认值。列的 Character Set 和 Collation 列的 Character Set 和 Collation 的语法如下:col_name {CHAR | VARCHAR | TEXT} (col_length) [CHARACTER SET charset_name] [COLLATE collation_name] col_name {ENUM | SET} (val_list) [CHARACTER SET charset_name] [COLLATE collation_name] 客户端连接的 Character Sets 和 Collations 服务器的字符集和排序规则可以通过系统变量 character_set_server 和 collation_server 获取。 数据库的字符集和排序规则可以通过环境变量 character_set_database 和 collation_database 获取。 对于每一个客户端的连接,也有相应的变量表示字符集和排序规则:character_set_connection 和 collation_connection。character_set_client 代表客户端的字符集。在返回结果前,服务端会把结果根据 character_set_results 转换成对应的字符集。包括结果的元信息等。可以用以下的语句来影响这些跟客户端相关的字符集变量: SET NAMES 'charset_name' [COLLATE 'collation_name'] SET NAMES 用来设定客户端会在之后的请求中使用的字符集。SET NAMES utf8 表示客户端会在接下来的请求中,都使用 utf8 字符集。服务端也会在之后返回结果的时候使用 utf8 字符集。 SET NAMES 'charset_name' 语句其实等于下面语句的组合:SET character_set_client = charset_name; SET character_set_results = charset_name; SET character_set_connection = charset_name; COLLATE 是可选的,如果没有提供,将会用 charset_name 默认的 Collation。 SET CHARACTER SET 'charset_name' 跟 SET NAMES 类似,等价于下面语句的组合:SET character_set_client = charset_name; SET character_set_results = charset_name; SET collation_connection = @@collation_database; 更多细节,参考 Connection Character Sets and Collations。"}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/character-set-support/", "title": "字符集支持", "content": " 字符集支持 名词解释,下面的阐述中会交错使用中文或者英文,请互相对照: Character Set:字符集 Collation:排序规则 目前 TiDB 支持以下字符集:mysql> SHOW CHARACTER SET; +---------|---------------|-------------------|--------+ | Charset | Description | Default collation | Maxlen | +---------|---------------|-------------------|--------+ | utf8 | UTF-8 Unicode | utf8_bin | 3 | | utf8mb4 | UTF-8 Unicode | utf8mb4_bin | 4 | | ascii | US ASCII | ascii_bin | 1 | | latin1 | Latin1 | latin1_bin | 1 | | binary | binary | binary | 1 | +---------|---------------|-------------------|--------+ 5 rows in set (0.00 sec) 注意:在 TiDB 中实际上 utf8 被当做成了 utf8mb4 来处理。 对于字符集来说,至少会有一个 Collation(排序规则)与之对应。而大部分字符集实际上会有多个 Collation。利用以下的语句可以查看:mysql> SHOW COLLATION WHERE Charset = 'latin1'; +-------------------|---------|------|---------|----------|---------+ | Collation | Charset | Id | Default | Compiled | Sortlen | +-------------------|---------|------|---------|----------|---------+ | latin1_german1_ci | latin1 | 5 | | Yes | 1 | | latin1_swedish_ci | latin1 | 8 | Yes | Yes | 1 | | latin1_danish_ci | latin1 | 15 | | Yes | 1 | | latin1_german2_ci | latin1 | 31 | | Yes | 1 | | latin1_bin | latin1 | 47 | | Yes | 1 | | latin1_general_ci | latin1 | 48 | | Yes | 1 | | latin1_general_cs | latin1 | 49 | | Yes | 1 | | latin1_spanish_ci | latin1 | 94 | | Yes | 1 | +-------------------|---------|------|---------|----------|---------+ 8 rows in set (0.00 sec) latin1 Collation(排序规则)分别有以下含义: Collation 含义 latin1_bin latin1 编码的二进制表示 latin1_danish_ci 丹麦语/挪威语,不区分大小写 latin1_general_ci 多种语言的 (西欧),不区分大小写 latin1_general_cs 多种语言的 (ISO 西欧),区分大小写 latin1_german1_ci 德国 DIN-1 (字典序),不区分大小写 latin1_german2_ci 德国 DIN-2,不区分大小写 latin1_spanish_ci 现代西班牙语,不区分大小写 latin1_swedish_ci 瑞典语/芬兰语,不区分大小写 每一个字符集,都有一个默认的 Collation,例如 utf8 的默认 Collation 就为 utf8_bin。注意 TiDB 目前的 Collation 都是区分大小写的。Collation 命名规则 TiDB 的 Collation 遵循着如下的命名规则: Collation 的前缀是它相应的字符集,通常之后会跟着一个或者更多的后缀来表名其他的排序规则, 例如:utf8_general_ci 和 lation1_swedish_ci 是 utf8 和 latin1 字符集的 Collation。但是 binary 字符集只有一个 Collation,就是 binary。 一个语言对应的 Collation 会包含语言的名字,例如 utf8_turkish_ci 和 utf8_hungarian_ci 是依据 Turkish(土耳其语) 和 Hungarian(匈牙利语) 的排序规则来排序。 Collation 的后缀表示了 Collation 是否区分大小写和是否区分口音。下面的表展示了这些特性: 后缀 含义 _ai 口音不敏感(Accent insensitive) _as 口音敏感 (Accent insensitive) _ci 大小写不敏感 _cs 大小写敏感 注意:目前为止 TiDB 只支持部分以上提到的 Collation。 数据库 Character Set 和 Collation 每个数据库都有相应的 Character Set 和 Collation,CREATE DATABASE 可以指定数据库的字符集和排序规则:CREATE DATABASE db_name [[DEFAULT] CHARACTER SET charset_name] [[DEFAULT] COLLATE collation_name] 在这里 SCHEMA 可以跟 DATABASE 互换使用。不同的数据库之间可以使用不一样的字符集和排序规则。通过系统变量 character_set_database 和 collation_database 可以查看到当前数据库的字符集以及排序规则:mysql> create schema test1 character set utf8 COLLATE uft8_general_ci; Query OK, 0 rows affected (0.09 sec) mysql> use test1; Database changed mysql> SELECT @@character_set_database, @@collation_database; +--------------------------|----------------------+ | @@character_set_database | @@collation_database | +--------------------------|----------------------+ | utf8 | uft8_general_ci | +--------------------------|----------------------+ 1 row in set (0.00 sec) mysql> create schema test2 character set latin1 COLLATE latin1_general_ci; Query OK, 0 rows affected (0.09 sec) mysql> use test2; Database changed mysql> SELECT @@character_set_database, @@collation_database; +--------------------------|----------------------+ | @@character_set_database | @@collation_database | +--------------------------|----------------------+ | latin1 | latin1_general_ci | +--------------------------|----------------------+ 1 row in set (0.00 sec) 在 INFORMATION_SCHEMA 中也可以查看到这两个值:SELECT DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = 'db_name'; 表的 Character Set 和 Collation 表的 Character Set 和 Collation 可以通过以下语句来设置:CREATE TABLE tbl_name (column_list) [[DEFAULT] CHARACTER SET charset_name] [COLLATE collation_name]] ALTER TABLE tbl_name [[DEFAULT] CHARACTER SET charset_name] [COLLATE collation_name] 例如:mysql> CREATE TABLE t1(a int) CHARACTER SET utf8 COLLATE utf8_general_ci; Query OK, 0 rows affected (0.08 sec) 如果 Column 的字符集和排序规则没有设置,那么表的字符集和排序规则就作为其默认值。列的 Character Set 和 Collation 列的 Character Set 和 Collation 的语法如下:col_name {CHAR | VARCHAR | TEXT} (col_length) [CHARACTER SET charset_name] [COLLATE collation_name] col_name {ENUM | SET} (val_list) [CHARACTER SET charset_name] [COLLATE collation_name] 客户端连接的 Character Sets 和 Collations 服务器的字符集和排序规则可以通过系统变量 character_set_server 和 collation_server 获取。 数据库的字符集和排序规则可以通过环境变量 character_set_database 和 collation_database 获取。 对于每一个客户端的连接,也有相应的变量表示字符集和排序规则:character_set_connection 和 collation_connection。character_set_client 代表客户端的字符集。在返回结果前,服务端会把结果根据 character_set_results 转换成对应的字符集。包括结果的元信息等。可以用以下的语句来影响这些跟客户端相关的字符集变量: SET NAMES 'charset_name' [COLLATE 'collation_name'] SET NAMES 用来设定客户端会在之后的请求中使用的字符集。SET NAMES utf8 表示客户端会在接下来的请求中,都使用 utf8 字符集。服务端也会在之后返回结果的时候使用 utf8 字符集。 SET NAMES 'charset_name' 语句其实等于下面语句的组合:SET character_set_client = charset_name; SET character_set_results = charset_name; SET character_set_connection = charset_name; COLLATE 是可选的,如果没有提供,将会用 charset_name 默认的 Collation。 SET CHARACTER SET 'charset_name' 跟 SET NAMES 类似,等价于下面语句的组合:SET character_set_client = charset_name; SET character_set_results = charset_name; SET collation_connection = @@collation_database; 更多细节,参考 Connection Character Sets and Collations。"}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/character-set-support/", "title": "字符集支持", "content": " 字符集支持 名词解释,下面的阐述中会交错使用中文或者英文,请互相对照: Character Set:字符集 Collation:排序规则 目前 TiDB 支持以下字符集:mysql> SHOW CHARACTER SET; +---------|---------------|-------------------|--------+ | Charset | Description | Default collation | Maxlen | +---------|---------------|-------------------|--------+ | utf8 | UTF-8 Unicode | utf8_bin | 3 | | utf8mb4 | UTF-8 Unicode | utf8mb4_bin | 4 | | ascii | US ASCII | ascii_bin | 1 | | latin1 | Latin1 | latin1_bin | 1 | | binary | binary | binary | 1 | +---------|---------------|-------------------|--------+ 5 rows in set (0.00 sec) 注意:在 TiDB 中实际上 utf8 被当做成了 utf8mb4 来处理。 对于字符集来说,至少会有一个 Collation(排序规则)与之对应。而大部分字符集实际上会有多个 Collation。利用以下的语句可以查看:mysql> SHOW COLLATION WHERE Charset = 'latin1'; +-------------------|---------|------|---------|----------|---------+ | Collation | Charset | Id | Default | Compiled | Sortlen | +-------------------|---------|------|---------|----------|---------+ | latin1_german1_ci | latin1 | 5 | | Yes | 1 | | latin1_swedish_ci | latin1 | 8 | Yes | Yes | 1 | | latin1_danish_ci | latin1 | 15 | | Yes | 1 | | latin1_german2_ci | latin1 | 31 | | Yes | 1 | | latin1_bin | latin1 | 47 | | Yes | 1 | | latin1_general_ci | latin1 | 48 | | Yes | 1 | | latin1_general_cs | latin1 | 49 | | Yes | 1 | | latin1_spanish_ci | latin1 | 94 | | Yes | 1 | +-------------------|---------|------|---------|----------|---------+ 8 rows in set (0.00 sec) latin1 Collation(排序规则)分别有以下含义: Collation 含义 latin1_bin latin1 编码的二进制表示 latin1_danish_ci 丹麦语/挪威语,不区分大小写 latin1_general_ci 多种语言的 (西欧),不区分大小写 latin1_general_cs 多种语言的 (ISO 西欧),区分大小写 latin1_german1_ci 德国 DIN-1 (字典序),不区分大小写 latin1_german2_ci 德国 DIN-2,不区分大小写 latin1_spanish_ci 现代西班牙语,不区分大小写 latin1_swedish_ci 瑞典语/芬兰语,不区分大小写 每一个字符集,都有一个默认的 Collation,例如 utf8 的默认 Collation 就为 utf8_bin。注意 TiDB 目前的 Collation 都是区分大小写的。Collation 命名规则 TiDB 的 Collation 遵循着如下的命名规则: Collation 的前缀是它相应的字符集,通常之后会跟着一个或者更多的后缀来表名其他的排序规则, 例如:utf8_general_ci 和 lation1_swedish_ci 是 utf8 和 latin1 字符集的 Collation。但是 binary 字符集只有一个 Collation,就是 binary。 一个语言对应的 Collation 会包含语言的名字,例如 utf8_turkish_ci 和 utf8_hungarian_ci 是依据 Turkish(土耳其语) 和 Hungarian(匈牙利语) 的排序规则来排序。 Collation 的后缀表示了 Collation 是否区分大小写和是否区分口音。下面的表展示了这些特性: 后缀 含义 _ai 口音不敏感(Accent insensitive) _as 口音敏感 (Accent insensitive) _ci 大小写不敏感 _cs 大小写敏感 注意:目前为止 TiDB 只支持部分以上提到的 Collation。 数据库 Character Set 和 Collation 每个数据库都有相应的 Character Set 和 Collation,CREATE DATABASE 可以指定数据库的字符集和排序规则:CREATE DATABASE db_name [[DEFAULT] CHARACTER SET charset_name] [[DEFAULT] COLLATE collation_name] 在这里 SCHEMA 可以跟 DATABASE 互换使用。不同的数据库之间可以使用不一样的字符集和排序规则。通过系统变量 character_set_database 和 collation_database 可以查看到当前数据库的字符集以及排序规则:mysql> create schema test1 character set utf8 COLLATE uft8_general_ci; Query OK, 0 rows affected (0.09 sec) mysql> use test1; Database changed mysql> SELECT @@character_set_database, @@collation_database; +--------------------------|----------------------+ | @@character_set_database | @@collation_database | +--------------------------|----------------------+ | utf8 | uft8_general_ci | +--------------------------|----------------------+ 1 row in set (0.00 sec) mysql> create schema test2 character set latin1 COLLATE latin1_general_ci; Query OK, 0 rows affected (0.09 sec) mysql> use test2; Database changed mysql> SELECT @@character_set_database, @@collation_database; +--------------------------|----------------------+ | @@character_set_database | @@collation_database | +--------------------------|----------------------+ | latin1 | latin1_general_ci | +--------------------------|----------------------+ 1 row in set (0.00 sec) 在 INFORMATION_SCHEMA 中也可以查看到这两个值:SELECT DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = 'db_name'; 表的 Character Set 和 Collation 表的 Character Set 和 Collation 可以通过以下语句来设置:CREATE TABLE tbl_name (column_list) [[DEFAULT] CHARACTER SET charset_name] [COLLATE collation_name]] ALTER TABLE tbl_name [[DEFAULT] CHARACTER SET charset_name] [COLLATE collation_name] 例如:mysql> CREATE TABLE t1(a int) CHARACTER SET utf8 COLLATE utf8_general_ci; Query OK, 0 rows affected (0.08 sec) 如果 Column 的字符集和排序规则没有设置,那么表的字符集和排序规则就作为其默认值。列的 Character Set 和 Collation 列的 Character Set 和 Collation 的语法如下:col_name {CHAR | VARCHAR | TEXT} (col_length) [CHARACTER SET charset_name] [COLLATE collation_name] col_name {ENUM | SET} (val_list) [CHARACTER SET charset_name] [COLLATE collation_name] 客户端连接的 Character Sets 和 Collations 服务器的字符集和排序规则可以通过系统变量 character_set_server 和 collation_server 获取。 数据库的字符集和排序规则可以通过环境变量 character_set_database 和 collation_database 获取。 对于每一个客户端的连接,也有相应的变量表示字符集和排序规则:character_set_connection 和 collation_connection。character_set_client 代表客户端的字符集。在返回结果前,服务端会把结果根据 character_set_results 转换成对应的字符集。包括结果的元信息等。可以用以下的语句来影响这些跟客户端相关的字符集变量: SET NAMES 'charset_name' [COLLATE 'collation_name'] SET NAMES 用来设定客户端会在之后的请求中使用的字符集。SET NAMES utf8 表示客户端会在接下来的请求中,都使用 utf8 字符集。服务端也会在之后返回结果的时候使用 utf8 字符集。 SET NAMES 'charset_name' 语句其实等于下面语句的组合:SET character_set_client = charset_name; SET character_set_results = charset_name; SET character_set_connection = charset_name; COLLATE 是可选的,如果没有提供,将会用 charset_name 默认的 Collation。 SET CHARACTER SET 'charset_name' 跟 SET NAMES 类似,等价于下面语句的组合:SET character_set_client = charset_name; SET character_set_results = charset_name; SET collation_connection = @@collation_database; 更多细节,参考 Connection Character Sets and Collations。"}, {"url": "https://pingcap.com/docs-cn/sql/character-set-configuration/", "title": "字符集配置", "content": " 字符集配置 目前,TiDB 只支持 utf8 字符集,相当于 MySQL 中的 utf8mb4。MySQL 5.7 的默认字符集为 latin1。关于 TiDB 与 MySQL 字符集的区别,在默认设置的区别中有相关说明。更多细节。"}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/character-set-configuration/", "title": "字符集配置", "content": " 字符集配置 目前 TiDB 还没有相应的配置来设置字符集,默认为 utf8。更多细节"}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/character-set-configuration/", "title": "字符集配置", "content": " 字符集配置 目前 TiDB 还没有相应的配置来设置字符集,默认为 utf8。更多细节"}, {"url": "https://pingcap.com/docs-cn/sql/literal-values/", "title": "字面值", "content": " 字面值 String Literals String Literals 是一个 bytes 或者 characters 的序列,两端被单引号 ' 或者双引号 " 包围,例如:'example string' "example string" 如果字符串是连续的,会被合并为一个独立的 string。以下表示是一样的:'a string' 'a' ' ' 'string' "a" ' ' "string" 如果 ANSI_QUOTES SQL MODE 开启了,那么只有单引号内的会被认为是 String Literals,对于双引号内的字符串,会被认为是一个 identifier。binary string 是一串 bytes 组成的字符串,每一个 binary string 有一个叫做 binary 的 character set 和 collation。一个非二进制的字符串是一个由字符组成的字符串,它有除 binary 外的 character set和与之兼容的 collation。对于两种字符串类型,比较都是基于每个字符的数值。对于 binary string 而言,比较单元就是字节,对于非二进制的字符串,那么单元就是字符,而有的字符集支持多字节字符。一个 String Literal 可以拥有一个可选的 character set introducer 和 COLLATE clause,可以用来指派特定的字符集跟 collation(TiDB 对此只是做了语法上的兼容,并不实质做处理)。[_charset_name]'string' [COLLATE collation_name] 例如:SELECT _latin1'string'; SELECT _binary'string'; SELECT _utf8'string' COLLATE utf8_bin; 你可以使用 N’literal’ 或者 n’literal’ 来创建使用 national character set 的字符串,下列语句是一样的:SELECT N'some text'; SELECT n'some text'; SELECT _utf8'some text'; 转义字符: 0: ASCII NUL (X’00’) 字符 ‘: 单引号 “: 双引号 b: 退格符号 n: 换行符 r: 回车符 t: tab 符(制表符) z: ASCII 26 (Ctrl + Z) : 反斜杠 %: % _: _ 如果要在 string literal 中使用 ' 或者 ",有以下几种办法: 在 ' 引用的字符串中,可以用 '' 来表示单引号。 在 " 引用的字符串中,可以用 "" 来表示双引号。 前面接转义符。 在 ' 中表示 " 或者在 " 中表示 ' 都不需要特别的处理。 更多细节。Numeric Literals 数值字面值包括 integer 跟 Decimal 类型跟浮点数字面值。integer 可以包括 . 作为小数点分隔,数字前可以有 - 或者 + 来表示正数或者负数。精确数值字面值可以表示为如下格式:1, .2, 3.4, -5, -6.78, +9.10.科学记数法也是被允许的,表示为如下格式:1.2E3, 1.2E-3, -1.2E3, -1.2E-3。更多细节。NULL Values NULL 代表数据为空,它是大小写不敏感的,与 N(大小写敏感) 同义。需要注意的是 NULL 跟 0 并不一样,跟空字符串 '' 也不一样。Hexadecimal Literals 十六进制字面值是有 X 和 0x 前缀的字符串,后接表示十六进制的数字。注意 0x 是大小写敏感的,不能表示为 0X。例:X'ac12' X'12AC' x'ac12' x'12AC' 0xac12 0x12AC 以下是不合法的十六进制字面值:X'1z' (z 不是合法的十六进制值) 0X12AC (0X 必须用小写的 0x) 对于使用 X'val' 格式的十六进制字面值,val 必须要有一个数字,可以在前面补一个 0 来避免语法错误。mysql> select X'aff'; ERROR 1105 (HY000): line 0 column 13 near ""hex literal: invalid hexadecimal format, must even numbers, but 3 (total length 13) mysql> select X'0aff'; +---------+ | X'0aff' | +---------+ | | +---------+ 1 row in set (0.00 sec) 默认情况,十六进制字面值是一个二进制字符串。如果需要将一个字符串或者数字转换为十六进制字面值,可以使用内建函数 HEX():mysql> SELECT HEX('TiDB'); +-------------+ | HEX('TiDB') | +-------------+ | 54694442 | +-------------+ 1 row in set (0.01 sec) mysql> SELECT X'54694442'; +-------------+ | X'54694442' | +-------------+ | TiDB | +-------------+ 1 row in set (0.00 sec) Date and Time Literals Date 跟 Time 字面值有几种格式,例如用字符串表示,或者直接用数字表示。在 TiDB 里面,当 TiDB 期望一个 Date 的时候,它会把 '2017-08-24', '20170824',20170824 当做是 Date。TiDB 的 Date 值有以下几种格式: 'YYYY-MM-DD' 或者 'YY-MM-DD',这里的 - 分隔符并不是严格的,可以是任意的标点符号。比如 '2017-08-24','2017&08&24', '2012@12^31' 都是一样的。唯一需要特别对待的是 ‘.’ 号,它被当做是小数点,用于分隔整数和小数部分。 Date 和 Time 部分可以被 ’T’ 分隔,它的作用跟空格符是一样的,例如 2017-8-24 10:42:00 跟 2017-8-24T10:42:00 是一样的。 'YYYYMMDDHHMMSS' 或者 'YYMMDDHHMMSS',例如 '20170824104520' 和 '170824104520' 被当做是 '2017-08-24 10:45:20',但是如果你提供了一个超过范围的值,例如'170824304520',那这就不是一个有效的 Date 字面值。 YYYYMMDDHHMMSS 或者 YYMMDDHHMMSS 注意这里没有单引号或者双引号,是一个数字。例如 20170824104520表示为 '2017-08-24 10:45:20'。 DATETIME 或者 TIMESTAMP 值可以接一个小数部分,用来表示微秒(精度最多到小数点后 6 位),用小数点 . 分隔。Dates 如果 year 部分只有两个数字,这是有歧义的(推荐使用四个数字的格式),TiDB 会尝试用以下的规则来解释: year 值如果在 70-99 范围,那么被转换成 1970-1999。 year 值如果在 00-69 范围,那么被转换成 2000-2069。 对于小于 10 的 month 或者 day 值,'2017-8-4' 跟 '2017-08-04' 是一样的。对于 Time 也是一样,比如 '2017-08-24 1:2:3' 跟 '2017-08-24 01:02:03'是一样的。在需要 Date 或者 Time 的语境下, 对于数值,TiDB 会根据数值的长度来选定指定的格式: 6 个数字,会被解释为 YYMMDD。 12 个数字,会被解释为 YYMMDDHHMMSS。 8 个数字,会解释为 YYYYMMDD。 14 个数字,会被解释为 YYYYMMDDHHMMSS。 对于 Time 类型,TiDB 用以下格式来表示: 'D HH:MM:SS',或者 'HH:MM:SS','HH:MM','D HH:MM','D HH','SS',这里的 D 表示 days,合法的范围是 0-34。 数值 HHMMSS,例如 231010 被解释为'23:10:10'。 数值 SS,MMSS,HHMMSS 都是可以被当做 Time。 Time 类型的小数点也是 .,精度最多小数点后 6 位。更多细节。Boolean Literals 常量 TRUE 和 FALSE 等于 1 和 0,它是大小写不敏感的。mysql> SELECT TRUE, true, tRuE, FALSE, FaLsE, false; +------+------+------+-------+-------+-------+ | TRUE | true | tRuE | FALSE | FaLsE | false | +------+------+------+-------+-------+-------+ | 1 | 1 | 1 | 0 | 0 | 0 | +------+------+------+-------+-------+-------+ 1 row in set (0.00 sec) Bit-Value Literals 位值字面值用 b 或者 0b 做前缀,后接以 0 跟 1 组成的二进制数字。其中 0b 是区分大小写的,0B 是会报错的。合法的 Bit-value: b’01’ B’01’ 0b01 非法的 Bit-value: b’2’ (2 不是二进制数值, 必须为 0 或 1) 0B01 (0B 必须是小写 0b) 默认情况,位值字面值是一个二进制字符串。Bit-value 是作为二进制返回的,所以输出到 MySQL Client 可能会显示不出来,如果要转换为可打印的字符,可以使用内建函数 BIN() 或者 HEX():CREATE TABLE t (b BIT(8)); INSERT INTO t SET b = b'00010011'; INSERT INTO t SET b = b'1110'; INSERT INTO t SET b = b'100101'; mysql> SELECT b+0, BIN(b), HEX(b) FROM t; +------+--------+--------+ | b+0 | BIN(b) | HEX(b) | +------+--------+--------+ | 19 | 10011 | 13 | | 14 | 1110 | E | | 37 | 100101 | 25 | +------+--------+--------+ 3 rows in set (0.00 sec)"}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/literal-values/", "title": "字面值", "content": " 字面值 String Literals String Literals 是一个 bytes 或者 characters 的序列,两端被单引号 ' 或者双引号 " 包围,例如:'example string' "example string" 如果字符串是连续的,会被合并为一个独立的 string。以下表示是一样的:'a string' 'a' ' ' 'string' "a" ' ' "string" 如果 ANSI_QUOTES SQL MODE 开启了,那么只有单引号内的会被认为是 String Literals,对于双引号内的字符串,会被认为是一个 identifier。binary string 是一串 bytes 组成的字符串,每一个 binary string 有一个叫做 binary 的 character set 和 collation。一个非二进制的字符串是一个由字符组成的字符串,它有除 binary 外的 character set和与之兼容的 collation。对于两种字符串类型,比较都是基于每个字符的数值。对于 binary string 而言,比较单元就是字节,对于非二进制的字符串,那么单元就是字符,而有的字符集支持多字节字符。一个 String Literal 可以拥有一个可选的 character set introducer 和 COLLATE clause,可以用来指派特定的字符集跟 collation(TiDB 对此只是做了语法上的兼容,并不实质做处理)。[_charset_name]'string' [COLLATE collation_name] 例如:SELECT _latin1'string'; SELECT _binary'string'; SELECT _utf8'string' COLLATE utf8_bin; 你可以使用 N’literal’ 或者 n’literal’ 来创建使用 national character set 的字符串,下列语句是一样的:SELECT N'some text'; SELECT n'some text'; SELECT _utf8'some text'; 转义字符: 0: ASCII NUL (X’00’) 字符 ‘: 单引号 “: 双引号 b: 退格符号 n: 换行符 r: 回车符 t: tab 符(制表符) z: ASCII 26 (Ctrl + Z) : 反斜杠 %: % _: _ 如果要在 string literal 中使用 ' 或者 ",有以下几种办法: 在 ' 引用的字符串中,可以用 '' 来表示单引号。 在 " 引用的字符串中,可以用 "" 来表示双引号。 前面接转义符。 在 ' 中表示 " 或者在 " 中表示 ' 都不需要特别的处理。 更多细节。Numeric Literals 数值字面值包括 integer 跟 Decimal 类型跟浮点数字面值。integer 可以包括 . 作为小数点分隔,数字前可以有 - 或者 + 来表示正数或者负数。精确数值字面值可以表示为如下格式:1, .2, 3.4, -5, -6.78, +9.10.科学记数法也是被允许的,表示为如下格式:1.2E3, 1.2E-3, -1.2E3, -1.2E-3。更多细节。NULL Values NULL 代表数据为空,它是大小写不敏感的,与 N(大小写敏感) 同义。需要注意的是 NULL 跟 0 并不一样,跟空字符串 '' 也不一样。Hexadecimal Literals 十六进制字面值是有 X 和 0x 前缀的字符串,后接表示十六进制的数字。注意 0x 是大小写敏感的,不能表示为 0X。例:X'ac12' X'12AC' x'ac12' x'12AC' 0xac12 0x12AC 以下是不合法的十六进制字面值:X'1z' (z 不是合法的十六进制值) 0X12AC (0X 必须用小写的 0x) 对于使用 X'val' 格式的十六进制字面值,val 必须要有一个数字,可以在前面补一个 0 来避免语法错误。mysql> select X'aff'; ERROR 1105 (HY000): line 0 column 13 near ""hex literal: invalid hexadecimal format, must even numbers, but 3 (total length 13) mysql> select X'0aff'; +---------+ | X'0aff' | +---------+ | | +---------+ 1 row in set (0.00 sec) 默认情况,十六进制字面值是一个二进制字符串。如果需要将一个字符串或者数字转换为十六进制字面值,可以使用内建函数 HEX():mysql> SELECT HEX('TiDB'); +-------------+ | HEX('TiDB') | +-------------+ | 54694442 | +-------------+ 1 row in set (0.01 sec) mysql> SELECT X'54694442'; +-------------+ | X'54694442' | +-------------+ | TiDB | +-------------+ 1 row in set (0.00 sec) Date and Time Literals Date 跟 Time 字面值有几种格式,例如用字符串表示,或者直接用数字表示。在 TiDB 里面,当 TiDB 期望一个 Date 的时候,它会把 '2017-08-24', '20170824',20170824 当做是 Date。TiDB 的 Date 值有以下几种格式: 'YYYY-MM-DD' 或者 'YY-MM-DD',这里的 - 分隔符并不是严格的,可以是任意的标点符号。比如 '2017-08-24','2017&08&24', '2012@12^31' 都是一样的。唯一需要特别对待的是 ‘.’ 号,它被当做是小数点,用于分隔整数和小数部分。 Date 和 Time 部分可以被 ’T’ 分隔,它的作用跟空格符是一样的,例如 2017-8-24 10:42:00 跟 2017-8-24T10:42:00 是一样的。 'YYYYMMDDHHMMSS' 或者 'YYMMDDHHMMSS',例如 '20170824104520' 和 '170824104520' 被当做是 '2017-08-24 10:45:20',但是如果你提供了一个超过范围的值,例如'170824304520',那这就不是一个有效的 Date 字面值。 YYYYMMDDHHMMSS 或者 YYMMDDHHMMSS 注意这里没有单引号或者双引号,是一个数字。例如 20170824104520表示为 '2017-08-24 10:45:20'。 DATETIME 或者 TIMESTAMP 值可以接一个小数部分,用来表示微秒(精度最多到小数点后 6 位),用小数点 . 分隔。Dates 如果 year 部分只有两个数字,这是有歧义的(推荐使用四个数字的格式),TiDB 会尝试用以下的规则来解释: year 值如果在 70-99 范围,那么被转换成 1970-1999。 year 值如果在 00-69 范围,那么被转换成 2000-2069。 对于小于 10 的 month 或者 day 值,'2017-8-4' 跟 '2017-08-04' 是一样的。对于 Time 也是一样,比如 '2017-08-24 1:2:3' 跟 '2017-08-24 01:02:03'是一样的。在需要 Date 或者 Time 的语境下, 对于数值,TiDB 会根据数值的长度来选定指定的格式: 6 个数字,会被解释为 YYMMDD。 12 个数字,会被解释为 YYMMDDHHMMSS。 8 个数字,会解释为 YYYYMMDD。 14 个数字,会被解释为 YYYYMMDDHHMMSS。 对于 Time 类型,TiDB 用以下格式来表示: 'D HH:MM:SS',或者 'HH:MM:SS','HH:MM','D HH:MM','D HH','SS',这里的 D 表示 days,合法的范围是 0-34。 数值 HHMMSS,例如 231010 被解释为'23:10:10'。 数值 SS,MMSS,HHMMSS 都是可以被当做 Time。 Time 类型的小数点也是 .,精度最多小数点后 6 位。更多细节。Boolean Literals 常量 TRUE 和 FALSE 等于 1 和 0,它是大小写不敏感的。mysql> SELECT TRUE, true, tRuE, FALSE, FaLsE, false; +------+------+------+-------+-------+-------+ | TRUE | true | tRuE | FALSE | FaLsE | false | +------+------+------+-------+-------+-------+ | 1 | 1 | 1 | 0 | 0 | 0 | +------+------+------+-------+-------+-------+ 1 row in set (0.00 sec) Bit-Value Literals 位值字面值用 b 或者 0b 做前缀,后接以 0 跟 1 组成的二进制数字。其中 0b 是区分大小写的,0B 是会报错的。合法的 Bit-value: b’01’ B’01’ 0b01 非法的 Bit-value: b’2’ (2 不是二进制数值, 必须为 0 或 1) 0B01 (0B 必须是小写 0b) 默认情况,位值字面值是一个二进制字符串。Bit-value 是作为二进制返回的,所以输出到 MySQL Client 可能会显示不出来,如果要转换为可打印的字符,可以使用内建函数 BIN() 或者 HEX():CREATE TABLE t (b BIT(8)); INSERT INTO t SET b = b'00010011'; INSERT INTO t SET b = b'1110'; INSERT INTO t SET b = b'100101'; mysql> SELECT b+0, BIN(b), HEX(b) FROM t; +------+--------+--------+ | b+0 | BIN(b) | HEX(b) | +------+--------+--------+ | 19 | 10011 | 13 | | 14 | 1110 | E | | 37 | 100101 | 25 | +------+--------+--------+ 3 rows in set (0.00 sec)"}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/literal-values/", "title": "字面值", "content": " 字面值 String Literals String Literals 是一个 bytes 或者 characters 的序列,两端被单引号 ' 或者双引号 " 包围,例如:'example string' "example string" 如果字符串是连续的,会被合并为一个独立的 string。以下表示是一样的:'a string' 'a' ' ' 'string' "a" ' ' "string" 如果 ANSI_QUOTES SQL MODE 开启了,那么只有单引号内的会被认为是 String Literals,对于双引号内的字符串,会被认为是一个 identifier。binary string 是一串 bytes 组成的字符串,每一个 binary string 有一个叫做 binary 的 character set 和 collation。一个非二进制的字符串是一个由字符组成的字符串,它有除 binary 外的 character set和与之兼容的 collation。对于两种字符串类型,比较都是基于每个字符的数值。对于 binary string 而言,比较单元就是字节,对于非二进制的字符串,那么单元就是字符,而有的字符集支持多字节字符。一个 String Literal 可以拥有一个可选的 character set introducer 和 COLLATE clause,可以用来指派特定的字符集跟 collation(TiDB 对此只是做了语法上的兼容,并不实质做处理)。[_charset_name]'string' [COLLATE collation_name] 例如:SELECT _latin1'string'; SELECT _binary'string'; SELECT _utf8'string' COLLATE utf8_bin; 你可以使用 N’literal’ 或者 n’literal’ 来创建使用 national character set 的字符串,下列语句是一样的:SELECT N'some text'; SELECT n'some text'; SELECT _utf8'some text'; 转义字符: 0: ASCII NUL (X’00’) 字符 ‘: 单引号 “: 双引号 b: 退格符号 n: 换行符 r: 回车符 t: tab 符(制表符) z: ASCII 26 (Ctrl + Z) : 反斜杠 %: % _: _ 如果要在 string literal 中使用 ' 或者 ",有以下几种办法: 在 ' 引用的字符串中,可以用 '' 来表示单引号。 在 " 引用的字符串中,可以用 "" 来表示双引号。 前面接转义符。 在 ' 中表示 " 或者在 " 中表示 ' 都不需要特别的处理。 更多细节。Numeric Literals 数值字面值包括 integer 跟 Decimal 类型跟浮点数字面值。integer 可以包括 . 作为小数点分隔,数字前可以有 - 或者 + 来表示正数或者负数。精确数值字面值可以表示为如下格式:1, .2, 3.4, -5, -6.78, +9.10.科学记数法也是被允许的,表示为如下格式:1.2E3, 1.2E-3, -1.2E3, -1.2E-3。更多细节。NULL Values NULL 代表数据为空,它是大小写不敏感的,与 N(大小写敏感) 同义。需要注意的是 NULL 跟 0 并不一样,跟空字符串 '' 也不一样。Hexadecimal Literals 十六进制字面值是有 X 和 0x 前缀的字符串,后接表示十六进制的数字。注意 0x 是大小写敏感的,不能表示为 0X。例:X'ac12' X'12AC' x'ac12' x'12AC' 0xac12 0x12AC 以下是不合法的十六进制字面值:X'1z' (z 不是合法的十六进制值) 0X12AC (0X 必须用小写的 0x) 对于使用 X'val' 格式的十六进制字面值,val 必须要有一个数字,可以在前面补一个 0 来避免语法错误。mysql> select X'aff'; ERROR 1105 (HY000): line 0 column 13 near ""hex literal: invalid hexadecimal format, must even numbers, but 3 (total length 13) mysql> select X'0aff'; +---------+ | X'0aff' | +---------+ | | +---------+ 1 row in set (0.00 sec) 默认情况,十六进制字面值是一个二进制字符串。如果需要将一个字符串或者数字转换为十六进制字面值,可以使用内建函数 HEX():mysql> SELECT HEX('TiDB'); +-------------+ | HEX('TiDB') | +-------------+ | 54694442 | +-------------+ 1 row in set (0.01 sec) mysql> SELECT X'54694442'; +-------------+ | X'54694442' | +-------------+ | TiDB | +-------------+ 1 row in set (0.00 sec) Date and Time Literals Date 跟 Time 字面值有几种格式,例如用字符串表示,或者直接用数字表示。在 TiDB 里面,当 TiDB 期望一个 Date 的时候,它会把 '2017-08-24', '20170824',20170824 当做是 Date。TiDB 的 Date 值有以下几种格式: 'YYYY-MM-DD' 或者 'YY-MM-DD',这里的 - 分隔符并不是严格的,可以是任意的标点符号。比如 '2017-08-24','2017&08&24', '2012@12^31' 都是一样的。唯一需要特别对待的是 ‘.’ 号,它被当做是小数点,用于分隔整数和小数部分。 Date 和 Time 部分可以被 ’T’ 分隔,它的作用跟空格符是一样的,例如 2017-8-24 10:42:00 跟 2017-8-24T10:42:00 是一样的。 'YYYYMMDDHHMMSS' 或者 'YYMMDDHHMMSS',例如 '20170824104520' 和 '170824104520' 被当做是 '2017-08-24 10:45:20',但是如果你提供了一个超过范围的值,例如'170824304520',那这就不是一个有效的 Date 字面值。 YYYYMMDDHHMMSS 或者 YYMMDDHHMMSS 注意这里没有单引号或者双引号,是一个数字。例如 20170824104520表示为 '2017-08-24 10:45:20'。 DATETIME 或者 TIMESTAMP 值可以接一个小数部分,用来表示微秒(精度最多到小数点后 6 位),用小数点 . 分隔。Dates 如果 year 部分只有两个数字,这是有歧义的(推荐使用四个数字的格式),TiDB 会尝试用以下的规则来解释: year 值如果在 70-99 范围,那么被转换成 1970-1999。 year 值如果在 00-69 范围,那么被转换成 2000-2069。 对于小于 10 的 month 或者 day 值,'2017-8-4' 跟 '2017-08-04' 是一样的。对于 Time 也是一样,比如 '2017-08-24 1:2:3' 跟 '2017-08-24 01:02:03'是一样的。在需要 Date 或者 Time 的语境下, 对于数值,TiDB 会根据数值的长度来选定指定的格式: 6 个数字,会被解释为 YYMMDD。 12 个数字,会被解释为 YYMMDDHHMMSS。 8 个数字,会解释为 YYYYMMDD。 14 个数字,会被解释为 YYYYMMDDHHMMSS。 对于 Time 类型,TiDB 用以下格式来表示: 'D HH:MM:SS',或者 'HH:MM:SS','HH:MM','D HH:MM','D HH','SS',这里的 D 表示 days,合法的范围是 0-34。 数值 HHMMSS,例如 231010 被解释为'23:10:10'。 数值 SS,MMSS,HHMMSS 都是可以被当做 Time。 Time 类型的小数点也是 .,精度最多小数点后 6 位。更多细节。Boolean Literals 常量 TRUE 和 FALSE 等于 1 和 0,它是大小写不敏感的。mysql> SELECT TRUE, true, tRuE, FALSE, FaLsE, false; +------+------+------+-------+-------+-------+ | TRUE | true | tRuE | FALSE | FaLsE | false | +------+------+------+-------+-------+-------+ | 1 | 1 | 1 | 0 | 0 | 0 | +------+------+------+-------+-------+-------+ 1 row in set (0.00 sec) Bit-Value Literals 位值字面值用 b 或者 0b 做前缀,后接以 0 跟 1 组成的二进制数字。其中 0b 是区分大小写的,0B 是会报错的。合法的 Bit-value: b’01’ B’01’ 0b01 非法的 Bit-value: b’2’ (2 不是二进制数值, 必须为 0 或 1) 0B01 (0B 必须是小写 0b) 默认情况,位值字面值是一个二进制字符串。Bit-value 是作为二进制返回的,所以输出到 MySQL Client 可能会显示不出来,如果要转换为可打印的字符,可以使用内建函数 BIN() 或者 HEX():CREATE TABLE t (b BIT(8)); INSERT INTO t SET b = b'00010011'; INSERT INTO t SET b = b'1110'; INSERT INTO t SET b = b'100101'; mysql> SELECT b+0, BIN(b), HEX(b) FROM t; +------+--------+--------+ | b+0 | BIN(b) | HEX(b) | +------+--------+--------+ | 19 | 10011 | 13 | | 14 | 1110 | E | | 37 | 100101 | 25 | +------+--------+--------+ 3 rows in set (0.00 sec)"}, {"url": "https://pingcap.com/docs-cn/sql/util/", "title": "实用工具语句", "content": " 实用工具语句 DESCRIBE 语句 DESCRIBE 和 EXPLAIN 是同义词,另外还可以缩写为 DESC。请参考 EXPLAIN 语句的用法。EXPLAIN 语句 {EXPLAIN | DESCRIBE | DESC} tbl_name [col_name] {EXPLAIN | DESCRIBE | DESC} [explain_type] explainable_stmt explain_type: FORMAT = format_name format_name: "DOT" explainable_stmt: { SELECT statement | DELETE statement | INSERT statement | REPLACE statement | UPDATE statement } EXPLAIN 语句详细信息参考理解 TiDB 执行计划章节。除了 MySQL 标准的结果格式之外,TiDB 还支持输出 DotGraph 结果,这时需要指定 FORMAT = "dot",示例如下:create table t(a bigint, b bigint); desc format = "dot" select A.a, B.b from t A join t B on A.a > B.b where A.a < 10; TiDB > desc format = "dot" select A.a, B.b from t A join t B on A.a > B.b where A.a < 10;desc format = "dot" select A.a, B.b from t A join t B on A.a > B.b where A.a < 10; +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | dot contents | +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | digraph HashRightJoin_7 { subgraph cluster7{ node [style=filled, color=lightgrey] color=black label = "root" "HashRightJoin_7" -> "TableReader_10" "HashRightJoin_7" -> "TableReader_12" } subgraph cluster9{ node [style=filled, color=lightgrey] color=black label = "cop" "Selection_9" -> "TableScan_8" } subgraph cluster11{ node [style=filled, color=lightgrey] color=black label = "cop" "TableScan_11" } "TableReader_10" -> "Selection_9" "TableReader_12" -> "TableScan_11" } | +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 1 row in set (0.00 sec) 如果电脑上安装了 dot 程序 (包含在 graphviz 软件包中),可以通过如下方式生成 PNG 文件:dot xx.dot -T png -O 这里的 xx.dot 是上面的语句返回结果。 如果没有安装 dot,可以将结果拷贝到这个网站,可以得到一个树状图:USE 语句 USE db_name 切换默认 Database,当 SQL 语句中的表没有显示指定 Database 时,即使用默认 Database。"}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/util/", "title": "实用工具语句", "content": " DESCRIBE 语句 DESCRIBE 和 EXPLAIN 是同义词,另外还可以缩写为 DESC。请参考 EXPLAIN 语句的用法。EXPLAIN 语句 {EXPLAIN | DESCRIBE | DESC} tbl_name [col_name] {EXPLAIN | DESCRIBE | DESC} [explain_type] explainable_stmt explain_type: FORMAT = format_name format_name: "DOT" explainable_stmt: { SELECT statement | DELETE statement | INSERT statement | REPLACE statement | UPDATE statement } EXPLAIN 语句详细信息参考理解 TiDB 执行计划章节。除了 MySQL 标准的结果格式之外,TiDB 还支持输出 DotGraph 结果,这时需要指定 FORMAT = "dot",示例如下:create table t(a bigint, b bigint); desc format = "dot" select A.a, B.b from t A join t B on A.a > B.b where A.a < 10; TiDB > desc format = "dot" select A.a, B.b from t A join t B on A.a > B.b where A.a < 10;desc format = "dot" select A.a, B.b from t A join t B on A.a > B.b where A.a < 10; +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | dot contents | +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | digraph HashRightJoin_7 { subgraph cluster7{ node [style=filled, color=lightgrey] color=black label = "root" "HashRightJoin_7" -> "TableReader_10" "HashRightJoin_7" -> "TableReader_12" } subgraph cluster9{ node [style=filled, color=lightgrey] color=black label = "cop" "Selection_9" -> "TableScan_8" } subgraph cluster11{ node [style=filled, color=lightgrey] color=black label = "cop" "TableScan_11" } "TableReader_10" -> "Selection_9" "TableReader_12" -> "TableScan_11" } | +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 1 row in set (0.00 sec) 如果电脑上安装了 dot 程序 (包含在 graphviz 软件包中),可以通过如下方式生成 PNG 文件:dot xx.dot -T png -O 这里的 xx.dot 是上面的语句返回结果。 如果没有安装 dot,可以将结果拷贝到这个网站,可以得到一个树状图:USE 语句 USE db_name 切换默认 Database,当 SQL 语句中的表没有显示指定 Database 时,即使用默认 Database。"}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/util/", "title": "实用工具语句", "content": " DESCRIBE 语句 DESCRIBE 和 EXPLAIN 是同义词,另外还可以缩写为 DESC。请参考 EXPLAIN 语句的用法。EXPLAIN 语句 {EXPLAIN | DESCRIBE | DESC} tbl_name [col_name] {EXPLAIN | DESCRIBE | DESC} [explain_type] explainable_stmt explain_type: FORMAT = format_name format_name: "DOT" explainable_stmt: { SELECT statement | DELETE statement | INSERT statement | REPLACE statement | UPDATE statement } EXPLAIN 语句详细信息参考理解 TiDB 执行计划章节。除了 MySQL 标准的结果格式之外,TiDB 还支持输出 DotGraph 结果,这时需要指定 FORMAT = "dot",示例如下:create table t(a bigint, b bigint); desc format = "dot" select A.a, B.b from t A join t B on A.a > B.b where A.a < 10; TiDB > desc format = "dot" select A.a, B.b from t A join t B on A.a > B.b where A.a < 10;desc format = "dot" select A.a, B.b from t A join t B on A.a > B.b where A.a < 10; +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | dot contents | +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | digraph HashRightJoin_7 { subgraph cluster7{ node [style=filled, color=lightgrey] color=black label = "root" "HashRightJoin_7" -> "TableReader_10" "HashRightJoin_7" -> "TableReader_12" } subgraph cluster9{ node [style=filled, color=lightgrey] color=black label = "cop" "Selection_9" -> "TableScan_8" } subgraph cluster11{ node [style=filled, color=lightgrey] color=black label = "cop" "TableScan_11" } "TableReader_10" -> "Selection_9" "TableReader_12" -> "TableScan_11" } | +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 1 row in set (0.00 sec) 如果电脑上安装了 dot 程序 (包含在 graphviz 软件包中),可以通过如下方式生成 PNG 文件:dot xx.dot -T png -O 这里的 xx.dot 是上面的语句返回结果。 如果没有安装 dot,可以将结果拷贝到这个网站,可以得到一个树状图:USE 语句 USE db_name 切换默认 Database,当 SQL 语句中的表没有显示指定 Database 时,即使用默认 Database。"}, {"url": "https://pingcap.com/docs-cn/op-guide/security/", "title": "开启 TLS 验证", "content": " 开启 TLS 验证 概述 本文档介绍 TiDB 集群如何开启 TLS 验证,其支持: TiDB 组件之间的双向验证,包括 TiDB、TiKV、PD 相互之间,TiKV Control 与 TiKV、PD Control 与 PD 的双向认证,以及 TiKV peer 之间、PD peer 之间。一旦开启,所有组件之间均使用验证,不支持只开启某一部分的验证。 MySQL Client 与 TiDB 之间的客户端对服务器身份的单向验证以及双向验证。 MySQL Client 与 TiDB 之间使用一套证书,TiDB 集群组件之间使用另外一套证书。TiDB 集群组件间开启 TLS(双向认证) 准备证书 推荐为 TiDB、TiKV、PD 分别准备一个 server 证书,并保证可以相互验证,而它们的各种客户端共用 client 证书。有多种工具可以生成自签名证书,如 openssl,easy-rsa,cfssl。这里提供一个使用 cfssl 生成证书的示例:生成自签名证书。配置证书 TiDB 在 config 文件或命令行参数中设置:[security] # Path of file that contains list of trusted SSL CAs for connection with cluster components. cluster-ssl-ca = "/path/to/ca.pem" # Path of file that contains X509 certificate in PEM format for connection with cluster components. cluster-ssl-cert = "/path/to/tidb-server.pem" # Path of file that contains X509 key in PEM format for connection with cluster components. cluster-ssl-key = "/path/to/tidb-server-key.pem" TiKV 在 config 文件或命令行参数中设置,并设置相应 url 为 https:[security] # set the path for certificates. Empty string means disabling secure connectoins. ca-path = "/path/to/ca.pem" cert-path = "/path/to/client.pem" key-path = "/path/to/client-key.pem" PD 在 config 文件或命令行参数中设置,并设置相应 url 为 https:[security] # Path of file that contains list of trusted SSL CAs. if set, following four settings shouldn't be empty cacert-path = "/path/to/ca.pem" # Path of file that contains X509 certificate in PEM format. cert-path = "/path/to/server.pem" # Path of file that contains X509 key in PEM format. key-path = "/path/to/server-key.pem" 此时 TiDB 集群各个组件间便开启了双向验证。在使用客户端连接时,需要指定 client 证书,示例:./pd-ctl -u https://127.0.0.1:2379 --cacert /path/to/ca.pem --cert /path/to/pd-client.pem --key /path/to/pd-client-key.pem ./tikv-ctl --host="127.0.0.1:20160" --ca-path="/path/to/ca.pem" --cert-path="/path/to/client.pem" --key-path="/path/to/clinet-key.pem" MySQL 与 TiDB 间开启 TLS 准备证书 mysql_ssl_rsa_setup --datadir=certs 配置单向认证 在 TiDB 的 config 文件或命令行参数中设置:[security] # Path of file that contains list of trusted SSL CAs. ssl-ca = "" # Path of file that contains X509 certificate in PEM format. ssl-cert = "/path/to/certs/server.pem" # Path of file that contains X509 key in PEM format. ssl-key = "/path/to/certs/server-key.pem" 客户端mysql -u root --host 127.0.0.1 --port 4000 --ssl-mode=REQUIRED 配置双向认证 在 TiDB 的 config 文件或命令行参数中设置:[security] # Path of file that contains list of trusted SSL CAs for connection with mysql client. ssl-ca = "/path/to/certs/ca.pem" # Path of file that contains X509 certificate in PEM format for connection with mysql client. ssl-cert = "/path/to/certs/server.pem" # Path of file that contains X509 key in PEM format for connection with mysql client. ssl-key = "/path/to/certs/server-key.pem" 客户端需要指定 client 证书mysql -u root --host 127.0.0.1 --port 4000 --ssl-cert=/path/to/certs/client-cert.pem --ssl-key=/path/to/certs/client-key.pem --ssl-ca=/path/to/certs/ca.pem --ssl-mode=VERIFY_IDENTITY"}, {"url": "https://pingcap.com/docs-cn/v1.0/op-guide/security/", "title": "开启 TLS 验证", "content": " 开启 TLS 验证 概述 本文档介绍 TiDB 集群如何开启 TLS 验证,其支持: TiDB 组件之间的双向验证,包括 TiDB、TiKV、PD 相互之间,TiKV Control 与 TiKV、PD Control 与 PD 的双向认证,以及 TiKV peer 之间、PD peer 之间。一旦开启,所有组件之间均使用验证,不支持只开启某一部分的验证。 MySQL Client 与 TiDB 之间的客户端对服务器身份的单向验证以及双向验证。 MySQL Client 与 TiDB 之间使用一套证书,TiDB 集群组件之间使用另外一套证书。TiDB 集群组件间开启 TLS(双向认证) 准备证书 推荐为 TiDB、TiKV、PD 分别准备一个 server 证书,并保证可以相互验证,而它们的各种客户端共用 client 证书。有多种工具可以生成自签名证书,如 openssl,easy-rsa,cfssl。这里提供一个使用 cfssl 生成证书的示例:生成自签名证书。配置证书 TiDB 在 config 文件或命令行参数中设置:[security] # Path of file that contains list of trusted SSL CAs for connection with cluster components. cluster-ssl-ca = "/path/to/ca.pem" # Path of file that contains X509 certificate in PEM format for connection with cluster components. cluster-ssl-cert = "/path/to/tidb-server.pem" # Path of file that contains X509 key in PEM format for connection with cluster components. cluster-ssl-key = "/path/to/tidb-server-key.pem" TiKV 在 config 文件或命令行参数中设置,并设置相应 url 为 https:[security] # set the path for certificates. Empty string means disabling secure connectoins. ca-path = "/path/to/ca.pem" cert-path = "/path/to/client.pem" key-path = "/path/to/client-key.pem" PD 在 config 文件或命令行参数中设置,并设置相应 url 为 https:[security] # Path of file that contains list of trusted SSL CAs. if set, following four settings shouldn't be empty cacert-path = "/path/to/ca.pem" # Path of file that contains X509 certificate in PEM format. cert-path = "/path/to/server.pem" # Path of file that contains X509 key in PEM format. key-path = "/path/to/server-key.pem" 此时 TiDB 集群各个组件间便开启了双向验证。在使用客户端连接时,需要指定 client 证书,示例:./pd-ctl -u https://127.0.0.1:2379 --cacert /path/to/ca.pem --cert /path/to/pd-client.pem --key /path/to/pd-client-key.pem ./tikv-ctl --host="127.0.0.1:20160" --ca-path="/path/to/ca.pem" --cert-path="/path/to/client.pem" --key-path="/path/to/clinet-key.pem" MySQL 与 TiDB 间开启 TLS 准备证书 mysql_ssl_rsa_setup --datadir=certs 配置单向认证 在 TiDB 的 config 文件或命令行参数中设置:[security] # Path of file that contains list of trusted SSL CAs. ssl-ca = "" # Path of file that contains X509 certificate in PEM format. ssl-cert = "/path/to/certs/server.pem" # Path of file that contains X509 key in PEM format. ssl-key = "/path/to/certs/server-key.pem" 客户端mysql -u root --host 127.0.0.1 --port 4000 --ssl-mode=REQUIRED 配置双向认证 在 TiDB 的 config 文件或命令行参数中设置:[security] # Path of file that contains list of trusted SSL CAs for connection with mysql client. ssl-ca = "/path/to/certs/ca.pem" # Path of file that contains X509 certificate in PEM format for connection with mysql client. ssl-cert = "/path/to/certs/server.pem" # Path of file that contains X509 key in PEM format for connection with mysql client. ssl-key = "/path/to/certs/server-key.pem" 客户端需要指定 client 证书mysql -u root --host 127.0.0.1 --port 4000 --ssl-cert=/path/to/certs/client-cert.pem --ssl-key=/path/to/certs/client-key.pem --ssl-ca=/path/to/certs/ca.pem --ssl-mode=VERIFY_IDENTITY"}, {"url": "https://pingcap.com/docs-cn/v2.0/op-guide/security/", "title": "开启 TLS 验证", "content": " 开启 TLS 验证 概述 本文档介绍 TiDB 集群如何开启 TLS 验证,其支持: TiDB 组件之间的双向验证,包括 TiDB、TiKV、PD 相互之间,TiKV Control 与 TiKV、PD Control 与 PD 的双向认证,以及 TiKV peer 之间、PD peer 之间。一旦开启,所有组件之间均使用验证,不支持只开启某一部分的验证。 MySQL Client 与 TiDB 之间的客户端对服务器身份的单向验证以及双向验证。 MySQL Client 与 TiDB 之间使用一套证书,TiDB 集群组件之间使用另外一套证书。TiDB 集群组件间开启 TLS(双向认证) 准备证书 推荐为 TiDB、TiKV、PD 分别准备一个 server 证书,并保证可以相互验证,而它们的各种客户端共用 client 证书。有多种工具可以生成自签名证书,如 openssl,easy-rsa,cfssl。这里提供一个使用 cfssl 生成证书的示例:生成自签名证书。配置证书 TiDB 在 config 文件或命令行参数中设置:[security] # Path of file that contains list of trusted SSL CAs for connection with cluster components. cluster-ssl-ca = "/path/to/ca.pem" # Path of file that contains X509 certificate in PEM format for connection with cluster components. cluster-ssl-cert = "/path/to/tidb-server.pem" # Path of file that contains X509 key in PEM format for connection with cluster components. cluster-ssl-key = "/path/to/tidb-server-key.pem" TiKV 在 config 文件或命令行参数中设置,并设置相应 url 为 https:[security] # set the path for certificates. Empty string means disabling secure connectoins. ca-path = "/path/to/ca.pem" cert-path = "/path/to/client.pem" key-path = "/path/to/client-key.pem" PD 在 config 文件或命令行参数中设置,并设置相应 url 为 https:[security] # Path of file that contains list of trusted SSL CAs. if set, following four settings shouldn't be empty cacert-path = "/path/to/ca.pem" # Path of file that contains X509 certificate in PEM format. cert-path = "/path/to/server.pem" # Path of file that contains X509 key in PEM format. key-path = "/path/to/server-key.pem" 此时 TiDB 集群各个组件间便开启了双向验证。在使用客户端连接时,需要指定 client 证书,示例:./pd-ctl -u https://127.0.0.1:2379 --cacert /path/to/ca.pem --cert /path/to/pd-client.pem --key /path/to/pd-client-key.pem ./tikv-ctl --host="127.0.0.1:20160" --ca-path="/path/to/ca.pem" --cert-path="/path/to/client.pem" --key-path="/path/to/clinet-key.pem" MySQL 与 TiDB 间开启 TLS 准备证书 mysql_ssl_rsa_setup --datadir=certs 配置单向认证 在 TiDB 的 config 文件或命令行参数中设置:[security] # Path of file that contains list of trusted SSL CAs. ssl-ca = "" # Path of file that contains X509 certificate in PEM format. ssl-cert = "/path/to/certs/server.pem" # Path of file that contains X509 key in PEM format. ssl-key = "/path/to/certs/server-key.pem" 客户端mysql -u root --host 127.0.0.1 --port 4000 --ssl-mode=REQUIRED 配置双向认证 在 TiDB 的 config 文件或命令行参数中设置:[security] # Path of file that contains list of trusted SSL CAs for connection with mysql client. ssl-ca = "/path/to/certs/ca.pem" # Path of file that contains X509 certificate in PEM format for connection with mysql client. ssl-cert = "/path/to/certs/server.pem" # Path of file that contains X509 key in PEM format for connection with mysql client. ssl-key = "/path/to/certs/server-key.pem" 客户端需要指定 client 证书mysql -u root --host 127.0.0.1 --port 4000 --ssl-cert=/path/to/certs/client-cert.pem --ssl-key=/path/to/certs/client-key.pem --ssl-ca=/path/to/certs/ca.pem --ssl-mode=VERIFY_IDENTITY"}, {"url": "https://pingcap.com/docs-cn/v1.0/QUICKSTART/", "title": "快速入门指南", "content": " TiDB 快速入门指南 关于 TiDB TiDB 是开源分布式 SQL 数据库,结合了传统的 RDBMS 和 NoSQL 的最佳特性。TiDB 兼容 MySQL,支持无限的水平扩展,具备强一致性和高可用性。TiDB 的目标是为在线事务和分析提供一站式的解决方案。关于本指南 本指南为您介绍如何使用 TiDB-Ansible 快速部署一个 TiDB 集群,并了解 TiDB 的基本操作和管理。TiDB 集群部署 本节具体介绍如何部署一个 TiDB 集群。一个 TiDB 集群由不同的模块组成,包括:TiDB 服务器、TiKV 服务器、Placement Driver (PD) 服务器。架构图如下所示:参考TiDB Ansible 部署方案。TiDB 基本操作 本节具体介绍 TiDB 中基本的增删改查操作。创建、查看和删除数据库 使用 CREATE DATABASE 语句创建数据库。语法如下:CREATE DATABASE db_name [options]; 例如,要创建一个名为 samp_db 的数据库,可使用以下语句:CREATE DATABASE IF NOT EXISTS samp_db; 使用 SHOW DATABASES 语句查看数据库:SHOW DATABASES; 使用 DROP DATABASE 语句删除数据库,例如:DROP DATABASE samp_db; 创建、查看和删除表 使用 CREATE TABLE 语句创建表。语法如下:CREATE TABLE table_name column_name data_type constraint; 例如:CREATE TABLE person ( number INT(11), name VARCHAR(255), birthday DATE ); 如果表已存在,添加 IF NOT EXISTS 可防止发生错误:CREATE TABLE IF NOT EXISTS person ( number INT(11), name VARCHAR(255), birthday DATE ); 使用 SHOW CREATE 语句查看建表语句。例如:SHOW CREATE table person; 使用 SHOW FULL COLUMNS 语句查看表的列。 例如:SHOW FULL COLUMNS FROM person; 使用 DROP TABLE 语句删除表。例如:DROP TABLE person; 或者DROP TABLE IF EXISTS person; 使用 SHOW TABLES 语句查看数据库中的所有表。例如:SHOW TABLES FROM samp_db; 创建、查看和删除索引 对于值不唯一的列,可使用 CREATE INDEX 或 ALTER TABLE 语句。例如:CREATE INDEX person_num ON person (number); 或者ALTER TABLE person ADD INDEX person_num (number); 对于值唯一的列,可以创建唯一索引。例如:CREATE UNIQUE INDEX person_num ON person (number); 或者ALTER TABLE person ADD UNIQUE person_num on (number); 使用 SHOW INDEX 语句查看表内所有索引:SHOW INDEX from person; 使用 ALTER TABLE 或 DROP INDEX 语句来删除索引。与 CREATE INDEX 语句类似,DROP INDEX 也可以嵌入 ALTER TABLE 语句。例如:DROP INDEX person_num ON person; ALTER TABLE person DROP INDEX person_num; 增删改查数据 使用 INSERT 语句向表内插入数据。例如:INSERT INTO person VALUES("1","tom","20170912"); 使用 SELECT 语句检索表内数据。例如:SELECT * FROM person; +--------+------+------------+ | number | name | birthday | +--------+------+------------+ | 1 | tom | 2017-09-12 | +--------+------+------------+ 使用 UPDATE 语句修改表内数据。例如:UPDATE person SET birthday='20171010' WHERE name='tom'; SELECT * FROM person; +--------+------+------------+ | number | name | birthday | +--------+------+------------+ | 1 | tom | 2017-10-10 | +--------+------+------------+ 使用 DELETE 语句删除表内数据:DELETE FROM person WHERE number=1; SELECT * FROM person; Empty set (0.00 sec) 创建、授权和删除用户 使用 CREATE USER 语句创建一个用户 tiuser,密码为 123456:CREATE USER 'tiuser'@'localhost' IDENTIFIED BY '123456'; 授权用户 tiuser 可检索数据库 samp_db 内的表:GRANT SELECT ON samp_db .* TO 'tiuser'@'localhost'; 查询用户 tiuser 的权限:SHOW GRANTS for tiuser@localhost; 删除用户 tiuser:DROP USER 'tiuser'@'localhost'; TiDB 集群监控 打开浏览器,访问以下监控平台:地址:http://172.16.10.3:3000, 默认帐户和密码为:admin@admin。重要监控指标详解 PD Storage Capacity : TiDB 集群总可用数据库空间大小 Current Storage Size : TiDB 集群目前已用数据库空间大小 Store Status – up store : TiKV 正常节点数量 Store Status – down store : TiKV 异常节点数量如果大于 0,证明有节点不正常 Store Status – offline store : 手动执行下线操作 TiKV 节点数量 Store Status – Tombstone store : 下线成功的 TiKV 节点数量 Current storage usage : TiKV 集群存储空间占用率超过 80% 应考虑添加 TiKV 节点 99% completed_cmds_duration_seconds : 99% pd-server 请求完成时间小于 5ms average completed_cmds_duration_seconds : pd-server 请求平均完成时间小于 50ms leader balance ratio : leader ratio 最大的节点与最小的节点的差均衡状况下一般小于 5%,节点重启时会比较大 region balance ratio : region ratio 最大的节点与最小的节点的差均衡状况下一般小于 5%,新增/下线节点时会比较大 TiDB handle_requests_duration_seconds : 请求 PD 获取 TSO 响应时间小于 100ms tidb server QPS : 集群的请求量 connection count : 从业务服务器连接到数据库的连接数和业务相关。但是如果连接数发生跳变,需要查明原因。比如突然掉为 0,可以检查网络是否中断; 如果突然上涨,需要检查业务。 statement count : 单位时间内不同类型语句执行的数目 Query Duration 99th percentile : 99% 的 query 时间 TiKV 99% & 99.99% scheduler command duration : 99% & 99.99% 命令执行的时间99% 小于 50ms;99.99% 小于 100ms 95% & 99% storage async_request duration : 95% & 99% Raft 命令执行时间95% 小于 50ms;99% 小于 100ms server report failure message : 发送失败或者收到了错误的 message如果出现了大量的 unreachadble 的消息,表明系统网络出现了问题。如果有 store not match 这样的错误, 表明收到了不属于这个集群发过来的消息 Vote : Raft vote 的频率通常这个值只会在发生 split 的时候有变动,如果长时间出现了 vote 偏高的情况,证明系统出现了严重的问题, 有一些节点无法工作了 95% & 99% coprocessor request duration : 95% & 99% coprocessor 执行时间和业务相关,但通常不会出现持续高位的值 Pending task : 累积的任务数量除了 pd worker,其他任何偏高都属于异常 stall : RocksDB Stall 时间大于 0,表明 RocksDB 忙不过来,需要注意 IO 和 CPU 了 channel full : channel 满了,表明线程太忙无法处理如果大于 0,表明线程已经没法处理了 95% send_message_duration_seconds : 95% 发送消息的时间小于 50ms leader/region : 每个 TiKV 的 leader/region 数量 TiDB 集群扩容缩容方案 TiDB 集群可以在不影响线上服务的情况下进行扩容和缩容。以下缩容示例中,被移除的节点没有混合部署其他服务;如果混合部署了其他服务,不能按如下操作。假设拓扑结构如下所示: Name Host IP Services node1 172.16.10.1 PD1 node2 172.16.10.2 PD2 node3 172.16.10.3 PD3, Monitor node4 172.16.10.4 TiDB1 node5 172.16.10.5 TiDB2 node6 172.16.10.6 TiKV1 node7 172.16.10.7 TiKV2 node8 172.16.10.8 TiKV3 node9 172.16.10.9 TiKV4 扩容 TiDB/TiKV 节点 例如,如果要添加两个 TiDB 节点 (node101、node102),IP 地址为 172.16.10.101、172.16.10.102,可以进行如下操作: 编辑 inventory.ini 文件,添加节点信息:[tidb_servers] 172.16.10.4 172.16.10.5 172.16.10.101 172.16.10.102 [pd_servers] 172.16.10.1 172.16.10.2 172.16.10.3 [tikv_servers] 172.16.10.6 172.16.10.7 172.16.10.8 172.16.10.9 [monitored_servers] 172.16.10.1 172.16.10.2 172.16.10.3 172.16.10.4 172.16.10.5 172.16.10.6 172.16.10.7 172.16.10.8 172.16.10.9 172.16.10.101 172.16.10.102 [monitoring_servers] 172.16.10.3 [grafana_servers] 172.16.10.3 现在拓扑结构如下所示: Name Host IP Services node1 172.16.10.1 PD1 node2 172.16.10.2 PD2 node3 172.16.10.3 PD3, Monitor node4 172.16.10.4 TiDB1 node5 172.16.10.5 TiDB2 node101 172.16.10.101 TiDB3 node102 172.16.10.102 TiDB4 node6 172.16.10.6 TiKV1 node7 172.16.10.7 TiKV2 node8 172.16.10.8 TiKV3 node9 172.16.10.9 TiKV4 初始化新增节点:ansible-playbook bootstrap.yml -l 172.16.10.101,172.16.10.102 部署新增节点:ansible-playbook deploy.yml -l 172.16.10.101,172.16.10.102 启动新节点服务:ansible-playbook start.yml -l 172.16.10.101,172.16.10.102 更新 Prometheus 配置并重启:ansible-playbook rolling_update_monitor.yml --tags=prometheus 打开浏览器访问监控平台:http://172.16.10.3:3000,监控整个集群和新增节点的状态。 可使用同样的步骤添加 TiKV 节点。但如果要添加 PD 节点,则需手动更新一些配置文件。扩容 PD 节点 例如,如果要添加一个 PD 节点 (node103),IP 地址为 172.16.10.103,可以进行如下操作: 编辑 inventory.ini 文件,添加节点信息:[tidb_servers] 172.16.10.4 172.16.10.5 [pd_servers] 172.16.10.1 172.16.10.2 172.16.10.3 172.16.10.103 [tikv_servers] 172.16.10.6 172.16.10.7 172.16.10.8 172.16.10.9 [monitored_servers] 172.16.10.4 172.16.10.5 172.16.10.1 172.16.10.2 172.16.10.3 172.16.10.103 172.16.10.6 172.16.10.7 172.16.10.8 172.16.10.9 [monitoring_servers] 172.16.10.3 [grafana_servers] 172.16.10.3 现在拓扑结构如下所示: Name Host IP Services node1 172.16.10.1 PD1 node2 172.16.10.2 PD2 node3 172.16.10.3 PD3, Monitor node103 172.16.10.103 PD4 node4 172.16.10.4 TiDB1 node5 172.16.10.5 TiDB2 node6 172.16.10.6 TiKV1 node7 172.16.10.7 TiKV2 node8 172.16.10.8 TiKV3 node9 172.16.10.9 TiKV4 初始化新增节点:ansible-playbook bootstrap.yml -l 172.16.10.103 部署新增节点:ansible-playbook deploy.yml -l 172.16.10.103 登录新增的 PD 节点,编辑启动脚本:{deploy_dir}/scripts/run_pd.sh 移除 --initial-cluster="xxxx" 配置 添加 --join="http://172.16.10.1:2379" 。IP 地址 (172.16.10.1) 可以是集群内现有 PD IP 地址中的任意一个 在新增 PD 节点中手动启动 PD 服务: {deploy_dir}/scripts/start_pd.sh 使用 pd-ctl 检查新节点是否添加成功: ./pd-ctl -u "http://172.16.10.1:2379" 注: pd-ctl 命令用于查询 PD 节点的数量。 滚动升级整个集群:ansible-playbook rolling_update.yml 更新 Prometheus 配置并重启:ansible-playbook rolling_update_monitor.yml --tags=prometheus 打开浏览器访问监控平台:http://172.16.10.3:3000,监控整个集群和新增节点的状态。 缩容 TiDB 节点 例如,如果要移除一个 TiDB 节点 (node5),IP 地址为 172.16.10.5,可以进行如下操作: 停止 node5 节点上的服务:ansible-playbook stop.yml -l 172.16.10.5 编辑 inventory.ini 文件,移除节点信息:[tidb_servers] 172.16.10.4 #172.16.10.5 # 注释被移除节点 [pd_servers] 172.16.10.1 172.16.10.2 172.16.10.3 [tikv_servers] 172.16.10.6 172.16.10.7 172.16.10.8 172.16.10.9 [monitored_servers] 172.16.10.4 #172.16.10.5 # 注释被移除节点 172.16.10.1 172.16.10.2 172.16.10.3 172.16.10.6 172.16.10.7 172.16.10.8 172.16.10.9 [monitoring_servers] 172.16.10.3 [grafana_servers] 172.16.10.3 现在拓扑结构如下所示: Name Host IP Services node1 172.16.10.1 PD1 node2 …"}, {"url": "https://pingcap.com/docs-cn/v2.0/QUICKSTART/", "title": "快速入门指南", "content": " TiDB 快速入门指南 关于 TiDB TiDB 是开源分布式 SQL 数据库,结合了传统的 RDBMS 和 NoSQL 的最佳特性。TiDB 兼容 MySQL,支持无限的水平扩展,具备强一致性和高可用性。TiDB 的目标是为在线事务和分析提供一站式的解决方案。关于本指南 本指南为您介绍如何使用 TiDB-Ansible 快速部署一个 TiDB 集群,并了解 TiDB 的基本操作和管理。TiDB 集群部署 本节具体介绍如何部署一个 TiDB 集群。一个 TiDB 集群由不同的模块组成,包括:TiDB 服务器、TiKV 服务器、Placement Driver (PD) 服务器。架构图如下所示:参考TiDB Ansible 部署方案。TiDB 基本操作 本节具体介绍 TiDB 中基本的增删改查操作。创建、查看和删除数据库 使用 CREATE DATABASE 语句创建数据库。语法如下:CREATE DATABASE db_name [options]; 例如,要创建一个名为 samp_db 的数据库,可使用以下语句:CREATE DATABASE IF NOT EXISTS samp_db; 使用 SHOW DATABASES 语句查看数据库:SHOW DATABASES; 使用 DROP DATABASE 语句删除数据库,例如:DROP DATABASE samp_db; 创建、查看和删除表 使用 CREATE TABLE 语句创建表。语法如下:CREATE TABLE table_name column_name data_type constraint; 例如:CREATE TABLE person ( number INT(11), name VARCHAR(255), birthday DATE ); 如果表已存在,添加 IF NOT EXISTS 可防止发生错误:CREATE TABLE IF NOT EXISTS person ( number INT(11), name VARCHAR(255), birthday DATE ); 使用 SHOW CREATE 语句查看建表语句。例如:SHOW CREATE table person; 使用 SHOW FULL COLUMNS 语句查看表的列。 例如:SHOW FULL COLUMNS FROM person; 使用 DROP TABLE 语句删除表。例如:DROP TABLE person; 或者DROP TABLE IF EXISTS person; 使用 SHOW TABLES 语句查看数据库中的所有表。例如:SHOW TABLES FROM samp_db; 创建、查看和删除索引 对于值不唯一的列,可使用 CREATE INDEX 或 ALTER TABLE 语句。例如:CREATE INDEX person_num ON person (number); 或者ALTER TABLE person ADD INDEX person_num (number); 对于值唯一的列,可以创建唯一索引。例如:CREATE UNIQUE INDEX person_num ON person (number); 或者ALTER TABLE person ADD UNIQUE person_num on (number); 使用 SHOW INDEX 语句查看表内所有索引:SHOW INDEX from person; 使用 ALTER TABLE 或 DROP INDEX 语句来删除索引。与 CREATE INDEX 语句类似,DROP INDEX 也可以嵌入 ALTER TABLE 语句。例如:DROP INDEX person_num ON person; ALTER TABLE person DROP INDEX person_num; 增删改查数据 使用 INSERT 语句向表内插入数据。例如:INSERT INTO person VALUES("1","tom","20170912"); 使用 SELECT 语句检索表内数据。例如:SELECT * FROM person; +--------+------+------------+ | number | name | birthday | +--------+------+------------+ | 1 | tom | 2017-09-12 | +--------+------+------------+ 使用 UPDATE 语句修改表内数据。例如:UPDATE person SET birthday='20171010' WHERE name='tom'; SELECT * FROM person; +--------+------+------------+ | number | name | birthday | +--------+------+------------+ | 1 | tom | 2017-10-10 | +--------+------+------------+ 使用 DELETE 语句删除表内数据:DELETE FROM person WHERE number=1; SELECT * FROM person; Empty set (0.00 sec) 创建、授权和删除用户 使用 CREATE USER 语句创建一个用户 tiuser,密码为 123456:CREATE USER 'tiuser'@'localhost' IDENTIFIED BY '123456'; 授权用户 tiuser 可检索数据库 samp_db 内的表:GRANT SELECT ON samp_db.* TO 'tiuser'@'localhost'; 查询用户 tiuser 的权限:SHOW GRANTS for tiuser@localhost; 删除用户 tiuser:DROP USER 'tiuser'@'localhost'; TiDB 集群监控 打开浏览器,访问以下监控平台:地址:http://172.16.10.3:3000, 默认帐户和密码为:admin@admin。重要监控指标详解 PD Storage Capacity : TiDB 集群总可用数据库空间大小 Current Storage Size : TiDB 集群目前已用数据库空间大小 Store Status – up store : TiKV 正常节点数量 Store Status – down store : TiKV 异常节点数量如果大于 0,证明有节点不正常 Store Status – offline store : 手动执行下线操作 TiKV 节点数量 Store Status – Tombstone store : 下线成功的 TiKV 节点数量 Current storage usage : TiKV 集群存储空间占用率超过 80% 应考虑添加 TiKV 节点 99% completed_cmds_duration_seconds : 99% pd-server 请求完成时间小于 5ms average completed_cmds_duration_seconds : pd-server 请求平均完成时间小于 50ms leader balance ratio : leader ratio 最大的节点与最小的节点的差均衡状况下一般小于 5%,节点重启时会比较大 region balance ratio : region ratio 最大的节点与最小的节点的差均衡状况下一般小于 5%,新增/下线节点时会比较大 TiDB handle_requests_duration_seconds : 请求 PD 获取 TSO 响应时间小于 100ms tidb server QPS : 集群的请求量 connection count : 从业务服务器连接到数据库的连接数和业务相关。但是如果连接数发生跳变,需要查明原因。比如突然掉为 0,可以检查网络是否中断; 如果突然上涨,需要检查业务。 statement count : 单位时间内不同类型语句执行的数目 Query Duration 99th percentile : 99% 的 query 时间 TiKV 99% & 99.99% scheduler command duration : 99% & 99.99% 命令执行的时间99% 小于 50ms;99.99% 小于 100ms 95% & 99% storage async_request duration : 95% & 99% Raft 命令执行时间95% 小于 50ms;99% 小于 100ms server report failure message : 发送失败或者收到了错误的 message如果出现了大量的 unreachadble 的消息,表明系统网络出现了问题。如果有 store not match 这样的错误, 表明收到了不属于这个集群发过来的消息 Vote : Raft vote 的频率通常这个值只会在发生 split 的时候有变动,如果长时间出现了 vote 偏高的情况,证明系统出现了严重的问题, 有一些节点无法工作了 95% & 99% coprocessor request duration : 95% & 99% coprocessor 执行时间和业务相关,但通常不会出现持续高位的值 Pending task : 累积的任务数量除了 pd worker,其他任何偏高都属于异常 stall : RocksDB Stall 时间大于 0,表明 RocksDB 忙不过来,需要注意 IO 和 CPU 了 channel full : channel 满了,表明线程太忙无法处理如果大于 0,表明线程已经没法处理了 95% send_message_duration_seconds : 95% 发送消息的时间小于 50ms leader/region : 每个 TiKV 的 leader/region 数量 TiDB 集群扩容缩容方案 TiDB 集群可以在不影响线上服务的情况下进行扩容和缩容。以下缩容示例中,被移除的节点没有混合部署其他服务;如果混合部署了其他服务,不能按如下操作。假设拓扑结构如下所示: Name Host IP Services node1 172.16.10.1 PD1 node2 172.16.10.2 PD2 node3 172.16.10.3 PD3, Monitor node4 172.16.10.4 TiDB1 node5 172.16.10.5 TiDB2 node6 172.16.10.6 TiKV1 node7 172.16.10.7 TiKV2 node8 172.16.10.8 TiKV3 node9 172.16.10.9 TiKV4 扩容 TiDB/TiKV 节点 例如,如果要添加两个 TiDB 节点 (node101、node102),IP 地址为 172.16.10.101、172.16.10.102,可以进行如下操作: 编辑 inventory.ini 文件,添加节点信息:[tidb_servers] 172.16.10.4 172.16.10.5 172.16.10.101 172.16.10.102 [pd_servers] 172.16.10.1 172.16.10.2 172.16.10.3 [tikv_servers] 172.16.10.6 172.16.10.7 172.16.10.8 172.16.10.9 [monitored_servers] 172.16.10.1 172.16.10.2 172.16.10.3 172.16.10.4 172.16.10.5 172.16.10.6 172.16.10.7 172.16.10.8 172.16.10.9 172.16.10.101 172.16.10.102 [monitoring_servers] 172.16.10.3 [grafana_servers] 172.16.10.3 现在拓扑结构如下所示: Name Host IP Services node1 172.16.10.1 PD1 node2 172.16.10.2 PD2 node3 172.16.10.3 PD3, Monitor node4 172.16.10.4 TiDB1 node5 172.16.10.5 TiDB2 node101 172.16.10.101 TiDB3 node102 172.16.10.102 TiDB4 node6 172.16.10.6 TiKV1 node7 172.16.10.7 TiKV2 node8 172.16.10.8 TiKV3 node9 172.16.10.9 TiKV4 初始化新增节点:ansible-playbook bootstrap.yml -l 172.16.10.101,172.16.10.102 部署新增节点:ansible-playbook deploy.yml -l 172.16.10.101,172.16.10.102 启动新节点服务:ansible-playbook start.yml -l 172.16.10.101,172.16.10.102 更新 Prometheus 配置并重启:ansible-playbook rolling_update_monitor.yml --tags=prometheus 打开浏览器访问监控平台:http://172.16.10.3:3000,监控整个集群和新增节点的状态。 可使用同样的步骤添加 TiKV 节点。但如果要添加 PD 节点,则需手动更新一些配置文件。扩容 PD 节点 例如,如果要添加一个 PD 节点 (node103),IP 地址为 172.16.10.103,可以进行如下操作: 编辑 inventory.ini 文件,添加节点信息:[tidb_servers] 172.16.10.4 172.16.10.5 [pd_servers] 172.16.10.1 172.16.10.2 172.16.10.3 172.16.10.103 [tikv_servers] 172.16.10.6 172.16.10.7 172.16.10.8 172.16.10.9 [monitored_servers] 172.16.10.4 172.16.10.5 172.16.10.1 172.16.10.2 172.16.10.3 172.16.10.103 172.16.10.6 172.16.10.7 172.16.10.8 172.16.10.9 [monitoring_servers] 172.16.10.3 [grafana_servers] 172.16.10.3 现在拓扑结构如下所示: Name Host IP Services node1 172.16.10.1 PD1 node2 172.16.10.2 PD2 node3 172.16.10.3 PD3, Monitor node103 172.16.10.103 PD4 node4 172.16.10.4 TiDB1 node5 172.16.10.5 TiDB2 node6 172.16.10.6 TiKV1 node7 172.16.10.7 TiKV2 node8 172.16.10.8 TiKV3 node9 172.16.10.9 TiKV4 初始化新增节点:ansible-playbook bootstrap.yml -l 172.16.10.103 部署新增节点:ansible-playbook deploy.yml -l 172.16.10.103 登录新增的 PD 节点,编辑启动脚本:{deploy_dir}/scripts/run_pd.sh 移除 --initial-cluster="xxxx" 配置 添加 --join="http://172.16.10.1:2379" 。IP 地址 (172.16.10.1) 可以是集群内现有 PD IP 地址中的任意一个 在新增 PD 节点中手动启动 PD 服务: {deploy_dir}/scripts/start_pd.sh 使用 pd-ctl 检查新节点是否添加成功: ./pd-ctl -u "http://172.16.10.1:2379" 注: pd-ctl 命令用于查询 PD 节点的数量。 滚动升级整个集群:ansible-playbook rolling_update.yml 更新 Prometheus 配置并重启:ansible-playbook rolling_update_monitor.yml --tags=prometheus 打开浏览器访问监控平台:http://172.16.10.3:3000,监控整个集群和新增节点的状态。 缩容 TiDB 节点 例如,如果要移除一个 TiDB 节点 (node5),IP 地址为 172.16.10.5,可以进行如下操作: 停止 node5 节点上的服务:ansible-playbook stop.yml -l 172.16.10.5 编辑 inventory.ini 文件,移除节点信息:[tidb_servers] 172.16.10.4 #172.16.10.5 # 注释被移除节点 [pd_servers] 172.16.10.1 172.16.10.2 172.16.10.3 [tikv_servers] 172.16.10.6 172.16.10.7 172.16.10.8 172.16.10.9 [monitored_servers] 172.16.10.4 #172.16.10.5 # 注释被移除节点 172.16.10.1 172.16.10.2 172.16.10.3 172.16.10.6 172.16.10.7 172.16.10.8 172.16.10.9 [monitoring_servers] 172.16.10.3 [grafana_servers] 172.16.10.3 现在拓扑结构如下所示: Name Host IP Services node1 172.16.10.1 PD1 node2 …"}, {"url": "https://pingcap.com/docs-cn/sql/slow-query/", "title": "慢查询日志", "content": " 慢查询日志 一条不合理的 SQL 语句会导致整个集群压力增大,响应变慢。对于这种问题,需要用慢查询日志来定位有问题的语句,解决性能问题。获取日志 通过在 TiDB 的日志文件上 grep SLOW_QUERY 这个关键字,可以得到执行时间超过 slow-threshold 的语句日志。slow-threshold 可以通过配置文件修改,默认是 300ms。如果配置了 slow-query-file,慢查询日志会全部写在这个文件里。示例 2018/08/20 19:52:08.632 adapter.go:363: [warning] [SLOW_QUERY] cost_time:18.647928814s process_time:1m6.768s wait_time:12m11.212s backoff_time:600ms request_count:2058 total_keys:1869712 processed_keys:1869710 succ:true con:3 user:root@127.0.0.1 txn_start_ts:402329674704224261 database:test table_ids:[31],index_ids:[1], sql:select count(c) from sbtest1 use index (k_1) 字段解析 cost_time 表示执行这个语句花费的时间。只有执行时间超过 slow-threshold 的语句才会输出这个日志。process_time 表示这个语句在 TiKV 的处理时间之和,因为数据会并行的发到 TiKV 执行,这个值可能会超过 cost_time。wait_time 表示这个语句在 TiKV 的等待时间之和,因为 TiKV 的 Coprocessor 线程数是有限的,当所有的 Coprocessor 线程都在工作的时候,请求会排队,当队列中有某些请求耗时很长的时候,后面的请求的等待时间都会增加。backoff_time 表示语句遇到需要重试的错误时在重试前等待的时间,常见的需要重试的错误有以下几种:遇到了 lock、Region 分裂、tikv server is busy。request_count 表示这个语句发送的 Coprocessor 请求的数量。total_keys 表示 Coprocessor 扫过的 key 的数量processed_keys 表示 Coprocessor 处理的 key 的数量。相比 total_keys,processed_keys 不包含 MVCC 的旧版本。如果 processed_keys 和 total_keys 相差很大,说明旧版本比较多。succ 表示请求是否执行成功con 表示 connection ID,即 session ID, 可以用类似 con:3 的关键字在日志中 grep 出 session ID 为 3 的日志。user 表示执行语句的用户名txn_start_ts 表示事务的开始时间戳,也是事务的 ID, 可以用这个值在日志中 grep 出事务相关的日志。database 表示当前的 databasetable_ids 表示语句涉及到的表的 IDindex_ids 表示语句涉及到的索引的 IDsql 表示 SQL 语句定位问题语句的方法 并不是所有 SLOW_QUERY 的语句都是有问题的。会造成集群整体压力增大的,是那些 process_time 很大的语句。wait_time 很大,但 process_time 很小的语句通常不是问题语句,是因为被问题语句阻塞,在执行队列等待造成的响应时间过长。admin show slow 命令 除了获取 TiDB 日志,还有一种定位慢查询的方式是通过 admin show slow SQL 命令:admin show slow recent N admin show slow top [internal | all] N recent N 会显示最近的 N 条慢查询记录,例如:admin show slow recent 10 top N 则显示最近一段时间(大约几天)内,最慢的查询记录。如果指定 internal 选项,则返回查询系统内部 SQL 的慢查询记录;如果指定 all 选项,返回系统内部和用户 SQL 汇总以后的慢查询记录;默认只返回用户 SQL 中的慢查询记录。admin show slow top 3 admin show slow top internal 3 admin show slow top all 5 由于内存限制,保留的慢查询记录的条数是有限的。当命令查询的 N 大于记录条数时,返回的结果记录条数会小于 N。"}, {"url": "https://pingcap.com/recruit-cn/general-administrative/hr-manager/", "title": "招聘主管", "content": " 招聘主管 岗位职责: 负责公司招聘渠道的开拓和维护; 实施招聘工作,发布招聘广告、进行简历筛选、组织面试,评估候选人并提供初步面试报告,出具综合评价意见; 负责设计优化招聘流程、面试标准、面试题库,组织实施招聘; 对招聘渠道开发、维护、拓展,保证人才信息量大、层次丰富、质量高,确保招聘渠道能有效满足公司的用人需求; 总结招聘工作中存在的问题,提出优化招聘制度和流程的合理化建议; 总结和统计招聘工作各项数据,完成招聘分析报告; 配合完成其它人力资源工作。 任职要求: 本科以上学历,人力资源相关专业,2 年以上招聘工作经验; 熟悉 IT 软件、互联网、相关行业人才渠道,有销售类职位猎头招聘经验优先; 丰富的招聘经验和技巧,熟悉国家相关法律法规; 良好的职业道德及团队合作意识,良好的亲和力; 优秀的语言表达能力、沟通协调能力和分析判断力。 待遇:10K - 30K,13薪 + 奖金,优秀者可面议联系方式:hire@pingcap.com工作地点:北京,上海,广州,杭州,成都"}, {"url": "https://pingcap.com/docs-cn/sql/control-flow-functions/", "title": "控制流程函数", "content": " 控制流程函数 函数名 功能描述 CASE Case 操作符 IF() 构建 if/else IFNULL() 构建 Null if/else NULLIF() 如果 expr1 = expr2,返回 NULL "}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/control-flow-functions/", "title": "控制流程函数", "content": " 控制流程函数 函数名 功能描述 CASE Case 操作符 IF() 构建 if/else IFNULL() 构建 Null if/else NULLIF() 如果 expr1 = expr2,返回 NULL "}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/control-flow-functions/", "title": "控制流程函数", "content": " 控制流程函数 函数名 功能描述 CASE Case 操作符 IF() 构建 if/else IFNULL() 构建 Null if/else NULLIF() 如果 expr1 = expr2,返回 NULL "}, {"url": "https://pingcap.com/docs-cn/sql/operators/", "title": "操作符", "content": " 操作符 操作符名 功能描述 AND, && 逻辑与 = 赋值 (可用于 SET 语句中, 或用于 UPDATE 语句的 SET 中 ) := 赋值 BETWEEN ... AND ... 判断值满足范围 BINARY 将一个字符串转换为一个二进制字符串 & 位与 ~ 位非 | 位或 ^ 按位异或 CASE case 操作符 DIV 整数除 / 除法 = 相等比较 <=> 空值安全型相等比较 > 大于 >= 大于或等于 IS 判断一个值是否等于一个布尔值 IS NOT 判断一个值是否不等于一个布尔值 IS NOT NULL 非空判断 IS NULL 空值判断 << 左移 < 小于 <= 小于或等于 LIKE 简单模式匹配 - 减 %, MOD 求余 NOT, ! 取反 NOT BETWEEN ... AND ... 判断值是否不在范围内 !=, <> 不等于 NOT LIKE 不符合简单模式匹配 NOT REGEXP 不符合正则表达式模式匹配 ||, OR 逻辑或 + 加 REGEXP 使用正则表达式进行模式匹配 >> 右移 RLIKE REGEXP 同义词 * 乘 - 取反符号 XOR 逻辑亦或 操作符优先级 操作符优先级显示在以下列表中,从最高优先级到最低优先级。同一行显示的操作符具有相同的优先级。INTERVAL BINARY ! - (unary minus), ~ (unary bit inversion) ^ *, /, DIV, %, MOD -, + <<, >> & | = (comparison), <=>, >=, >, <=, <, <>, !=, IS, LIKE, REGEXP, IN BETWEEN, CASE, WHEN, THEN, ELSE NOT AND, && XOR OR, || = (assignment), := 详情参见 这里.比较方法和操作符 操作符名 功能描述 BETWEEN ... AND ... 判断值是否在范围内 COALESCE() 返回第一个非空值 = 相等比较 <=> 空值安全型相等比较 > 大于 >= 大于或等于 GREATEST() 返回最大值 IN() 判断值是否在一个值的集合内 INTERVAL() 返回一个小于第一个参数的参数的下标 IS 判断是否等于一个布尔值 IS NOT 判断是否不等于一个布尔值 IS NOT NULL 非空判断 IS NULL 空值判断 ISNULL() 判断参数是否为空 LEAST() 返回最小值 < 小于 <= 小于或等于 LIKE 简单模式匹配 NOT BETWEEN ... AND ... 判断值是否不在范围内 !=, <> 不等于 NOT IN() 判断值是否不在一个值的集合内 NOT LIKE 不满足简单模式匹配 STRCMP() 比较两个字符串 详情参见 这里.逻辑操作符 操作符名 功能描述 AND, && 逻辑与 NOT, ! 逻辑非 ||, OR 逻辑或 XOR 逻辑亦或 详情参见 这里.赋值操作符 操作符名 功能描述 = 赋值 (可用于 SET 语句中, 或用于 UPDATE 语句的 SET 中 ) := 赋值 详情参见 这里."}, {"url": "https://pingcap.com/docs-cn/sql/numeric-functions-and-operators/", "title": "数值函数与操作符", "content": " 数值函数与操作符 算术操作符 操作符名 功能描述 + 加号 - 减号 * 乘号 / 除号 DIV 整数除法 %, MOD 模运算,取余 - 更改参数符号 数学函数 函数名 功能描述 POW() 返回参数的指定乘方的结果值 POWER() 返回参数的指定乘方的结果值 EXP() 返回 e(自然对数的底)的指定乘方后的值 SQRT() 返回非负数的二次方根 LN() 返回参数的自然对数 LOG() 返回第一个参数的自然对数 LOG2() 返回参数以 2 为底的对数 LOG10() 返回参数以 10 为底的对数 PI() 返回 pi 的值 TAN() 返回参数的正切值 COT() 返回参数的余切值 SIN() 返回参数的正弦值 COS() 返回参数的余弦值 ATAN() 返回参数的反正切值 ATAN2(), ATAN() 返回两个参数的反正切值 ASIN() 返回参数的反正弦值 ACOS() 返回参数的反余弦值 RADIANS() 返回由度转化为弧度的参数 DEGREES() 返回由弧度转化为度的参数 MOD() 返回余数 ABS() 返回参数的绝对值 CEIL() 返回不小于参数的最小整数值 CEILING() 返回不小于参数的最小整数值 FLOOR() 返回不大于参数的最大整数值 ROUND() 返回参数最近似的整数或指定小数位数的数值 RAND() 返回一个随机浮点值 SIGN() 返回参数的符号 CONV() 不同数基间转换数字,返回数字的字符串表示 TRUNCATE() 返回被舍位至指定小数位数的数字 CRC32() 计算循环冗余码校验值并返回一个 32 位无符号值 "}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/numeric-functions-and-operators/", "title": "数值函数与操作符", "content": " 数值函数与操作符 算术操作符 操作符名 功能描述 + 加号 - 减号 * 乘号 / 除号 DIV 整数除法 %, MOD 模运算,取余 - 更改参数符号 数学函数 函数名 功能描述 POW() 返回参数的指定乘方的结果值 POWER() 返回参数的指定乘方的结果值 EXP() 返回 e(自然对数的底)的指定乘方后的值 SQRT() 返回非负数的二次方根 LN() 返回参数的自然对数 LOG() 返回第一个参数的自然对数 LOG2() 返回参数以 2 为底的对数 LOG10() 返回参数以 10 为底的对数 PI() 返回 pi 的值 TAN() 返回参数的正切值 COT() 返回参数的余切值 SIN() 返回参数的正弦值 COS() 返回参数的余弦值 ATAN() 返回参数的反正切值 ATAN2(), ATAN() 返回两个参数的反正切值 ASIN() 返回参数的反正弦值 ACOS() 返回参数的反余弦值 RADIANS() 返回由度转化为弧度的参数 DEGREES() 返回由弧度转化为度的参数 MOD() 返回余数 ABS() 返回参数的绝对值 CEIL() 返回不小于参数的最小整数值 CEILING() 返回不小于参数的最小整数值 FLOOR() 返回不大于参数的最大整数值 ROUND() 返回参数最近似的整数或指定小数位数的数值 RAND() 返回一个随机浮点值 SIGN() 返回参数的符号 CONV() 不同数基间转换数字,返回数字的字符串表示 TRUNCATE() 返回被舍位至指定小数位数的数字 CRC32() 计算循环冗余码校验值并返回一个 32 位无符号值 "}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/numeric-functions-and-operators/", "title": "数值函数与操作符", "content": " 数值函数与操作符 算术操作符 操作符名 功能描述 + 加号 - 减号 * 乘号 / 除号 DIV 整数除法 %, MOD 模运算,取余 - 更改参数符号 数学函数 函数名 功能描述 POW() 返回参数的指定乘方的结果值 POWER() 返回参数的指定乘方的结果值 EXP() 返回 e(自然对数的底)的指定乘方后的值 SQRT() 返回非负数的二次方根 LN() 返回参数的自然对数 LOG() 返回第一个参数的自然对数 LOG2() 返回参数以 2 为底的对数 LOG10() 返回参数以 10 为底的对数 PI() 返回 pi 的值 TAN() 返回参数的正切值 COT() 返回参数的余切值 SIN() 返回参数的正弦值 COS() 返回参数的余弦值 ATAN() 返回参数的反正切值 ATAN2(), ATAN() 返回两个参数的反正切值 ASIN() 返回参数的反正弦值 ACOS() 返回参数的反余弦值 RADIANS() 返回由度转化为弧度的参数 DEGREES() 返回由弧度转化为度的参数 MOD() 返回余数 ABS() 返回参数的绝对值 CEIL() 返回不小于参数的最小整数值 CEILING() 返回不小于参数的最小整数值 FLOOR() 返回不大于参数的最大整数值 ROUND() 返回参数最近似的整数或指定小数位数的数值 RAND() 返回一个随机浮点值 SIGN() 返回参数的符号 CONV() 不同数基间转换数字,返回数字的字符串表示 TRUNCATE() 返回被舍位至指定小数位数的数字 CRC32() 计算循环冗余码校验值并返回一个 32 位无符号值 "}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/literal-value-numeric-literals/", "title": "数值字面值", "content": " Numeric Literals 数值字面值包括 integer 跟 Decimal 类型跟浮点数字面值。integer 可以包括 . 作为小数点分隔,数字前可以有 - 或者 + 来表示正数或者负数。精确数值字面值可以表示为如下格式:1, .2, 3.4, -5, -6.78, +9.10.科学记数法也是被允许的,表示为如下格式:1.2E3, 1.2E-3, -1.2E3, -1.2E-3。更多细节"}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/literal-value-numeric-literals/", "title": "数值字面值", "content": " Numeric Literals 数值字面值包括 integer 跟 Decimal 类型跟浮点数字面值。integer 可以包括 . 作为小数点分隔,数字前可以有 - 或者 + 来表示正数或者负数。精确数值字面值可以表示为如下格式:1, .2, 3.4, -5, -6.78, +9.10.科学记数法也是被允许的,表示为如下格式:1.2E3, 1.2E-3, -1.2E3, -1.2E-3。更多细节"}, {"url": "https://pingcap.com/docs-cn/sql/ddl/", "title": "数据定义语言", "content": " 数据定义语言 DDL(Data Definition Language)用于定义和管理数据库以及数据库中各种对象的语句。目前 TiDB 实现了 ADD INDEX 操作和 GENERAL 操作(除了 ADD INDEX 以外的 DDL 操作)在表间的并行。即在不同表之间,ADD INDEX 操作和 GENERAL 操作可以并行执行。也可以认为目前有两个 worker 分别处理 ADD INDEX 操作和 GENERAL 操作,当处理的请求是同一个表内的操作时,按接受到 DDL 请求的先后顺序来执行。该功能是为了初步且稳定地解决 ADD INDEX 操作(当前 TiDB 中只有 ADD INDEX 操作的执行时间会比较久)可能阻塞其他 DDL 操作的问题。CREATE DATABASE 语法 CREATE {DATABASE | SCHEMA} [IF NOT EXISTS] db_name [create_specification] ... create_specification: [DEFAULT] CHARACTER SET [=] charset_name | [DEFAULT] COLLATE [=] collation_name CREATE DATABASE 用于创建数据库,并可以指定数据库的默认属性(如数据库默认字符集,校验规则。CREATE SCHEMA 跟 CREATE DATABASE 操作效果一样。当创建已存在的数据库且不指定使用 IF NOT EXISTS 时会报错。create_specification 选项用于指定数据库具体的 CHARACTER SET 和 COLLATE。目前这个选项只是语法支持。DROP DATABASE 语法 DROP {DATABASE | SCHEMA} [IF EXISTS] db_name DROP DATABASE 用于删除指定数据库以及它其中的所用表格。IF EXISTS 用于防止当数据库不存在时发生错误。CREATE TABLE 语法 CREATE TABLE [IF NOT EXISTS] tbl_name (create_definition,...) [table_options] CREATE TABLE [IF NOT EXISTS] tbl_name { LIKE old_tbl_name | (LIKE old_tbl_name) } create_definition: col_name column_definition | [CONSTRAINT [symbol]] PRIMARY KEY [index_type] (index_col_name,...) [index_option] ... | {INDEX|KEY} [index_name] [index_type] (index_col_name,...) [index_option] ... | [CONSTRAINT [symbol]] UNIQUE [INDEX|KEY] [index_name] [index_type] (index_col_name,...) [index_option] ... | {FULLTEXT} [INDEX|KEY] [index_name] (index_col_name,...) [index_option] ... | [CONSTRAINT [symbol]] FOREIGN KEY [index_name] (index_col_name,...) reference_definition column_definition: data_type [NOT NULL | NULL] [DEFAULT default_value] [AUTO_INCREMENT] [UNIQUE [KEY] | [PRIMARY] KEY] [COMMENT 'string'] [reference_definition] | data_type [GENERATED ALWAYS] AS (expression) [VIRTUAL | STORED] [UNIQUE [KEY]] [COMMENT comment] [NOT NULL | NULL] [[PRIMARY] KEY] data_type: BIT[(length)] | TINYINT[(length)] [UNSIGNED] [ZEROFILL] | SMALLINT[(length)] [UNSIGNED] [ZEROFILL] | MEDIUMINT[(length)] [UNSIGNED] [ZEROFILL] | INT[(length)] [UNSIGNED] [ZEROFILL] | INTEGER[(length)] [UNSIGNED] [ZEROFILL] | BIGINT[(length)] [UNSIGNED] [ZEROFILL] | REAL[(length,decimals)] [UNSIGNED] [ZEROFILL] | DOUBLE[(length,decimals)] [UNSIGNED] [ZEROFILL] | FLOAT[(length,decimals)] [UNSIGNED] [ZEROFILL] | DECIMAL[(length[,decimals])] [UNSIGNED] [ZEROFILL] | NUMERIC[(length[,decimals])] [UNSIGNED] [ZEROFILL] | DATE | TIME[(fsp)] | TIMESTAMP[(fsp)] | DATETIME[(fsp)] | YEAR | CHAR[(length)] [BINARY] [CHARACTER SET charset_name] [COLLATE collation_name] | VARCHAR(length) [BINARY] [CHARACTER SET charset_name] [COLLATE collation_name] | BINARY[(length)] | VARBINARY(length) | TINYBLOB | BLOB | MEDIUMBLOB | LONGBLOB | TINYTEXT [BINARY] [CHARACTER SET charset_name] [COLLATE collation_name] | TEXT [BINARY] [CHARACTER SET charset_name] [COLLATE collation_name] | MEDIUMTEXT [BINARY] [CHARACTER SET charset_name] [COLLATE collation_name] | LONGTEXT [BINARY] [CHARACTER SET charset_name] [COLLATE collation_name] | ENUM(value1,value2,value3,...) [CHARACTER SET charset_name] [COLLATE collation_name] | SET(value1,value2,value3,...) [CHARACTER SET charset_name] [COLLATE collation_name] | JSON index_col_name: col_name [(length)] [ASC | DESC] index_type: USING {BTREE | HASH} index_option: KEY_BLOCK_SIZE [=] value | index_type | COMMENT 'string' reference_definition: REFERENCES tbl_name (index_col_name,...) [MATCH FULL | MATCH PARTIAL | MATCH SIMPLE] [ON DELETE reference_option] [ON UPDATE reference_option] reference_option: RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT table_options: table_option [[,] table_option] ... table_option: AUTO_INCREMENT [=] value | AVG_ROW_LENGTH [=] value | [DEFAULT] CHARACTER SET [=] charset_name | CHECKSUM [=] {0 | 1} | [DEFAULT] COLLATE [=] collation_name | COMMENT [=] 'string' | COMPRESSION [=] {'ZLIB'|'LZ4'|'NONE'} | CONNECTION [=] 'connect_string' | DELAY_KEY_WRITE [=] {0 | 1} | ENGINE [=] engine_name | KEY_BLOCK_SIZE [=] value | MAX_ROWS [=] value | MIN_ROWS [=] value | ROW_FORMAT [=] {DEFAULT|DYNAMIC|FIXED|COMPRESSED|REDUNDANT|COMPACT} | STATS_PERSISTENT [=] {DEFAULT|0|1} CREATE TABLE 用于创建一个表。目前不支持临时表,不支持 CHECK 约束,不支持创建表的同时从其它表导入数据功能。 在语法上也支持一些 Partition_options,但是并不完全,就不做列举了。 使用 IF NOT EXIST 时,即使创建的表已经存在,也不会报错,如果不指定时,则报错。 使用 LIKE 基于一个表的定义创建一个空表,包括这个表中的列属性和索引属性。 create_definition 中 FULLTEXT 和 FOREIGN KEY 目前只是语法上支持 data_type 请参考数据类型章节。 index_col_name 中 [ASC | DESC] 目前只是语法上支持。 index_type 目前只是语法上支持。 index_option 中 KEY_BLOCK_SIZE 目前只是语法上支持。 table_option 目前支持的只有 AUTO_INCREMENT,CHARACTER SET 和 COMMENT,其它只是语法上支持。具体内容参考下表,各个子句之间用逗号隔开。 参数 含义 举例 AUTO_INCREMENT 自增字段初始值 AUTO_INCREMENT = 5 CHARACTER SET 指定该表的字符串编码。目前支持 UTF8MB4 CHARACTER SET = ‘utf8mb4’ COMMENT 注释信息 COMMENT = ‘comment info’ AUTO_INCREMENT 说明 TiDB 的自增 ID (AUTO_INCREMENT ID) 只保证自增且唯一,并不保证连续分配。TiDB 目前采用批量分配的方式,所以如果在多台 TiDB 上同时插入数据,分配的自增 ID 会不连续。允许给整型类型的字段指定 AUTO_INCREMENT,且一个表只允许一个属性为 AUTO_INCREMENT 的字段。DROP TABLE 语法 DROP TABLE [IF EXISTS] tbl_name [, tbl_name] ... [RESTRICT | CASCADE] 可以同时删除多个表,表之间用 , 隔开。当删除不存在的表时且不指定使用 IF EXISTS 时会报错。关键字 RESTRICT 和 CASCADE 没有实际效果。其作用是与其他数据库兼容。TRUNCATE TABLE 语法 TRUNCATE [TABLE] tbl_name TRUNCATE TABLE 用于清除指定表中所有数据,但是保留表结构。此操作于删除指定表全表数据的操作类似,但是操作的执行速度会远快于删除全表的速度,且不受表内数据行数影响。 注意:使用此语句后,原先表内的 AUTO_INCREMENT 的值不会记录,会被重新计数。 RENAME TABLE 语法 RENAME TABLE tbl_name TO new_tbl_name RENAME TABLE 用于对一个表进行重命名。这个语句等价于如下的 ALTER TABLE 语句:ALTER TABLE old_table RENAME new_table; ALTER TABLE 语法 ALTER TABLE tbl_name [alter_specification] alter_specification: table_options | ADD [COLUMN] col_name column_definition [FIRST | AFTER col_name] | ADD [COLUMN] (col_name column_definition,...) | ADD {INDEX|KEY} [index_name] [index_type] (index_col_name,...) [index_option] ... | ADD [CONSTRAINT [symbol]] PRIMARY KEY [index_type] (index_col_name,...) [index_option] ... | ADD [CONSTRAINT [symbol]] UNIQUE [INDEX|KEY] [index_name] [index_type] (index_col_name,...) [index_option] ... | ADD FULLTEXT [INDEX|KEY] [index_name] (index_col_name,...) [index_option] ... | ADD [CONSTRAINT [symbol]] FOREIGN KEY [index_name] (index_col_name,...) reference_definition | ALTER [COLUMN] col_name {SET DEFAULT literal | DROP DEFAULT} | CHANGE [COLUMN] old_col_name new_col_name column_definition [FIRST|AFTER col_name] | {DISABLE|ENABLE} KEYS | DROP [COLUMN] col_name | DROP {INDEX|KEY} index_name | DROP PRIMARY KEY | DROP FOREIGN KEY fk_symbol | LOCK [=] {DEFAULT|NONE|SHARED|EXCLUSIVE} | MODIFY [COLUMN] col_name column_definition [FIRST | AFTER col_name] | RENAME [TO|AS] new_tbl_name | {WITHOUT|WITH} VALIDATION index_col_name: col_name [(length)] [ASC | DESC] index_type: USING {BTREE | HASH} index_option: KEY_BLOCK_SIZE [=] value | index_type | COMMENT 'string' table_options: table_option [[,] table_option] ... table_option: AVG_ROW_LENGTH [=] value | [DEFAULT] CHARACTER SET [=] charset_name | CHECKSUM [=] {0 | 1} | [DEFAULT] COLLATE [=] collation_name | COMMENT [=] 'string' | COMPRESSION [=] {'ZLIB'|'LZ4'|'NONE'} | CONNECTION [=] 'connect_string' | DELAY_KEY_WRITE [=] {0 | 1} | ENGINE [=] engine_name | KEY_BLOCK_SIZE [=] value | MAX_ROWS [=] value | MIN_ROWS [=] value | ROW_FORMAT [=] {DEFAULT|DYNAMIC|FIXED|COMPRESSED|REDUNDANT|COMPACT} | STATS_PERSISTENT [=] {DEFAULT|0|1} ALTER TABLE 用于修改已存在的表的结构,比如:修改表及表属性、新增或删除列、创建或删除索引、修改列及属性等。以下是几个字段类型的描述: index_col_name、index_type 和 index_option 可以参考 CREATE INDEX 语法。 table_option 目前支持的修改类型为 AUTO_INCREMENT 和 COMMENT,其它的只是语法上支持。 下面介绍一下具体操作类型的支持情况。 ADD/DROP INDEX/COLUMN 操作目前不支持同时创建或删除多个索引或列。 ADD/DROP PRIMARY KEY 操作目前不支持。 DROP COLUMN 操作目前不支持删除的列为主键列或索引列。 ADD COLUMN 操作目前不支持同时将新添加的列设为主键或唯一索引,也不支持将此列设成 AUTO_INCREMENT 属性。 CHANGE/MODIFY COLUMN 操作目前支持部分语法,细节如下: 在修改类型方面,只支持整数类型之间修改,字符串类型之间修改和 Blob 类型之间的修改,且只能使原类型长度变长。此外,不能改变列的 unsigned/charset/collate 属性。这里的类型分类如下: 具体支持的整型类型有:TinyInt,SmallInt,MediumInt,Int,BigInt。 具体支持的字符串类型有:Char,Varchar,Text,TinyText,MediumText,LongText。 具体支持的 Blob 类型有:Blob,TinyBlob,MediumBlob,LongBlob。 在修改类型 …"}, {"url": "https://pingcap.com/recruit-cn/campus/infrastructure-engineer-intern/", "title": "数据库开发实习生", "content": " 数据库开发实习生 职位描述:你能从工作中学习到什么? 如何构建一个分布式关系数据库; 如何将其包装成为一套完整的商业产品; 亲身参与以上过程,并实践你所掌握的开发技术; 任职要求: 熟悉常用的开发语言,熟悉 Golang/Rust 优先; 熟悉分布式系统/数据库系统优先; 有开源项目实践经历优先; 实习优秀者有机会转正,并有机会获得期权。 待遇300 元/8 小时,餐补,水果零食,生日会,Team Building联系方式:hire@pingcap.com工作地点北京,上海,广州,杭州,成都"}, {"url": "https://pingcap.com/docs-cn/sql/admin/", "title": "数据库管理语句", "content": " 数据库管理语句 TiDB 可以通过一些语句对数据库进行管理,包括设置权限、修改系统变量、查询数据库状态。权限管理 参考权限管理文档。SET 语句 SET 语句有多种作用和形式:设置变量值 SET variable_assignment [, variable_assignment] ... variable_assignment: user_var_name = expr | param_name = expr | local_var_name = expr | [GLOBAL | SESSION] system_var_name = expr | [@@global. | @@session. | @@] system_var_name = expr 这种语法可以设置 TiDB 的变量值,包括系统变量以及用户定义变量。对于用户自定义变量,都是会话范围的变量;对于系统变量,通过 @@global. 或者是 GLOBAL 设置的变量为全局范围变量,否则为会话范围变量,具体参考系统变量一章。SET CHARACTER 语句和 SET NAMES SET {CHARACTER SET | CHARSET} {'charset_name' | DEFAULT} SET NAMES {'charset_name' [COLLATE 'collation_name'] | DEFAULT} 这个语句设置这三个会话范围的系统变量:character_set_client,character_set_results,character_set_connection 设置为给定的字符集。目前 character_set_connection 变量的值和 MySQL 有所区别,MySQL 将其设置为 character_set_database 的值。设置密码 SET PASSWORD [FOR user] = password_option password_option: { 'auth_string' | PASSWORD('auth_string') } 设置用户密码,具体信息参考权限管理。设置隔离级别 SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; 设置事务隔离级别,具体信息参考事务语句。SHOW 语句 TiDB 支持部分 SHOW 语句,用于查看 Database/Table/Column 信息,或者是数据库内部的状态。已经支持的语句:# 已支持,且和 MySQL 行为一致 SHOW CHARACTER SET [like_or_where] SHOW COLLATION [like_or_where] SHOW [FULL] COLUMNS FROM tbl_name [FROM db_name] [like_or_where] SHOW CREATE {DATABASE|SCHEMA} db_name SHOW CREATE TABLE tbl_name SHOW DATABASES [like_or_where] SHOW GRANTS FOR user SHOW INDEX FROM tbl_name [FROM db_name] SHOW PRIVILEGES SHOW [FULL] PROCESSLIST SHOW [GLOBAL | SESSION] STATUS [like_or_where] SHOW TABLE STATUS [FROM db_name] [like_or_where] SHOW [FULL] TABLES [FROM db_name] [like_or_where] SHOW [GLOBAL | SESSION] VARIABLES [like_or_where] SHOW WARNINGS # 已支持,但是返回空结果,目的是提升兼容性 SHOW ENGINE engine_name {STATUS | MUTEX} SHOW [STORAGE] ENGINES SHOW PLUGINS SHOW PROCEDURE STATUS [like_or_where] SHOW TRIGGERS [FROM db_name] [like_or_where] SHOW EVENTS SHOW FUNCTION STATUS [like_or_where] SHOW MASTER STATUS # TiDB 特有语句,用于查看统计信息 SHOW STATS_META [like_or_where] SHOW STATS_HISTOGRAMS [like_or_where] SHOW STATS_BUCKETS [like_or_where] like_or_where: LIKE 'pattern' | WHERE expr 说明: 通过 SHOW 语句展示统计信息请参考统计信息说明。 关于 SHOW 语句更多信息请参考 MySQL 文档 在 TiDB 中,SHOW MASTER STATUS 语句返回的 UniqueID 实际上是从 PD 获取的当前 TSO 时间,这个时间在做 binlog 增量同步过程中需要使用。mysql> show master status; +-------------|--------------------|--------------|------------------|-------------------+ | File | UniqueID | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +-------------|--------------------|--------------|------------------|-------------------+ | tidb-binlog | 403756327834484736 | | | | +-------------|--------------------|--------------|------------------|-------------------+ 1 row in set (0.00 sec) ADMIN 语句 该语句是 TiDB 扩展语法,用于查看 TiDB 自身的状态。ADMIN SHOW DDL ADMIN SHOW DDL JOBS ADMIN SHOW DDL JOB QUERIES job_id [, job_id] ... ADMIN CANCEL DDL JOBS job_id [, job_id] ... ADMIN SHOW DDL 用于查看当前正在执行的 DDL 作业。 ADMIN SHOW DDL JOBS 用于查看当前 DDL 作业队列中的所有结果(包括正在运行以及等待运行的任务)以及已执行完成的 DDL 作业队列中的最近十条结果。 ADMIN SHOW DDL JOB QUERIES job_id [, job_id] ... 用于显示 job_id 对应的 DDL 任务的原始 SQL 语句。这个 job_id 只会搜索正在执行中的任务以及 DDL 历史作业队伍中最近的十条。 ADMIN CANCEL DDL JOBS job_id [, job_id] ... 用于取消正在执行的 DDL 作业,其返回值为对应的作业取消是否成功,如果失败会显示失败的具体原因。这个操作可以同时取消多个 DDL 作业,其中 DDL 作业 ID 可以通过 ADMIN SHOW DDL JOBS 语句来获取。其中如果希望取消的作业已经完成,则取消操作将会失败。"}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/admin/", "title": "数据库管理语句", "content": " TiDB 可以通过一些语句对数据库进行管理,包括设置权限、修改系统变量、查询数据库状态。权限管理 参考权限管理文档。SET 语句 SET 语句有多种作用和形式:设置变量值 SET variable_assignment [, variable_assignment] ... variable_assignment: user_var_name = expr | param_name = expr | local_var_name = expr | [GLOBAL | SESSION] system_var_name = expr | [@@global. | @@session. | @@] system_var_name = expr 这种语法可以设置 TiDB 的变量值,包括系统变量以及用户定义变量。对于用户自定义变量,都是会话范围的变量;对于系统变量,通过 @@global. 或者是 GLOBAL 设置的变量为全局范围变量,否则为会话范围变量,具体参考系统变量一章。SET CHARACTER 语句和 SET NAMES SET {CHARACTER SET | CHARSET} {'charset_name' | DEFAULT} SET NAMES {'charset_name' [COLLATE 'collation_name'] | DEFAULT} 这个语句设置这三个会话范围的系统变量:character_set_client,character_set_results,character_set_connection 设置为给定的字符集。目前 character_set_connection 变量的值和 MySQL 有所区别,MySQL 将其设置为 character_set_database 的值。设置密码 SET PASSWORD [FOR user] = password_option password_option: { 'auth_string' | PASSWORD('auth_string') } 设置用户密码,具体信息参考权限管理。设置隔离级别 SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; 设置事务隔离级别,具体信息参考事务语句。SHOW 语句 TiDB 支持部分 SHOW 语句,用于查看 Database/Table/Column 信息,或者是数据库内部的状态。已经支持的语句:# 已支持,且和 MySQL 行为一致 SHOW CHARACTER SET [like_or_where] SHOW COLLATION [like_or_where] SHOW [FULL] COLUMNS FROM tbl_name [FROM db_name] [like_or_where] SHOW CREATE {DATABASE|SCHEMA} db_name SHOW CREATE TABLE tbl_name SHOW DATABASES [like_or_where] SHOW GRANTS FOR user SHOW INDEX FROM tbl_name [FROM db_name] SHOW PRIVILEGES SHOW [FULL] PROCESSLIST SHOW [GLOBAL | SESSION] STATUS [like_or_where] SHOW TABLE STATUS [FROM db_name] [like_or_where] SHOW [FULL] TABLES [FROM db_name] [like_or_where] SHOW [GLOBAL | SESSION] VARIABLES [like_or_where] SHOW WARNINGS # 已支持,但是返回空结果,目的是提升兼容性 SHOW ENGINE engine_name {STATUS | MUTEX} SHOW [STORAGE] ENGINES SHOW PLUGINS SHOW PROCEDURE STATUS [like_or_where] SHOW TRIGGERS [FROM db_name] [like_or_where] SHOW EVENTS SHOW FUNCTION STATUS [like_or_where] # TiDB 特有语句,用于查看统计信息 SHOW STATS_META [like_or_where] SHOW STATS_HISTOGRAMS [like_or_where] SHOW STATS_BUCKETS [like_or_where] like_or_where: LIKE 'pattern' | WHERE expr 说明: * 通过 SHOW 语句展示统计信息请参考统计信息说明 * 关于 SHOW 语句更多信息请参考 MySQL 文档ADMIN 语句 该语句是 TiDB 扩展语法,用于查看 TiDB 自身的状态。ADMIN SHOW DDL ADMIN SHOW DDL JOBS ADMIN CANCEL DDL JOBS 'job_id' [, 'job_id'] ... ADMIN SHOW DDL 用于查看当前正在执行的 DDL 作业。 ADMIN SHOW DDL JOBS 用于查看当前 DDL 作业队列中的所有结果(包括正在运行以及等待运行的任务)以及已执行完成的 DDL 作业队列中的最近十条结果。 ADMIN CANCEL DDL JOBS 'job_id' [, 'job_id'] ... 用于取消正在执行的 DDL 作业,其返回值为对应的作业取消是否成功,如果失败会显示失败的具体原因。这个操作可以同时取消多个 DDL 作业,其中 DDL 作业 ID 可以通过 ADMIN SHOW DDL JOBS 语句来获取。其中如果希望取消的作业已经完成,则取消操作将会失败。"}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/admin/", "title": "数据库管理语句", "content": " TiDB 可以通过一些语句对数据库进行管理,包括设置权限、修改系统变量、查询数据库状态。权限管理 参考权限管理文档。SET 语句 SET 语句有多种作用和形式:设置变量值 SET variable_assignment [, variable_assignment] ... variable_assignment: user_var_name = expr | param_name = expr | local_var_name = expr | [GLOBAL | SESSION] system_var_name = expr | [@@global. | @@session. | @@] system_var_name = expr 这种语法可以设置 TiDB 的变量值,包括系统变量以及用户定义变量。对于用户自定义变量,都是会话范围的变量;对于系统变量,通过 @@global. 或者是 GLOBAL 设置的变量为全局范围变量,否则为会话范围变量,具体参考系统变量一章。SET CHARACTER 语句和 SET NAMES SET {CHARACTER SET | CHARSET} {'charset_name' | DEFAULT} SET NAMES {'charset_name' [COLLATE 'collation_name'] | DEFAULT} 这个语句设置这三个会话范围的系统变量:character_set_client,character_set_results,character_set_connection 设置为给定的字符集。目前 character_set_connection 变量的值和 MySQL 有所区别,MySQL 将其设置为 character_set_database 的值。设置密码 SET PASSWORD [FOR user] = password_option password_option: { 'auth_string' | PASSWORD('auth_string') } 设置用户密码,具体信息参考权限管理。设置隔离级别 SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; 设置事务隔离级别,具体信息参考事务语句。SHOW 语句 TiDB 支持部分 SHOW 语句,用于查看 Database/Table/Column 信息,或者是数据库内部的状态。已经支持的语句:# 已支持,且和 MySQL 行为一致 SHOW CHARACTER SET [like_or_where] SHOW COLLATION [like_or_where] SHOW [FULL] COLUMNS FROM tbl_name [FROM db_name] [like_or_where] SHOW CREATE {DATABASE|SCHEMA} db_name SHOW CREATE TABLE tbl_name SHOW DATABASES [like_or_where] SHOW GRANTS FOR user SHOW INDEX FROM tbl_name [FROM db_name] SHOW PRIVILEGES SHOW [FULL] PROCESSLIST SHOW [GLOBAL | SESSION] STATUS [like_or_where] SHOW TABLE STATUS [FROM db_name] [like_or_where] SHOW [FULL] TABLES [FROM db_name] [like_or_where] SHOW [GLOBAL | SESSION] VARIABLES [like_or_where] SHOW WARNINGS # 已支持,但是返回空结果,目的是提升兼容性 SHOW ENGINE engine_name {STATUS | MUTEX} SHOW [STORAGE] ENGINES SHOW PLUGINS SHOW PROCEDURE STATUS [like_or_where] SHOW TRIGGERS [FROM db_name] [like_or_where] SHOW EVENTS SHOW FUNCTION STATUS [like_or_where] # TiDB 特有语句,用于查看统计信息 SHOW STATS_META [like_or_where] SHOW STATS_HISTOGRAMS [like_or_where] SHOW STATS_BUCKETS [like_or_where] like_or_where: LIKE 'pattern' | WHERE expr 说明: * 通过 SHOW 语句展示统计信息请参考统计信息说明 * 关于 SHOW 语句更多信息请参考 MySQL 文档ADMIN 语句 该语句是 TiDB 扩展语法,用于查看 TiDB 自身的状态。ADMIN SHOW DDL ADMIN SHOW DDL JOBS ADMIN CANCEL DDL JOBS 'job_id' [, 'job_id'] ... ADMIN SHOW DDL 用于查看当前正在执行的 DDL 作业。 ADMIN SHOW DDL JOBS 用于查看当前 DDL 作业队列中的所有结果(包括正在运行以及等待运行的任务)以及已执行完成的 DDL 作业队列中的最近十条结果。 ADMIN CANCEL DDL JOBS 'job_id' [, 'job_id'] ... 用于取消正在执行的 DDL 作业,其返回值为对应的作业取消是否成功,如果失败会显示失败的具体原因。这个操作可以同时取消多个 DDL 作业,其中 DDL 作业 ID 可以通过 ADMIN SHOW DDL JOBS 语句来获取。其中如果希望取消的作业已经完成,则取消操作将会失败。"}, {"url": "https://pingcap.com/docs-cn/sql/dml/", "title": "数据操作语言", "content": " TiDB 数据操作语言 数据操作语言 (Data Manipulation Language, DML) 用于帮助用户实现对数据库的基本操作,比如查询、写入、删除和修改数据库中的数据。TiDB 支持的数据操作语言包括 Select,Insert,Delete,Update 和 Replace。Select 语句 Select 语句用于从数据库中查询数据。语法定义 SELECT [ALL | DISTINCT | DISTINCTROW ] [HIGH_PRIORITY] [STRAIGHT_JOIN] [SQL_CACHE | SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS] select_expr [, select_expr ...] [FROM table_references [WHERE where_condition] [GROUP BY {col_name | expr | position} [ASC | DESC], ...] [HAVING where_condition] [ORDER BY {col_name | expr | position} [ASC | DESC], ...] [LIMIT {[offset,] row_count | row_count OFFSET offset}] [FOR UPDATE | LOCK IN SHARE MODE]] 语法元素说明 语法元素 说明 ALL、DISTINCT、DISTINCTROW 查询结果集中可能会包含重复值。指定 DISTINCT/DISTINCTROW 则在查询结果中过滤掉重复的行;指定 ALL 则列出所有的行。默认为 ALL。 HIGH_PRIORITY 该语句为高优先级语句,TiDB 在执行阶段会优先处理这条语句 SQL_CACHE、SQL_NO_CACHE、SQL_CALC_FOUND_ROWS TiDB 出于兼容性解析这三个语法,但是不做任何处理 STRAIGHT_JOIN STRAIGHT_JOIN 会强制优化器按照 FROM 子句中所使用的表的顺序做联合查询。当优化器选择的 Join 顺序并不优秀时,你可以使用这个语法来加速查询的执行 select_expr 投影操作列表,一般包括列名、表达式,或者是用 ‘*’ 表示全部列 FROM table_references 表示数据来源,数据来源可以是一个表(select * from t;)或者是多个表 (select * from t1 join t2;) 或者是0个表 (select 1+1 from dual;, 等价于 select 1+1;) WHERE where_condition Where 子句用于设置过滤条件,查询结果中只会包含满足条件的数据 GROUP BY GroupBy 子句用于对查询结果集进行分组 HAVING where_condition Having 子句与 Where 子句作用类似,Having 子句可以让过滤 GroupBy 后的各种数据,Where 子句用于在聚合前过滤记录。 ORDER BY OrderBy 子句用于指定结果排序顺序,可以按照列、表达式或者是 select_expr 列表中某个位置的字段进行排序。 LIMIT Limit 子句用于限制结果条数。Limit 接受一个或两个数字参数,如果只有一个参数,那么表示返回数据的最大行数;如果是两个参数,那么第一个参数表示返回数据的第一行的偏移量(第一行数据的偏移量是 0),第二个参数指定返回数据的最大条目数。 FOR UPDATE 对查询结果集所有数据上读锁,以监测其他事务对这些的并发修改。TiDB 使用乐观事务模型在语句执行期间不会检测锁冲突,在事务的提交阶段才会检测事务冲突,如果执行 Select For Update 期间,有其他事务修改相关的数据,那么包含 Select For Update 语句的事务会提交失败。 LOCK IN SHARE MODE TiDB 出于兼容性解析这个语法,但是不做任何处理 Insert 语句 Insert 语句用于向数据库中插入数据,TiDB 兼容 MySQL Insert 语句的所有语法。语法定义 InsertStatement: INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE] [INTO] tbl_name insert_values [ON DUPLICATE KEY UPDATE assignment_list] insert_values: [(col_name [, col_name] ...)] {VALUES | VALUE} (expr_list) [, (expr_list)] ... | SET assignment_list | [(col_name [, col_name] ...)] SELECT ... expr_list: expr [, expr] ... assignment: col_name = expr assignment_list: assignment [, assignment] ... 语法元素说明 语法元素 说明 LOW_PRIORITY 该语句为低优先级语句,TiDB 在执行阶段会降低这条语句的优先级 DELAYED TiDB 出于兼容性解析这个语法,但是不做任何处理 HIGH_PRIORITY 该语句为高优先级语句,TiDB 在执行阶段会优先处理这条语句 IGNORE 如果发生 Uniq Key 冲突,则忽略插入的数据,不报错 tbl_name 要插入的表名 insert_values 待插入的数据,下面一节会详细描述 ON DUPLICATE KEY UPDATE assignment_list 如果发生 Uniq Key 冲突,则舍弃要插入的数据,改用 assignment_list 更新已存在的行 insert_values 待插入的数据集,可以用以下三种方式指定: Value List 将被插入的数据值写入列表中,例如:CREATE TABLE tbl_name ( a int, b int, c int ); INSERT INTO tbl_name VALUES(1,2,3),(4,5,6),(7,8,9); 上面的例子中,(1,2,3),(4,5,6),(7,8,9) 即为 Value List,其中每个括号内部的数据表示一行数据,这个例子中插入了三行数据。Insert 语句也可以只给部分列插入数据,这种情况下,需要在 Value List 之前加上 ColumnName List,如:INSERT INTO tbl_name (a,c) VALUES(1,2),(4,5),(7,8); 上面的例子中,每行数据只指定了 a 和 c 这两列的值,b 列的值会设为 Null。 Assignment List 通过赋值列表指定插入的数据,例如:INSERT INTO tbl_name SET a=1, b=2, c=3; 这种方式每次只能插入一行数据,每列的值通过赋值列表指定。 Select Statement 待插入的数据集是通过一个 Select 语句获取,要插入的列是通过 Select 语句的 Schema 获得。例如:CREATE TABLE tbl_name1 ( a int, b int, c int ); INSERT INTO tbl_name SELECT * from tbl_name1; 上面的例子中,从 tbl_name1 中查询出数据,插入 tbl_name 中。Delete 语句 Delete 语句用于删除数据库中的数据,TiDB 兼容 MySQL Delete 语句除 PARTITION 之外的所有语法。Delete 语句主要分为单表删除和多表删除两种,下面分开描述。单表删除 这种语法用于删除的数据只会涉及一个表的情况。语法定义 DELETE [LOW_PRIORITY] [QUICK] [IGNORE] FROM tbl_name [WHERE where_condition] [ORDER BY ...] [LIMIT row_count] 多表删除 这种语法用于删除的数据会涉及多张表的情况。一共有两种写法:DELETE [LOW_PRIORITY] [QUICK] [IGNORE] tbl_name[.*] [, tbl_name[.*]] ... FROM table_references [WHERE where_condition] DELETE [LOW_PRIORITY] [QUICK] [IGNORE] FROM tbl_name[.*] [, tbl_name[.*]] ... USING table_references [WHERE where_condition] 删除多个表的数据的时候,可以用这两种语法。这两种写法都可以指定从多个表查询数据,但只删除其中一些表的数据。在第一种语法中,只会删除 FROM 关键字之前的 Table 列表中所列 Table 的表中的数据。对于第二种写法,只会删除 FROM 之后 USING 之前的 Table 列表中的所列 Table 中的数据。语法元素说明 语法元素 说明 LOW_PRIORITY 该语句为低优先级语句,TiDB 在执行阶段会降低这条语句的优先级 QUICK TiDB 出于兼容性解析这个语法,但是不做任何处理 IGNORE TiDB 出于兼容性解析这个语法,但是不做任何处理 tbl_name 要删除数据的表名 WHERE where_condition Where 表达式,只删除满足表达式的那些行 ORDER BY 对待删除数据集进行排序 LIMIT row_count 只对待删除数据集中排序前 row_count 行的内容进行删除 Update 语句 Update 语句用于更新表中的数据。语法定义 Update 语句一共有两种语法,分别用于更新单表数据和多表数据。单表 Update UPDATE [LOW_PRIORITY] [IGNORE] table_reference SET assignment_list [WHERE where_condition] [ORDER BY ...] [LIMIT row_count] assignment: col_name = value assignment_list: assignment [, assignment] ... 单表 Update 语句会更新 Table 中现有行的指定列。SET assignment_list 指定了要更新的列名,以及要赋予地新值。 Where/OrderBy/Limit 子句一起用于从 Table 中查询出待更新的数据。多表 Update UPDATE [LOW_PRIORITY] [IGNORE] table_references SET assignment_list [WHERE where_condition] 多表更新语句用于将 table_references 中满足 Where 子句的数据地指定列赋予新的值。语法元素说明 语法元素 说明 LOW_PRIORITY 该语句为低优先级语句,TiDB 在执行阶段会降低这条语句的优先级 IGNORE TiDB 出于兼容性解析这个语法,但是不做任何处理 table_reference 待更新的 Table 名称 table_references 待更新的 Table 名称列表 SET assignment_list 待更新的列名以及目标值 WHERE where_condition Where 表达式,只更新满足表达式的那些行 ORDER BY 对待更新数据集进行排序 LIMIT row_count 只对待更新数据集中排序前 row_count 行的内容进行更新 Replace 语句 Replace 语句是 MySQL 对标准 SQL 语法的扩展,其行为和 Insert 语句一样,但是当现有数据中有和待插入数据在 PRIMARY KEY 或者 UNIQUE KEY 冲突的情况下,会先删除旧数据,再插入新数据。语法定义 REPLACE [LOW_PRIORITY | DELAYED] [INTO] tbl_name [(col_name [, col_name] ...)] {VALUES | VALUE} (value_list) [, (value_list)] ... REPLACE [LOW_PRIORITY | DELAYED] [INTO] tbl_name SET assignment_list REPLACE [LOW_PRIORITY | DELAYED] [INTO] tbl_name [(col_name [, col_name] ...)] SELECT ... 语法元素说明 语法元素 说明 LOW_PRIORITY 该语句为低优先级语句,TiDB 在执行阶段会降低这条语句的优先级 DELAYED TiDB 出于兼容性解析这个语法,但是不做任何处理 tbl_name 待更新的 Table 名称 value_list 待插入的数据 SET assignment_list 待更新的列名以及目标值 SELECT ... 待插入的数据集,该数据集来自于一个 Select 语句 "}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/dml/", "title": "数据操作语言", "content": " TiDB 数据操作语言 数据操作语言(Data Manipulation Language, DML)用于帮助用户实现对数据库的基本操作,比如查询、写入、删除和修改数据库中的数据。TiDB 支持的数据操作语言包括 Select ,Insert, Delete, Update,和 Replace。Select 语句 Select 语句用于从数据库中查询数据。语法定义 SELECT [ALL | DISTINCT | DISTINCTROW ] [HIGH_PRIORITY] [SQL_CACHE | SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS] select_expr [, select_expr ...] [FROM table_references [WHERE where_condition] [GROUP BY {col_name | expr | position} [ASC | DESC], ...] [HAVING where_condition] [ORDER BY {col_name | expr | position} [ASC | DESC], ...] [LIMIT {[offset,] row_count | row_count OFFSET offset}] [FOR UPDATE | LOCK IN SHARE MODE]] 语法元素说明 语法元素 说明 ALL、DISTINCT、DISTINCTROW 查询结果集中可能会包含重复值。指定 DISTINCT/DISTINCTROW 则在查询结果中过滤掉重复的行;指定 ALL 则列出所有的行。默认为 ALL。 HIGH_PRIORITY 该语句为高优先级语句,TiDB 在执行阶段会优先处理这条语句 SQL_CACHE、SQL_NO_CACHE、SQL_CALC_FOUND_ROWS TiDB 出于兼容性解析这三个语法,但是不做任何处理 select_expr 投影操作列表,一般包括列名、表达式,或者是用 ‘*’ 表示全部列 FROM table_references 表示数据来源,数据来源可以是一个表(select * from t;)或者是多个表 (select * from t1 join t2;) 或者是0个表 (select 1+1 from dual;, 等价于 select 1+1;) WHERE where_condition Where 子句用于设置过滤条件,查询结果中只会包含满足条件的数据 GROUP BY GroupBy 子句用于对查询结果集进行分组 HAVING where_condition Having 子句与 Where 子句作用类似,Having 子句可以让过滤 GroupBy 后的各种数据,Where 子句用于在聚合前过滤记录。 ORDER BY OrderBy 子句用于指定结果排序顺序,可以按照列、表达式或者是 select_expr 列表中某个位置的字段进行排序。 LIMIT Limit 子句用于限制结果条数。Limit 接受一个或两个数字参数,如果只有一个参数,那么表示返回数据的最大行数;如果是两个参数,那么第一个参数表示返回数据的第一行的偏移量(第一行数据的偏移量是 0),第二个参数指定返回数据的最大条目数。 FOR UPDATE 对查询结果集所有数据上读锁,以监测其他事务对这些的并发修改。TiDB 使用乐观事务模型在语句执行期间不会检测锁冲突,在事务的提交阶段才会检测事务冲突,如果执行 Select For Update 期间,有其他事务修改相关的数据,那么包含 Select For Update 语句的事务会提交失败。 LOCK IN SHARE MODE TiDB 出于兼容性解析这个语法,但是不做任何处理 Insert 语句 Insert 语句用于向数据库中插入数据,TiDB 兼容 MySQL Insert 语句的所有语法。语法定义 InsertStatement: INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE] [INTO] tbl_name insert_values [ON DUPLICATE KEY UPDATE assignment_list] insert_values: [(col_name [, col_name] ...)] {VALUES | VALUE} (expr_list) [, (expr_list)] ... | SET assignment_list | [(col_name [, col_name] ...)] SELECT ... expr_list: expr [, expr] ... assignment: col_name = expr assignment_list: assignment [, assignment] ... 语法元素说明 语法元素 说明 LOW_PRIORITY 该语句为低优先级语句,TiDB 在执行阶段会降低这条语句的优先级 DELAYED TiDB 出于兼容性解析这个语法,但是不做任何处理 HIGH_PRIORITY 该语句为高优先级语句,TiDB 在执行阶段会优先处理这条语句 IGNORE 如果发生 Uniq Key 冲突,则忽略插入的数据,不报错 tbl_name 要插入的表名 insert_values 待插入的数据,下面一节会详细描述 ON DUPLICATE KEY UPDATE assignment_list 如果发生 Uniq Key 冲突,则舍弃要插入的数据,改用 assignment_list 更新已存在的行 insert_values 待插入的数据集,可以用以下三种方式指定: Value List 将被插入的数据值写入列表中,例如:CREATE TABLE tbl_name ( a int, b int, c int ); INSERT INTO tbl_name VALUES(1,2,3),(4,5,6),(7,8,9); 上面的例子中,(1,2,3),(4,5,6),(7,8,9) 即为 Value List,其中每个括号内部的数据表示一行数据,这个例子中插入了三行数据。Insert 语句也可以只给部分列插入数据,这种情况下,需要在 Value List 之前加上 ColumnName List,如:INSERT INTO tbl_name (a,c) VALUES(1,2),(4,5),(7,8); 上面的例子中,每行数据只指定了 a 和 c 这两列的值,b 列的值会设为 Null。 Assignment List 通过赋值列表指定插入的数据,例如:INSERT INTO tbl_name SET a=1, b=2, c=3; 这种方式每次只能插入一行数据,每列的值通过赋值列表指定。 Select Statement 待插入的数据集是通过一个 Select 语句获取,要插入的列是通过 Select 语句的 Schema 获得。例如:CREATE TABLE tbl_name1 ( a int, b int, c int ); INSERT INTO tbl_name SELECT * from tbl_name1; 上面的例子中,从 tbl_name1 中查询出数据,插入 tbl_name 中。Delete 语句 Delete 语句用于删除数据库中的数据,TiDB 兼容 MySQL Delete 语句除 PARTITION 之外的所有语法。Delete 语句主要分为单表删除和多表删除两种,下面分开描述。单表删除 这种语法用于删除的数据只会涉及一个表的情况。语法定义 DELETE [LOW_PRIORITY] [QUICK] [IGNORE] FROM tbl_name [WHERE where_condition] [ORDER BY ...] [LIMIT row_count] 多表删除 这种语法用于删除的数据会涉及多张表的情况。一共有两种写法:DELETE [LOW_PRIORITY] [QUICK] [IGNORE] tbl_name[.*] [, tbl_name[.*]] ... FROM table_references [WHERE where_condition] DELETE [LOW_PRIORITY] [QUICK] [IGNORE] FROM tbl_name[.*] [, tbl_name[.*]] ... USING table_references [WHERE where_condition] 删除多个表的数据的时候,可以用这两种语法。这两种写法都可以指定从多个表查询数据,但只删除其中一些表的数据。在第一种语法中,只会删除 FROM 关键字之前的 Table 列表中所列 Table 的表中的数据。对于第二种写法,只会删除 FROM 之后 USING 之前的 Table 列表中的所列 Table 中的数据。语法元素说明 语法元素 说明 LOW_PRIORITY 该语句为低优先级语句,TiDB 在执行阶段会降低这条语句的优先级 QUICK TiDB 出于兼容性解析这个语法,但是不做任何处理 IGNORE TiDB 出于兼容性解析这个语法,但是不做任何处理 tbl_name 要删除数据的表名 WHERE where_condition Where 表达式,只删除满足表达式的那些行 ORDER BY 对待删除数据集进行排序 LIMIT row_count 只对待删除数据集中排序前 row_count 行的内容进行删除 Update 语句 Update 语句用于更新表中的数据。语法定义 Update 语句一共有两种语法,分别用于更新单表数据和多表数据。单表 Update UPDATE [LOW_PRIORITY] [IGNORE] table_reference SET assignment_list [WHERE where_condition] [ORDER BY ...] [LIMIT row_count] assignment: col_name = value assignment_list: assignment [, assignment] ... 单表 Update 语句会更新 Table 中现有行的指定列。SET assignment_list 指定了要更新的列名,以及要赋予地新值。 Where/OrderBy/Limit 子句一起用于从 Table 中查询出待更新的数据。多表 Update UPDATE [LOW_PRIORITY] [IGNORE] table_references SET assignment_list [WHERE where_condition] 多表更新语句用于将 table_references 中满足 Where 子句的数据地指定列赋予新的值。语法元素说明 语法元素 说明 LOW_PRIORITY 该语句为低优先级语句,TiDB 在执行阶段会降低这条语句的优先级 IGNORE TiDB 出于兼容性解析这个语法,但是不做任何处理 table_reference 待更新的 Table 名称 table_references 待更新的 Table 名称列表 SET assignment_list 待更新的列名以及目标值 WHERE where_condition Where 表达式,只更新满足表达式的那些行 ORDER BY 对待更新数据集进行排序 LIMIT row_count 只对待更新数据集中排序前 row_count 行的内容进行更新 Replace 语句 Replace 语句是 MySQL 对标准 SQL 语法的扩展,其行为和 Insert 语句一样,但是当现有数据中有和待插入数据在 PRIMARY KEY 或者 UNIQUE KEY 冲突的情况下,会先删除旧数据,再插入新数据。语法定义 REPLACE [LOW_PRIORITY | DELAYED] [INTO] tbl_name [(col_name [, col_name] ...)] {VALUES | VALUE} (value_list) [, (value_list)] ... REPLACE [LOW_PRIORITY | DELAYED] [INTO] tbl_name SET assignment_list REPLACE [LOW_PRIORITY | DELAYED] [INTO] tbl_name [(col_name [, col_name] ...)] SELECT ... 语法元素说明 语法元素 说明 LOW_PRIORITY 该语句为低优先级语句,TiDB 在执行阶段会降低这条语句的优先级 DELAYED TiDB 出于兼容性解析这个语法,但是不做任何处理 tbl_name 待更新的 Table 名称 value_list 待插入的数据 SET assignment_list 待更新的列名以及目标值 SELECT ... 待插入的数据集,该数据集来自于一个 Select 语句 "}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/dml/", "title": "数据操作语言", "content": " TiDB 数据操作语言 数据操作语言(Data Manipulation Language, DML)用于帮助用户实现对数据库的基本操作,比如查询、写入、删除和修改数据库中的数据。TiDB 支持的数据操作语言包括 Select ,Insert, Delete, Update,和 Replace。Select 语句 Select 语句用于从数据库中查询数据。语法定义 SELECT [ALL | DISTINCT | DISTINCTROW ] [HIGH_PRIORITY] [SQL_CACHE | SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS] select_expr [, select_expr ...] [FROM table_references [WHERE where_condition] [GROUP BY {col_name | expr | position} [ASC | DESC], ...] [HAVING where_condition] [ORDER BY {col_name | expr | position} [ASC | DESC], ...] [LIMIT {[offset,] row_count | row_count OFFSET offset}] [FOR UPDATE | LOCK IN SHARE MODE]] 语法元素说明 语法元素 说明 ALL、DISTINCT、DISTINCTROW 查询结果集中可能会包含重复值。指定 DISTINCT/DISTINCTROW 则在查询结果中过滤掉重复的行;指定 ALL 则列出所有的行。默认为 ALL。 HIGH_PRIORITY 该语句为高优先级语句,TiDB 在执行阶段会优先处理这条语句 SQL_CACHE、SQL_NO_CACHE、SQL_CALC_FOUND_ROWS TiDB 出于兼容性解析这三个语法,但是不做任何处理 select_expr 投影操作列表,一般包括列名、表达式,或者是用 ‘*’ 表示全部列 FROM table_references 表示数据来源,数据来源可以是一个表(select * from t;)或者是多个表 (select * from t1 join t2;) 或者是0个表 (select 1+1 from dual;, 等价于 select 1+1;) WHERE where_condition Where 子句用于设置过滤条件,查询结果中只会包含满足条件的数据 GROUP BY GroupBy 子句用于对查询结果集进行分组 HAVING where_condition Having 子句与 Where 子句作用类似,Having 子句可以让过滤 GroupBy 后的各种数据,Where 子句用于在聚合前过滤记录。 ORDER BY OrderBy 子句用于指定结果排序顺序,可以按照列、表达式或者是 select_expr 列表中某个位置的字段进行排序。 LIMIT Limit 子句用于限制结果条数。Limit 接受一个或两个数字参数,如果只有一个参数,那么表示返回数据的最大行数;如果是两个参数,那么第一个参数表示返回数据的第一行的偏移量(第一行数据的偏移量是 0),第二个参数指定返回数据的最大条目数。 FOR UPDATE 对查询结果集所有数据上读锁,以监测其他事务对这些的并发修改。TiDB 使用乐观事务模型在语句执行期间不会检测锁冲突,在事务的提交阶段才会检测事务冲突,如果执行 Select For Update 期间,有其他事务修改相关的数据,那么包含 Select For Update 语句的事务会提交失败。 LOCK IN SHARE MODE TiDB 出于兼容性解析这个语法,但是不做任何处理 Insert 语句 Insert 语句用于向数据库中插入数据,TiDB 兼容 MySQL Insert 语句的所有语法。语法定义 InsertStatement: INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE] [INTO] tbl_name insert_values [ON DUPLICATE KEY UPDATE assignment_list] insert_values: [(col_name [, col_name] ...)] {VALUES | VALUE} (expr_list) [, (expr_list)] ... | SET assignment_list | [(col_name [, col_name] ...)] SELECT ... expr_list: expr [, expr] ... assignment: col_name = expr assignment_list: assignment [, assignment] ... 语法元素说明 语法元素 说明 LOW_PRIORITY 该语句为低优先级语句,TiDB 在执行阶段会降低这条语句的优先级 DELAYED TiDB 出于兼容性解析这个语法,但是不做任何处理 HIGH_PRIORITY 该语句为高优先级语句,TiDB 在执行阶段会优先处理这条语句 IGNORE 如果发生 Uniq Key 冲突,则忽略插入的数据,不报错 tbl_name 要插入的表名 insert_values 待插入的数据,下面一节会详细描述 ON DUPLICATE KEY UPDATE assignment_list 如果发生 Uniq Key 冲突,则舍弃要插入的数据,改用 assignment_list 更新已存在的行 insert_values 待插入的数据集,可以用以下三种方式指定: Value List 将被插入的数据值写入列表中,例如:CREATE TABLE tbl_name ( a int, b int, c int ); INSERT INTO tbl_name VALUES(1,2,3),(4,5,6),(7,8,9); 上面的例子中,(1,2,3),(4,5,6),(7,8,9) 即为 Value List,其中每个括号内部的数据表示一行数据,这个例子中插入了三行数据。Insert 语句也可以只给部分列插入数据,这种情况下,需要在 Value List 之前加上 ColumnName List,如:INSERT INTO tbl_name (a,c) VALUES(1,2),(4,5),(7,8); 上面的例子中,每行数据只指定了 a 和 c 这两列的值,b 列的值会设为 Null。 Assignment List 通过赋值列表指定插入的数据,例如:INSERT INTO tbl_name SET a=1, b=2, c=3; 这种方式每次只能插入一行数据,每列的值通过赋值列表指定。 Select Statement 待插入的数据集是通过一个 Select 语句获取,要插入的列是通过 Select 语句的 Schema 获得。例如:CREATE TABLE tbl_name1 ( a int, b int, c int ); INSERT INTO tbl_name SELECT * from tbl_name1; 上面的例子中,从 tbl_name1 中查询出数据,插入 tbl_name 中。Delete 语句 Delete 语句用于删除数据库中的数据,TiDB 兼容 MySQL Delete 语句除 PARTITION 之外的所有语法。Delete 语句主要分为单表删除和多表删除两种,下面分开描述。单表删除 这种语法用于删除的数据只会涉及一个表的情况。语法定义 DELETE [LOW_PRIORITY] [QUICK] [IGNORE] FROM tbl_name [WHERE where_condition] [ORDER BY ...] [LIMIT row_count] 多表删除 这种语法用于删除的数据会涉及多张表的情况。一共有两种写法:DELETE [LOW_PRIORITY] [QUICK] [IGNORE] tbl_name[.*] [, tbl_name[.*]] ... FROM table_references [WHERE where_condition] DELETE [LOW_PRIORITY] [QUICK] [IGNORE] FROM tbl_name[.*] [, tbl_name[.*]] ... USING table_references [WHERE where_condition] 删除多个表的数据的时候,可以用这两种语法。这两种写法都可以指定从多个表查询数据,但只删除其中一些表的数据。在第一种语法中,只会删除 FROM 关键字之前的 Table 列表中所列 Table 的表中的数据。对于第二种写法,只会删除 FROM 之后 USING 之前的 Table 列表中的所列 Table 中的数据。语法元素说明 语法元素 说明 LOW_PRIORITY 该语句为低优先级语句,TiDB 在执行阶段会降低这条语句的优先级 QUICK TiDB 出于兼容性解析这个语法,但是不做任何处理 IGNORE TiDB 出于兼容性解析这个语法,但是不做任何处理 tbl_name 要删除数据的表名 WHERE where_condition Where 表达式,只删除满足表达式的那些行 ORDER BY 对待删除数据集进行排序 LIMIT row_count 只对待删除数据集中排序前 row_count 行的内容进行删除 Update 语句 Update 语句用于更新表中的数据。语法定义 Update 语句一共有两种语法,分别用于更新单表数据和多表数据。单表 Update UPDATE [LOW_PRIORITY] [IGNORE] table_reference SET assignment_list [WHERE where_condition] [ORDER BY ...] [LIMIT row_count] assignment: col_name = value assignment_list: assignment [, assignment] ... 单表 Update 语句会更新 Table 中现有行的指定列。SET assignment_list 指定了要更新的列名,以及要赋予地新值。 Where/OrderBy/Limit 子句一起用于从 Table 中查询出待更新的数据。多表 Update UPDATE [LOW_PRIORITY] [IGNORE] table_references SET assignment_list [WHERE where_condition] 多表更新语句用于将 table_references 中满足 Where 子句的数据地指定列赋予新的值。语法元素说明 语法元素 说明 LOW_PRIORITY 该语句为低优先级语句,TiDB 在执行阶段会降低这条语句的优先级 IGNORE TiDB 出于兼容性解析这个语法,但是不做任何处理 table_reference 待更新的 Table 名称 table_references 待更新的 Table 名称列表 SET assignment_list 待更新的列名以及目标值 WHERE where_condition Where 表达式,只更新满足表达式的那些行 ORDER BY 对待更新数据集进行排序 LIMIT row_count 只对待更新数据集中排序前 row_count 行的内容进行更新 Replace 语句 Replace 语句是 MySQL 对标准 SQL 语法的扩展,其行为和 Insert 语句一样,但是当现有数据中有和待插入数据在 PRIMARY KEY 或者 UNIQUE KEY 冲突的情况下,会先删除旧数据,再插入新数据。语法定义 REPLACE [LOW_PRIORITY | DELAYED] [INTO] tbl_name [(col_name [, col_name] ...)] {VALUES | VALUE} (value_list) [, (value_list)] ... REPLACE [LOW_PRIORITY | DELAYED] [INTO] tbl_name SET assignment_list REPLACE [LOW_PRIORITY | DELAYED] [INTO] tbl_name [(col_name [, col_name] ...)] SELECT ... 语法元素说明 语法元素 说明 LOW_PRIORITY 该语句为低优先级语句,TiDB 在执行阶段会降低这条语句的优先级 DELAYED TiDB 出于兼容性解析这个语法,但是不做任何处理 tbl_name 待更新的 Table 名称 value_list 待插入的数据 SET assignment_list 待更新的列名以及目标值 SELECT ... 待插入的数据集,该数据集来自于一个 Select 语句 "}, {"url": "https://pingcap.com/docs-cn/op-guide/migration/", "title": "数据迁移", "content": " 数据迁移 使用 mydumper/loader 全量导入数据 mydumper 是一个更强大的数据迁移工具,具体可以参考 https://github.com/maxbube/mydumper。你可以使用 mydumper 从 MySQL 导出数据,然后用 loader 将其导入到 TiDB 里面。 注意:虽然 TiDB 也支持使用 MySQL 官方的 mysqldump 工具来进行数据的迁移工作,但相比于 mydumper/loader,性能会慢很多,大量数据的迁移会花费很多时间,这里我们并不推荐。 mydumper/loader 全量导入数据最佳实践 为了快速的迁移数据 (特别是数据量巨大的库),可以参考以下建议: mydumper 导出数据至少要拥有 SELECT,RELOAD,LOCK TABLES 权限 使用 mydumper 导出来的数据文件尽可能的小,最好不要超过 64M,可以设置参数 -F 64 loader的 -t 参数可以根据 tikv 的实例个数以及负载进行评估调整,例如 3个 tikv 的场景,此值可以设为 3 *(1 ~ n);当 tikv 负载过高,loader 以及 tidb 日志中出现大量 backoffer.maxSleep 15000ms is exceeded 可以适当调小该值,当 tikv 负载不是太高的时候,可以适当调大该值。 某次导入示例,以及相关的配置 mydumper 导出后总数据量 214G,单表 8 列,20 亿行数据 集群拓扑 TIKV * 12 TIDB * 4 PD * 3 mydumper -F 设置为 16, loader -t 参数 64 结果:导入时间 11 小时左右,19.4 G/小时从 MySQL 导出数据 我们使用 mydumper 从 MySQL 导出数据,如下:./bin/mydumper -h 127.0.0.1 -P 3306 -u root -t 16 -F 64 -B test -T t1,t2 --skip-tz-utc -o ./var/test 上面,我们使用 -B test 表明是对 test 这个 database 操作,然后用 -T t1,t2 表明只导出 t1,t2 两张表。-t 16 表明使用 16 个线程去导出数据。-F 64 是将实际的 table 切分成多大的 chunk,这里就是 64MB 一个 chunk。--skip-tz-utc 添加这个参数忽略掉 MySQL 与导数据的机器之间时区设置不一致的情况,禁止自动转换。 注意:在阿里云等一些需要 super privilege 的云上面,mydumper 需要加上 --no-locks 参数,否则会提示没有权限操作。 向 TiDB 导入数据 注意:目前 TiDB 支持 UTF8mb4 字符编码,假设 mydumper 导出数据为 latin1 字符编码,请使用 iconv -f latin1 -t utf-8 $file -o /data/imdbload/$basename 命令转换,$file 为已有文件,$basename 为转换后文件。注意:如果 mydumper 使用 -m 参数,会导出不带表结构的数据,这时 loader 无法导入数据。 我们使用 loader 将之前导出的数据导入到 TiDB。Loader 的下载和具体的使用方法见 Loader 使用文档./bin/loader -h 127.0.0.1 -u root -P 4000 -t 32 -d ./var/test 导入成功之后,我们可以用 MySQL 官方客户端进入 TiDB,查看:mysql -h127.0.0.1 -P4000 -uroot mysql> show tables; +----------------+ | Tables_in_test | +----------------+ | t1 | | t2 | +----------------+ mysql> select * from t1; +----+------+ | id | age | +----+------+ | 1 | 1 | | 2 | 2 | | 3 | 3 | +----+------+ mysql> select * from t2; +----+------+ | id | name | +----+------+ | 1 | a | | 2 | b | | 3 | c | +----+------+ 使用 syncer 增量导入数据 上面我们介绍了如何使用 mydumper/loader 将 MySQL 的数据全量导入到 TiDB,但如果后续 MySQL 的数据有更新,我们仍然希望快速导入,使用全量的方式就不合适了。TiDB 提供 syncer 工具能方便的将 MySQL 的数据增量的导入到 TiDB 里面。syncer 属于 TiDB 企业版工具集,如何获取可以参考 下载 TiDB 企业版工具集。下载 TiDB 企业版工具集 (Linux) # 下载 tool 压缩包 wget http://download.pingcap.org/tidb-enterprise-tools-latest-linux-amd64.tar.gz wget http://download.pingcap.org/tidb-enterprise-tools-latest-linux-amd64.sha256 # 检查文件完整性,返回 ok 则正确 sha256sum -c tidb-enterprise-tools-latest-linux-amd64.sha256 # 解开压缩包 tar -xzf tidb-enterprise-tools-latest-linux-amd64.tar.gz cd tidb-enterprise-tools-latest-linux-amd64 假设我们之前已经使用 mydumper/loader 导入了 t1 和 t2 两张表的一些数据,现在我们希望这两张表的任何更新,都是实时的同步到 TiDB 上面。获取同步 position 如上文所提,mydumper 导出的数据目录里面有一个 metadata 文件,里面就包含了我们所需的 position 信息。medadata 文件信息内容举例:Started dump at: 2017-04-28 10:48:10 SHOW MASTER STATUS: Log: mysql-bin.000003 Pos: 930143241 GTID: Finished dump at: 2017-04-28 10:48:11 我们将 position 相关的信息保存到一个 syncer.meta 文件里面,用于 syncer 的同步:# cat syncer.meta binlog-name = "mysql-bin.000003" binlog-pos = 930143241 binlog-gtid = "2bfabd22-fff7-11e6-97f7-f02fa73bcb01:1-23,61ccbb5d-c82d-11e6-ac2e-487b6bd31bf7:1-4" 注意:syncer.meta 只需要第一次使用的时候配置,后续 syncer 同步新的 binlog 之后会自动将其更新到最新的 position。 注意: 如果使用 binlog position 同步则只需要配置 binlog-name binlog-pos; 使用 gtid 同步则需要设置 gtid,且启动 syncer 时带有 --enable-gtid 启动 syncer 启动 syncer 服务之前请详细阅读 Syncer 增量导入syncer 的配置文件 config.toml:log-level = "info" server-id = 101 ## meta 文件地址 meta = "./syncer.meta" worker-count = 16 batch = 10 ## pprof 调试地址, Prometheus 也可以通过该地址拉取 syncer metrics ## 将 127.0.0.1 修改为相应主机 IP 地址 status-addr = "127.0.0.1:10086" ## 跳过 DDL 或者其他语句,格式为 **前缀完全匹配**,如: `DROP TABLE ABC`,则至少需要填入`DROP TABLE`. # skip-sqls = ["ALTER USER", "CREATE USER"] ## 在使用 route-rules 功能后, ## replicate-do-db & replicate-ignore-db 匹配合表之后(target-schema & target-table )数值 ## 优先级关系: replicate-do-db --> replicate-do-table --> replicate-ignore-db --> replicate-ignore-table ## 指定要同步数据库名;支持正则匹配,表达式语句必须以 `~` 开始 #replicate-do-db = ["~^b.*","s1"] ## 指定要同步的 db.table 表 ## db-name 与 tbl-name 不支持 `db-name ="dbname,dbname2"` 格式 #[[replicate-do-table]] #db-name ="dbname" #tbl-name = "table-name" #[[replicate-do-table]] #db-name ="dbname1" #tbl-name = "table-name1" ## 指定要同步的 db.table 表;支持正则匹配,表达式语句必须以 `~` 开始 #[[replicate-do-table]] #db-name ="test" #tbl-name = "~^a.*" ## 指定**忽略**同步数据库;支持正则匹配,表达式语句必须以 `~` 开始 #replicate-ignore-db = ["~^b.*","s1"] ## 指定**忽略**同步数据库 ## db-name & tbl-name 不支持 `db-name ="dbname,dbname2"` 语句格式 #[[replicate-ignore-table]] #db-name = "your_db" #tbl-name = "your_table" ## 指定要**忽略**同步数据库名;支持正则匹配,表达式语句必须以 `~` 开始 #[[replicate-ignore-table]] #db-name ="test" #tbl-name = "~^a.*" # sharding 同步规则,采用 wildcharacter # 1. 星号字符 (*) 可以匹配零个或者多个字符, # 例子, doc* 匹配 doc 和 document, 但是和 dodo 不匹配; # 星号只能放在 pattern 结尾,并且一个 pattern 中只能有一个 # 2. 问号字符 (?) 匹配任一一个字符 #[[route-rules]] #pattern-schema = "route_*" #pattern-table = "abc_*" #target-schema = "route" #target-table = "abc" #[[route-rules]] #pattern-schema = "route_*" #pattern-table = "xyz_*" #target-schema = "route" #target-table = "xyz" [from] host = "127.0.0.1" user = "root" password = "" port = 3306 [to] host = "127.0.0.1" user = "root" password = "" port = 4000 启动 syncer:./bin/syncer -config config.toml 2016/10/27 15:22:01 binlogsyncer.go:226: [info] begin to sync binlog from position (mysql-bin.000003, 1280) 2016/10/27 15:22:01 binlogsyncer.go:130: [info] register slave for master server 127.0.0.1:3306 2016/10/27 15:22:01 binlogsyncer.go:552: [info] rotate to (mysql-bin.000003, 1280) 2016/10/27 15:22:01 syncer.go:549: [info] rotate binlog to (mysql-bin.000003, 1280) 在 MySQL 插入新的数据 INSERT INTO t1 VALUES (4, 4), (5, 5); 登录到 TiDB 查看:mysql -h127.0.0.1 -P4000 -uroot -p mysql> select * from t1; +----+------+ | id | age | +----+------+ | 1 | 1 | | 2 | 2 | | 3 | 3 | | 4 | 4 | | 5 | 5 | +----+------+ syncer 每隔 30s 会输出当前的同步统计,如下2017/06/08 01:18:51 syncer.go:934: [info] [syncer]total events = 15, total tps = 130, recent tps = 4, master-binlog = (ON.000001, 11992), master-binlog-gtid=53ea0ed1-9bf8-11e6-8bea-64006a897c73:1-74, syncer-binlog = (ON.000001, 2504), syncer-binlog-gtid = 53ea0ed1-9bf8-11e6-8bea-64006a897c73:1-17 2017/06/08 01:19:21 syncer.go:934: [info] [syncer]total events = 15, total tps = 191, recent tps = 2, master-binlog = (ON.000001, 11992), master-binlog-gtid=53ea0ed1-9bf8-11e6-8bea-64006a897c73:1-74, syncer-binlog = (ON.000001, 2504), syncer-binlog-gtid = 53ea0ed1-9bf8-11e6-8bea-64006a897c73:1-35 可以看到,使用 syncer,我们就能自动的将 MySQL 的更新同步到 TiDB。"}, {"url": "https://pingcap.com/docs-cn/v1.0/op-guide/migration/", "title": "数据迁移", "content": " 数据迁移 使用 mydumper/loader 全量导入数据 mydumper 是一个更强大的数据迁移工具,具体可以参考 https://github.com/maxbube/mydumper。我们使用 mydumper 从 MySQL 导出数据,然后用 loader 将其导入到 TiDB 里面。 注意:虽然 TiDB 也支持使用 MySQL 官方的 mysqldump 工具来进行数据的迁移工作,但相比于 mydumper / loader,性能会慢很多,大量数据的迁移会花费很多时间,这里我们并不推荐。 mydumper/loader 全量导入数据最佳实践 为了快速的迁移数据 (特别是数据量巨大的库), 可以参考下面建议 mydumper 导出数据至少要拥有 SELECT , RELOAD , LOCK TABLES 权限 使用 mydumper 导出来的数据文件尽可能的小, 最好不要超过 64M, 可以设置参数 -F 64 loader的 -t 参数可以根据 tikv 的实例个数以及负载进行评估调整,例如 3个 tikv 的场景, 此值可以设为 3 *(1 ~ n);当 tikv 负载过高,loader 以及 tidb 日志中出现大量 backoffer.maxSleep 15000ms is exceeded 可以适当调小该值,当 tikv 负载不是太高的时候,可以适当调大该值。 某次导入示例,以及相关的配置 mydumper 导出后总数据量 214G,单表 8 列,20 亿行数据 集群拓扑 TIKV * 12 TIDB * 4 PD * 3 mydumper -F 设置为 16, loader -t 参数 64 结果:导入时间 11 小时左右,19.4 G/小时从 MySQL 导出数据 我们使用 mydumper 从 MySQL 导出数据,如下:./bin/mydumper -h 127.0.0.1 -P 3306 -u root -t 16 -F 64 -B test -T t1,t2 --skip-tz-utc -o ./var/test 上面,我们使用 -B test 表明是对 test 这个 database 操作,然后用 -T t1,t2 表明只导出 t1,t2 两张表。-t 16 表明使用 16 个线程去导出数据。-F 64 是将实际的 table 切分成多大的 chunk,这里就是 64MB 一个 chunk。--skip-tz-utc 添加这个参数忽略掉 MySQL 与导数据的机器之间时区设置不一致的情况,禁止自动转换。 注意:在阿里云等一些需要 super privilege 的云上面,mydumper 需要加上 --no-locks 参数,否则会提示没有权限操作。 向 TiDB 导入数据 注意:目前 TiDB 支持 UTF8mb4 字符编码,假设 mydumper 导出数据为 latin1 字符编码,请使用 iconv -f latin1 -t utf-8 $file -o /data/imdbload/$basename 命令转换,$file 为已有文件,$basename 为转换后文件。注意:如果 mydumper 使用 -m 参数,会导出不带表结构的数据,这时 loader 无法导入数据。 我们使用 loader 将之前导出的数据导入到 TiDB。Loader 的下载和具体的使用方法见 Loader 使用文档./bin/loader -h 127.0.0.1 -u root -P 4000 -t 32 -d ./var/test 导入成功之后,我们可以用 MySQL 官方客户端进入 TiDB,查看:mysql -h127.0.0.1 -P4000 -uroot mysql> show tables; +----------------+ | Tables_in_test | +----------------+ | t1 | | t2 | +----------------+ mysql> select * from t1; +----+------+ | id | age | +----+------+ | 1 | 1 | | 2 | 2 | | 3 | 3 | +----+------+ mysql> select * from t2; +----+------+ | id | name | +----+------+ | 1 | a | | 2 | b | | 3 | c | +----+------+ 使用 syncer 增量导入数据 上面我们介绍了如何使用 mydumper/loader 将 MySQL 的数据全量导入到 TiDB,但如果后续 MySQL 的数据有更新,我们仍然希望快速导入,使用全量的方式就不合适了。TiDB 提供 syncer 工具能方便的将 MySQL 的数据增量的导入到 TiDB 里面。syncer 属于 TiDB 企业版工具集,如何获取可以参考 下载 TiDB 企业版工具集。下载 TiDB 企业版工具集 (Linux) # 下载 tool 压缩包 wget http://download.pingcap.org/tidb-enterprise-tools-latest-linux-amd64.tar.gz wget http://download.pingcap.org/tidb-enterprise-tools-latest-linux-amd64.sha256 # 检查文件完整性,返回 ok 则正确 sha256sum -c tidb-enterprise-tools-latest-linux-amd64.sha256 # 解开压缩包 tar -xzf tidb-enterprise-tools-latest-linux-amd64.tar.gz cd tidb-enterprise-tools-latest-linux-amd64 假设我们之前已经使用 mydumper/loader 导入了 t1 和 t2 两张表的一些数据,现在我们希望这两张表的任何更新,都是实时的同步到 TiDB 上面。获取同步 position 如上文所提,mydumper 导出的数据目录里面有一个 metadata 文件,里面就包含了我们所需的 position 信息。medadata 文件信息内容举例:Started dump at: 2017-04-28 10:48:10 SHOW MASTER STATUS: Log: mysql-bin.000003 Pos: 930143241 GTID: Finished dump at: 2017-04-28 10:48:11 我们将 position 相关的信息保存到一个 syncer.meta 文件里面,用于 syncer 的同步:# cat syncer.meta binlog-name = "mysql-bin.000003" binlog-pos = 930143241 binlog-gtid = "2bfabd22-fff7-11e6-97f7-f02fa73bcb01:1-23,61ccbb5d-c82d-11e6-ac2e-487b6bd31bf7:1-4" 注意:syncer.meta 只需要第一次使用的时候配置,后续 syncer 同步新的 binlog 之后会自动将其更新到最新的 position。 注意: 如果使用 binlog position 同步则只需要配置 binlog-name binlog-pos; 使用 gtid 同步则需要设置 gtid,且启动 syncer 时带有 --enable-gtid 启动 syncer 启动 syncer 服务之前请详细阅读 Syncer 增量导入syncer 的配置文件 config.toml:log-level = "info" server-id = 101 ## meta 文件地址 meta = "./syncer.meta" worker-count = 16 batch = 10 ## pprof 调试地址, Prometheus 也可以通过该地址拉取 syncer metrics ## 将 127.0.0.1 修改为相应主机 IP 地址 status-addr = "127.0.0.1:10086" ## 跳过 DDL 或者其他语句,格式为 **前缀完全匹配**,如: `DROP TABLE ABC`,则至少需要填入`DROP TABLE`. # skip-sqls = ["ALTER USER", "CREATE USER"] ## 在使用 route-rules 功能后, ## replicate-do-db & replicate-ignore-db 匹配合表之后(target-schema & target-table )数值 ## 优先级关系: replicate-do-db --> replicate-do-table --> replicate-ignore-db --> replicate-ignore-table ## 指定要同步数据库名;支持正则匹配,表达式语句必须以 `~` 开始 #replicate-do-db = ["~^b.*","s1"] ## 指定要同步的 db.table 表 ## db-name 与 tbl-name 不支持 `db-name ="dbname,dbname2"` 格式 #[[replicate-do-table]] #db-name ="dbname" #tbl-name = "table-name" #[[replicate-do-table]] #db-name ="dbname1" #tbl-name = "table-name1" ## 指定要同步的 db.table 表;支持正则匹配,表达式语句必须以 `~` 开始 #[[replicate-do-table]] #db-name ="test" #tbl-name = "~^a.*" ## 指定**忽略**同步数据库;支持正则匹配,表达式语句必须以 `~` 开始 #replicate-ignore-db = ["~^b.*","s1"] ## 指定**忽略**同步数据库 ## db-name & tbl-name 不支持 `db-name ="dbname,dbname2"` 语句格式 #[[replicate-ignore-table]] #db-name = "your_db" #tbl-name = "your_table" ## 指定要**忽略**同步数据库名;支持正则匹配,表达式语句必须以 `~` 开始 #[[replicate-ignore-table]] #db-name ="test" #tbl-name = "~^a.*" # sharding 同步规则,采用 wildcharacter # 1. 星号字符 (*) 可以匹配零个或者多个字符, # 例子, doc* 匹配 doc 和 document, 但是和 dodo 不匹配; # 星号只能放在 pattern 结尾,并且一个 pattern 中只能有一个 # 2. 问号字符 (?) 匹配任一一个字符 #[[route-rules]] #pattern-schema = "route_*" #pattern-table = "abc_*" #target-schema = "route" #target-table = "abc" #[[route-rules]] #pattern-schema = "route_*" #pattern-table = "xyz_*" #target-schema = "route" #target-table = "xyz" [from] host = "127.0.0.1" user = "root" password = "" port = 3306 [to] host = "127.0.0.1" user = "root" password = "" port = 4000 启动 syncer:./bin/syncer -config config.toml 2016/10/27 15:22:01 binlogsyncer.go:226: [info] begin to sync binlog from position (mysql-bin.000003, 1280) 2016/10/27 15:22:01 binlogsyncer.go:130: [info] register slave for master server 127.0.0.1:3306 2016/10/27 15:22:01 binlogsyncer.go:552: [info] rotate to (mysql-bin.000003, 1280) 2016/10/27 15:22:01 syncer.go:549: [info] rotate binlog to (mysql-bin.000003, 1280) 在 MySQL 插入新的数据 INSERT INTO t1 VALUES (4, 4), (5, 5); 登录到 TiDB 查看:mysql -h127.0.0.1 -P4000 -uroot -p mysql> select * from t1; +----+------+ | id | age | +----+------+ | 1 | 1 | | 2 | 2 | | 3 | 3 | | 4 | 4 | | 5 | 5 | +----+------+ syncer 每隔 30s 会输出当前的同步统计,如下2017/06/08 01:18:51 syncer.go:934: [info] [syncer]total events = 15, total tps = 130, recent tps = 4, master-binlog = (ON.000001, 11992), master-binlog-gtid=53ea0ed1-9bf8-11e6-8bea-64006a897c73:1-74, syncer-binlog = (ON.000001, 2504), syncer-binlog-gtid = 53ea0ed1-9bf8-11e6-8bea-64006a897c73:1-17 2017/06/08 01:19:21 syncer.go:934: [info] [syncer]total events = 15, total tps = 191, recent tps = 2, master-binlog = (ON.000001, 11992), master-binlog-gtid=53ea0ed1-9bf8-11e6-8bea-64006a897c73:1-74, syncer-binlog = (ON.000001, 2504), syncer-binlog-gtid = 53ea0ed1-9bf8-11e6-8bea-64006a897c73:1-35 可以看到,使用 syncer,我们就能自动的将 MySQL 的更新同步到 TiDB。"}, {"url": "https://pingcap.com/docs-cn/v2.0/op-guide/migration/", "title": "数据迁移", "content": " 数据迁移 使用 mydumper/loader 全量导入数据 mydumper 是一个更强大的数据迁移工具,具体可以参考 https://github.com/maxbube/mydumper。我们使用 mydumper 从 MySQL 导出数据,然后用 loader 将其导入到 TiDB 里面。 注意:虽然 TiDB 也支持使用 MySQL 官方的 mysqldump 工具来进行数据的迁移工作,但相比于 mydumper / loader,性能会慢很多,大量数据的迁移会花费很多时间,这里我们并不推荐。 mydumper/loader 全量导入数据最佳实践 为了快速的迁移数据 (特别是数据量巨大的库), 可以参考下面建议 mydumper 导出数据至少要拥有 SELECT , RELOAD , LOCK TABLES 权限 使用 mydumper 导出来的数据文件尽可能的小, 最好不要超过 64M, 可以设置参数 -F 64 loader的 -t 参数可以根据 tikv 的实例个数以及负载进行评估调整,例如 3个 tikv 的场景, 此值可以设为 3 *(1 ~ n);当 tikv 负载过高,loader 以及 tidb 日志中出现大量 backoffer.maxSleep 15000ms is exceeded 可以适当调小该值,当 tikv 负载不是太高的时候,可以适当调大该值。 某次导入示例,以及相关的配置 mydumper 导出后总数据量 214G,单表 8 列,20 亿行数据 集群拓扑 TIKV * 12 TIDB * 4 PD * 3 mydumper -F 设置为 16, loader -t 参数 64 结果:导入时间 11 小时左右,19.4 G/小时从 MySQL 导出数据 我们使用 mydumper 从 MySQL 导出数据,如下:./bin/mydumper -h 127.0.0.1 -P 3306 -u root -t 16 -F 64 -B test -T t1,t2 --skip-tz-utc -o ./var/test 上面,我们使用 -B test 表明是对 test 这个 database 操作,然后用 -T t1,t2 表明只导出 t1,t2 两张表。-t 16 表明使用 16 个线程去导出数据。-F 64 是将实际的 table 切分成多大的 chunk,这里就是 64MB 一个 chunk。--skip-tz-utc 添加这个参数忽略掉 MySQL 与导数据的机器之间时区设置不一致的情况,禁止自动转换。 注意:在阿里云等一些需要 super privilege 的云上面,mydumper 需要加上 --no-locks 参数,否则会提示没有权限操作。 向 TiDB 导入数据 注意:目前 TiDB 支持 UTF8mb4 字符编码,假设 mydumper 导出数据为 latin1 字符编码,请使用 iconv -f latin1 -t utf-8 $file -o /data/imdbload/$basename 命令转换,$file 为已有文件,$basename 为转换后文件。注意:如果 mydumper 使用 -m 参数,会导出不带表结构的数据,这时 loader 无法导入数据。 我们使用 loader 将之前导出的数据导入到 TiDB。Loader 的下载和具体的使用方法见 Loader 使用文档./bin/loader -h 127.0.0.1 -u root -P 4000 -t 32 -d ./var/test 导入成功之后,我们可以用 MySQL 官方客户端进入 TiDB,查看:mysql -h127.0.0.1 -P4000 -uroot mysql> show tables; +----------------+ | Tables_in_test | +----------------+ | t1 | | t2 | +----------------+ mysql> select * from t1; +----+------+ | id | age | +----+------+ | 1 | 1 | | 2 | 2 | | 3 | 3 | +----+------+ mysql> select * from t2; +----+------+ | id | name | +----+------+ | 1 | a | | 2 | b | | 3 | c | +----+------+ 使用 syncer 增量导入数据 上面我们介绍了如何使用 mydumper/loader 将 MySQL 的数据全量导入到 TiDB,但如果后续 MySQL 的数据有更新,我们仍然希望快速导入,使用全量的方式就不合适了。TiDB 提供 syncer 工具能方便的将 MySQL 的数据增量的导入到 TiDB 里面。syncer 属于 TiDB 企业版工具集,如何获取可以参考 下载 TiDB 企业版工具集。下载 TiDB 企业版工具集 (Linux) # 下载 tool 压缩包 wget http://download.pingcap.org/tidb-enterprise-tools-latest-linux-amd64.tar.gz wget http://download.pingcap.org/tidb-enterprise-tools-latest-linux-amd64.sha256 # 检查文件完整性,返回 ok 则正确 sha256sum -c tidb-enterprise-tools-latest-linux-amd64.sha256 # 解开压缩包 tar -xzf tidb-enterprise-tools-latest-linux-amd64.tar.gz cd tidb-enterprise-tools-latest-linux-amd64 假设我们之前已经使用 mydumper/loader 导入了 t1 和 t2 两张表的一些数据,现在我们希望这两张表的任何更新,都是实时的同步到 TiDB 上面。获取同步 position 如上文所提,mydumper 导出的数据目录里面有一个 metadata 文件,里面就包含了我们所需的 position 信息。medadata 文件信息内容举例:Started dump at: 2017-04-28 10:48:10 SHOW MASTER STATUS: Log: mysql-bin.000003 Pos: 930143241 GTID: Finished dump at: 2017-04-28 10:48:11 我们将 position 相关的信息保存到一个 syncer.meta 文件里面,用于 syncer 的同步:# cat syncer.meta binlog-name = "mysql-bin.000003" binlog-pos = 930143241 binlog-gtid = "2bfabd22-fff7-11e6-97f7-f02fa73bcb01:1-23,61ccbb5d-c82d-11e6-ac2e-487b6bd31bf7:1-4" 注意:syncer.meta 只需要第一次使用的时候配置,后续 syncer 同步新的 binlog 之后会自动将其更新到最新的 position。 注意: 如果使用 binlog position 同步则只需要配置 binlog-name binlog-pos; 使用 gtid 同步则需要设置 gtid,且启动 syncer 时带有 --enable-gtid 启动 syncer 启动 syncer 服务之前请详细阅读 Syncer 增量导入syncer 的配置文件 config.toml:log-level = "info" server-id = 101 ## meta 文件地址 meta = "./syncer.meta" worker-count = 16 batch = 10 ## pprof 调试地址, Prometheus 也可以通过该地址拉取 syncer metrics ## 将 127.0.0.1 修改为相应主机 IP 地址 status-addr = "127.0.0.1:10086" ## 跳过 DDL 或者其他语句,格式为 **前缀完全匹配**,如: `DROP TABLE ABC`,则至少需要填入`DROP TABLE`. # skip-sqls = ["ALTER USER", "CREATE USER"] ## 在使用 route-rules 功能后, ## replicate-do-db & replicate-ignore-db 匹配合表之后(target-schema & target-table )数值 ## 优先级关系: replicate-do-db --> replicate-do-table --> replicate-ignore-db --> replicate-ignore-table ## 指定要同步数据库名;支持正则匹配,表达式语句必须以 `~` 开始 #replicate-do-db = ["~^b.*","s1"] ## 指定要同步的 db.table 表 ## db-name 与 tbl-name 不支持 `db-name ="dbname,dbname2"` 格式 #[[replicate-do-table]] #db-name ="dbname" #tbl-name = "table-name" #[[replicate-do-table]] #db-name ="dbname1" #tbl-name = "table-name1" ## 指定要同步的 db.table 表;支持正则匹配,表达式语句必须以 `~` 开始 #[[replicate-do-table]] #db-name ="test" #tbl-name = "~^a.*" ## 指定**忽略**同步数据库;支持正则匹配,表达式语句必须以 `~` 开始 #replicate-ignore-db = ["~^b.*","s1"] ## 指定**忽略**同步数据库 ## db-name & tbl-name 不支持 `db-name ="dbname,dbname2"` 语句格式 #[[replicate-ignore-table]] #db-name = "your_db" #tbl-name = "your_table" ## 指定要**忽略**同步数据库名;支持正则匹配,表达式语句必须以 `~` 开始 #[[replicate-ignore-table]] #db-name ="test" #tbl-name = "~^a.*" # sharding 同步规则,采用 wildcharacter # 1. 星号字符 (*) 可以匹配零个或者多个字符, # 例子, doc* 匹配 doc 和 document, 但是和 dodo 不匹配; # 星号只能放在 pattern 结尾,并且一个 pattern 中只能有一个 # 2. 问号字符 (?) 匹配任一一个字符 #[[route-rules]] #pattern-schema = "route_*" #pattern-table = "abc_*" #target-schema = "route" #target-table = "abc" #[[route-rules]] #pattern-schema = "route_*" #pattern-table = "xyz_*" #target-schema = "route" #target-table = "xyz" [from] host = "127.0.0.1" user = "root" password = "" port = 3306 [to] host = "127.0.0.1" user = "root" password = "" port = 4000 启动 syncer:./bin/syncer -config config.toml 2016/10/27 15:22:01 binlogsyncer.go:226: [info] begin to sync binlog from position (mysql-bin.000003, 1280) 2016/10/27 15:22:01 binlogsyncer.go:130: [info] register slave for master server 127.0.0.1:3306 2016/10/27 15:22:01 binlogsyncer.go:552: [info] rotate to (mysql-bin.000003, 1280) 2016/10/27 15:22:01 syncer.go:549: [info] rotate binlog to (mysql-bin.000003, 1280) 在 MySQL 插入新的数据 INSERT INTO t1 VALUES (4, 4), (5, 5); 登录到 TiDB 查看:mysql -h127.0.0.1 -P4000 -uroot -p mysql> select * from t1; +----+------+ | id | age | +----+------+ | 1 | 1 | | 2 | 2 | | 3 | 3 | | 4 | 4 | | 5 | 5 | +----+------+ syncer 每隔 30s 会输出当前的同步统计,如下2017/06/08 01:18:51 syncer.go:934: [info] [syncer]total events = 15, total tps = 130, recent tps = 4, master-binlog = (ON.000001, 11992), master-binlog-gtid=53ea0ed1-9bf8-11e6-8bea-64006a897c73:1-74, syncer-binlog = (ON.000001, 2504), syncer-binlog-gtid = 53ea0ed1-9bf8-11e6-8bea-64006a897c73:1-17 2017/06/08 01:19:21 syncer.go:934: [info] [syncer]total events = 15, total tps = 191, recent tps = 2, master-binlog = (ON.000001, 11992), master-binlog-gtid=53ea0ed1-9bf8-11e6-8bea-64006a897c73:1-74, syncer-binlog = (ON.000001, 2504), syncer-binlog-gtid = 53ea0ed1-9bf8-11e6-8bea-64006a897c73:1-35 可以看到,使用 syncer,我们就能自动的将 MySQL 的更新同步到 TiDB。"}, {"url": "https://pingcap.com/docs-cn/op-guide/migration-overview/", "title": "数据迁移概述", "content": " 数据迁移概述 概述 该文档详细介绍了如何将 MySQL 的数据迁移到 TiDB。这里我们假定 MySQL 以及 TiDB 服务信息如下: Name Address Port User Password MySQL 127.0.0.1 3306 root * TiDB 127.0.0.1 4000 root * 在这个数据迁移过程中,我们会用到下面四个工具: checker 检查 schema 能否被 TiDB 兼容 mydumper 从 MySQL 导出数据 loader 导入数据到 TiDB syncer 增量同步 MySQL 数据到 TiDB 两种迁移场景 第一种场景:只全量导入历史数据 (需要 checker + mydumper + loader); 第二种场景:全量导入历史数据后,通过增量的方式同步新的数据 (需要 checker + mydumper + loader + syncer)。该场景需要提前开启 binlog 且格式必须为 ROW。 MySQL 开启 binlog 注意: 只有上文提到的第二种场景才需要在 dump 数据之前先开启 binlog MySQL 开启 binlog 功能,参考 Setting the Replication Master Configuration Binlog 格式必须使用 ROW format,这也是 MySQL 5.7 之后推荐的 binlog 格式,可以使用如下语句打开:SET GLOBAL binlog_format = ROW; 使用 checker 进行 Schema 检查 在迁移之前,我们可以使用 TiDB 的 checker 工具,来预先检查 TiDB 是否能支持需要迁移的 table schema。如果 check 某个 table schema 失败,表明 TiDB 当前并不支持,我们不能对该 table 里面的数据进行迁移。checker 包含在 TiDB 工具集里面,我们可以直接下载。下载 TiDB 工具集 (Linux) # 下载 tool 压缩包 wget http://download.pingcap.org/tidb-enterprise-tools-latest-linux-amd64.tar.gz wget http://download.pingcap.org/tidb-enterprise-tools-latest-linux-amd64.sha256 # 检查文件完整性,返回 ok 则正确 sha256sum -c tidb-enterprise-tools-latest-linux-amd64.sha256 # 解开压缩包 tar -xzf tidb-enterprise-tools-latest-linux-amd64.tar.gz cd tidb-enterprise-tools-latest-linux-amd64 使用 checker 检查的一个示范 在 MySQL 的 test database 里面创建几张表,并插入数据:USE test; CREATE TABLE t1 (id INT, age INT, PRIMARY KEY(id)) ENGINE=InnoDB; CREATE TABLE t2 (id INT, name VARCHAR(256), PRIMARY KEY(id)) ENGINE=InnoDB; INSERT INTO t1 VALUES (1, 1), (2, 2), (3, 3); INSERT INTO t2 VALUES (1, "a"), (2, "b"), (3, "c"); 使用 checker 检查 test database 里面所有的 table./bin/checker -host 127.0.0.1 -port 3306 -user root test 2016/10/27 13:11:49 checker.go:48: [info] Checking database test 2016/10/27 13:11:49 main.go:37: [info] Database DSN: root:@tcp(127.0.0.1:3306)/test?charset=utf8 2016/10/27 13:11:49 checker.go:63: [info] Checking table t1 2016/10/27 13:11:49 checker.go:69: [info] Check table t1 succ 2016/10/27 13:11:49 checker.go:63: [info] Checking table t2 2016/10/27 13:11:49 checker.go:69: [info] Check table t2 succ 使用 checker 检查 test database 里面某一个 table这里,假设我们只需要迁移 table t1。./bin/checker -host 127.0.0.1 -port 3306 -user root test t1 2016/10/27 13:13:56 checker.go:48: [info] Checking database test 2016/10/27 13:13:56 main.go:37: [info] Database DSN: root:@tcp(127.0.0.1:3306)/test?charset=utf8 2016/10/27 13:13:56 checker.go:63: [info] Checking table t1 2016/10/27 13:13:56 checker.go:69: [info] Check table t1 succ Check database succ! 一个无法迁移的 table 例子 我们在 MySQL 里面创建如下表:CREATE TABLE t_error ( a INT NOT NULL, PRIMARY KEY (a)) ENGINE=InnoDB TABLESPACE ts1 PARTITION BY RANGE (a) PARTITIONS 3 ( PARTITION P1 VALUES LESS THAN (2), PARTITION P2 VALUES LESS THAN (4) TABLESPACE ts2, PARTITION P3 VALUES LESS THAN (6) TABLESPACE ts3); 使用 checker 进行检查,会报错,表明我们没法迁移 t_error 这张表。./bin/checker -host 127.0.0.1 -port 3306 -user root test t_error 2017/08/04 11:14:35 checker.go:48: [info] Checking database test 2017/08/04 11:14:35 main.go:39: [info] Database DSN: root:@tcp(127.0.0.1:3306)/test?charset=utf8 2017/08/04 11:14:35 checker.go:63: [info] Checking table t1 2017/08/04 11:14:35 checker.go:67: [error] Check table t1 failed with err: line 3 column 29 near " ENGINE=InnoDB DEFAULT CHARSET=latin1 /*!50100 PARTITION BY RANGE (a) (PARTITION P1 VALUES LESS THAN (2) ENGINE = InnoDB, PARTITION P2 VALUES LESS THAN (4) TABLESPACE = ts2 ENGINE = InnoDB, PARTITION P3 VALUES LESS THAN (6) TABLESPACE = ts3 ENGINE = InnoDB) */" (total length 354) github.com/pingcap/tidb/parser/yy_parser.go:96: github.com/pingcap/tidb/parser/yy_parser.go:109: /home/jenkins/workspace/build_tidb_tools_master/go/src/github.com/pingcap/tidb-tools/checker/checker.go:122: parse CREATE TABLE `t1` ( `a` int(11) NOT NULL, PRIMARY KEY (`a`) ) /*!50100 TABLESPACE ts1 */ ENGINE=InnoDB DEFAULT CHARSET=latin1 /*!50100 PARTITION BY RANGE (a) (PARTITION P1 VALUES LESS THAN (2) ENGINE = InnoDB, PARTITION P2 VALUES LESS THAN (4) TABLESPACE = ts2 ENGINE = InnoDB, PARTITION P3 VALUES LESS THAN (6) TABLESPACE = ts3 ENGINE = InnoDB) */ error /home/jenkins/workspace/build_tidb_tools_master/go/src/github.com/pingcap/tidb-tools/checker/checker.go:114: 2017/08/04 11:14:35 main.go:83: [error] Check database test with 1 errors and 0 warnings."}, {"url": "https://pingcap.com/docs-cn/v1.0/op-guide/migration-overview/", "title": "数据迁移概述", "content": " 数据迁移概述 概述 该文档详细介绍了如何将 MySQL 的数据迁移到 TiDB。这里我们假定 MySQL 以及 TiDB 服务信息如下: Name Address Port User Password MySQL 127.0.0.1 3306 root * TiDB 127.0.0.1 4000 root * 在这个数据迁移过程中,我们会用到下面四个工具: checker 检查 schema 能否被 TiDB 兼容 mydumper 从 MySQL 导出数据 loader 导入数据到 TiDB syncer 增量同步 MySQL 数据到 TiDB 两种迁移场景 第一种场景:只全量导入历史数据 (需要 checker + mydumper + loader); 第二种场景:全量导入历史数据后,通过增量的方式同步新的数据 (需要 checker + mydumper + loader + syncer)。该场景需要提前开启 binlog 且格式必须为 ROW。 MySQL 开启 binlog 注意: 只有上文提到的第二种场景才需要在 dump 数据之前先开启 binlog MySQL 开启 binlog 功能,参考 Setting the Replication Master Configuration Binlog 格式必须使用 ROW format,这也是 MySQL 5.7 之后推荐的 binlog 格式,可以使用如下语句打开:SET GLOBAL binlog_format = ROW; 使用 checker 进行 Schema 检查 在迁移之前,我们可以使用 TiDB 的 checker 工具,来预先检查 TiDB 是否能支持需要迁移的 table schema。如果 check 某个 table schema 失败,表明 TiDB 当前并不支持,我们不能对该 table 里面的数据进行迁移。checker 包含在 TiDB 工具集里面,我们可以直接下载。下载 TiDB 工具集 (Linux) # 下载 tool 压缩包 wget http://download.pingcap.org/tidb-enterprise-tools-latest-linux-amd64.tar.gz wget http://download.pingcap.org/tidb-enterprise-tools-latest-linux-amd64.sha256 # 检查文件完整性,返回 ok 则正确 sha256sum -c tidb-enterprise-tools-latest-linux-amd64.sha256 # 解开压缩包 tar -xzf tidb-enterprise-tools-latest-linux-amd64.tar.gz cd tidb-enterprise-tools-latest-linux-amd64 使用 checker 检查的一个示范 在 MySQL 的 test database 里面创建几张表,并插入数据:USE test; CREATE TABLE t1 (id INT, age INT, PRIMARY KEY(id)) ENGINE=InnoDB; CREATE TABLE t2 (id INT, name VARCHAR(256), PRIMARY KEY(id)) ENGINE=InnoDB; INSERT INTO t1 VALUES (1, 1), (2, 2), (3, 3); INSERT INTO t2 VALUES (1, "a"), (2, "b"), (3, "c"); 使用 checker 检查 test database 里面所有的 table./bin/checker -host 127.0.0.1 -port 3306 -user root test 2016/10/27 13:11:49 checker.go:48: [info] Checking database test 2016/10/27 13:11:49 main.go:37: [info] Database DSN: root:@tcp(127.0.0.1:3306)/test?charset=utf8 2016/10/27 13:11:49 checker.go:63: [info] Checking table t1 2016/10/27 13:11:49 checker.go:69: [info] Check table t1 succ 2016/10/27 13:11:49 checker.go:63: [info] Checking table t2 2016/10/27 13:11:49 checker.go:69: [info] Check table t2 succ 使用 checker 检查 test database 里面某一个 table这里,假设我们只需要迁移 table t1。./bin/checker -host 127.0.0.1 -port 3306 -user root test t1 2016/10/27 13:13:56 checker.go:48: [info] Checking database test 2016/10/27 13:13:56 main.go:37: [info] Database DSN: root:@tcp(127.0.0.1:3306)/test?charset=utf8 2016/10/27 13:13:56 checker.go:63: [info] Checking table t1 2016/10/27 13:13:56 checker.go:69: [info] Check table t1 succ Check database succ! 一个无法迁移的 table 例子 我们在 MySQL 里面创建如下表:CREATE TABLE t_error ( a INT NOT NULL, PRIMARY KEY (a)) ENGINE=InnoDB TABLESPACE ts1 PARTITION BY RANGE (a) PARTITIONS 3 ( PARTITION P1 VALUES LESS THAN (2), PARTITION P2 VALUES LESS THAN (4) TABLESPACE ts2, PARTITION P3 VALUES LESS THAN (6) TABLESPACE ts3); 使用 checker 进行检查,会报错,表明我们没法迁移 t_error 这张表。./bin/checker -host 127.0.0.1 -port 3306 -user root test t_error 2017/08/04 11:14:35 checker.go:48: [info] Checking database test 2017/08/04 11:14:35 main.go:39: [info] Database DSN: root:@tcp(127.0.0.1:3306)/test?charset=utf8 2017/08/04 11:14:35 checker.go:63: [info] Checking table t1 2017/08/04 11:14:35 checker.go:67: [error] Check table t1 failed with err: line 3 column 29 near " ENGINE=InnoDB DEFAULT CHARSET=latin1 /*!50100 PARTITION BY RANGE (a) (PARTITION P1 VALUES LESS THAN (2) ENGINE = InnoDB, PARTITION P2 VALUES LESS THAN (4) TABLESPACE = ts2 ENGINE = InnoDB, PARTITION P3 VALUES LESS THAN (6) TABLESPACE = ts3 ENGINE = InnoDB) */" (total length 354) github.com/pingcap/tidb/parser/yy_parser.go:96: github.com/pingcap/tidb/parser/yy_parser.go:109: /home/jenkins/workspace/build_tidb_tools_master/go/src/github.com/pingcap/tidb-tools/checker/checker.go:122: parse CREATE TABLE `t1` ( `a` int(11) NOT NULL, PRIMARY KEY (`a`) ) /*!50100 TABLESPACE ts1 */ ENGINE=InnoDB DEFAULT CHARSET=latin1 /*!50100 PARTITION BY RANGE (a) (PARTITION P1 VALUES LESS THAN (2) ENGINE = InnoDB, PARTITION P2 VALUES LESS THAN (4) TABLESPACE = ts2 ENGINE = InnoDB, PARTITION P3 VALUES LESS THAN (6) TABLESPACE = ts3 ENGINE = InnoDB) */ error /home/jenkins/workspace/build_tidb_tools_master/go/src/github.com/pingcap/tidb-tools/checker/checker.go:114: 2017/08/04 11:14:35 main.go:83: [error] Check database test with 1 errors and 0 warnings."}, {"url": "https://pingcap.com/docs-cn/v2.0/op-guide/migration-overview/", "title": "数据迁移概述", "content": " 数据迁移概述 概述 该文档详细介绍了如何将 MySQL 的数据迁移到 TiDB。这里我们假定 MySQL 以及 TiDB 服务信息如下: Name Address Port User Password MySQL 127.0.0.1 3306 root * TiDB 127.0.0.1 4000 root * 在这个数据迁移过程中,我们会用到下面四个工具: checker 检查 schema 能否被 TiDB 兼容 mydumper 从 MySQL 导出数据 loader 导入数据到 TiDB syncer 增量同步 MySQL 数据到 TiDB 两种迁移场景 第一种场景:只全量导入历史数据 (需要 checker + mydumper + loader); 第二种场景:全量导入历史数据后,通过增量的方式同步新的数据 (需要 checker + mydumper + loader + syncer)。该场景需要提前开启 binlog 且格式必须为 ROW。 MySQL 开启 binlog 注意: 只有上文提到的第二种场景才需要在 dump 数据之前先开启 binlog MySQL 开启 binlog 功能,参考 Setting the Replication Master Configuration Binlog 格式必须使用 ROW format,这也是 MySQL 5.7 之后推荐的 binlog 格式,可以使用如下语句打开:SET GLOBAL binlog_format = ROW; 使用 checker 进行 Schema 检查 在迁移之前,我们可以使用 TiDB 的 checker 工具,来预先检查 TiDB 是否能支持需要迁移的 table schema。如果 check 某个 table schema 失败,表明 TiDB 当前并不支持,我们不能对该 table 里面的数据进行迁移。checker 包含在 TiDB 工具集里面,我们可以直接下载。下载 TiDB 工具集 (Linux) # 下载 tool 压缩包 wget http://download.pingcap.org/tidb-enterprise-tools-latest-linux-amd64.tar.gz wget http://download.pingcap.org/tidb-enterprise-tools-latest-linux-amd64.sha256 # 检查文件完整性,返回 ok 则正确 sha256sum -c tidb-enterprise-tools-latest-linux-amd64.sha256 # 解开压缩包 tar -xzf tidb-enterprise-tools-latest-linux-amd64.tar.gz cd tidb-enterprise-tools-latest-linux-amd64 使用 checker 检查的一个示范 在 MySQL 的 test database 里面创建几张表,并插入数据:USE test; CREATE TABLE t1 (id INT, age INT, PRIMARY KEY(id)) ENGINE=InnoDB; CREATE TABLE t2 (id INT, name VARCHAR(256), PRIMARY KEY(id)) ENGINE=InnoDB; INSERT INTO t1 VALUES (1, 1), (2, 2), (3, 3); INSERT INTO t2 VALUES (1, "a"), (2, "b"), (3, "c"); 使用 checker 检查 test database 里面所有的 table./bin/checker -host 127.0.0.1 -port 3306 -user root test 2016/10/27 13:11:49 checker.go:48: [info] Checking database test 2016/10/27 13:11:49 main.go:37: [info] Database DSN: root:@tcp(127.0.0.1:3306)/test?charset=utf8 2016/10/27 13:11:49 checker.go:63: [info] Checking table t1 2016/10/27 13:11:49 checker.go:69: [info] Check table t1 succ 2016/10/27 13:11:49 checker.go:63: [info] Checking table t2 2016/10/27 13:11:49 checker.go:69: [info] Check table t2 succ 使用 checker 检查 test database 里面某一个 table这里,假设我们只需要迁移 table t1。./bin/checker -host 127.0.0.1 -port 3306 -user root test t1 2016/10/27 13:13:56 checker.go:48: [info] Checking database test 2016/10/27 13:13:56 main.go:37: [info] Database DSN: root:@tcp(127.0.0.1:3306)/test?charset=utf8 2016/10/27 13:13:56 checker.go:63: [info] Checking table t1 2016/10/27 13:13:56 checker.go:69: [info] Check table t1 succ Check database succ! 一个无法迁移的 table 例子 我们在 MySQL 里面创建如下表:CREATE TABLE t_error ( a INT NOT NULL, PRIMARY KEY (a)) ENGINE=InnoDB TABLESPACE ts1 PARTITION BY RANGE (a) PARTITIONS 3 ( PARTITION P1 VALUES LESS THAN (2), PARTITION P2 VALUES LESS THAN (4) TABLESPACE ts2, PARTITION P3 VALUES LESS THAN (6) TABLESPACE ts3); 使用 checker 进行检查,会报错,表明我们没法迁移 t_error 这张表。./bin/checker -host 127.0.0.1 -port 3306 -user root test t_error 2017/08/04 11:14:35 checker.go:48: [info] Checking database test 2017/08/04 11:14:35 main.go:39: [info] Database DSN: root:@tcp(127.0.0.1:3306)/test?charset=utf8 2017/08/04 11:14:35 checker.go:63: [info] Checking table t1 2017/08/04 11:14:35 checker.go:67: [error] Check table t1 failed with err: line 3 column 29 near " ENGINE=InnoDB DEFAULT CHARSET=latin1 /*!50100 PARTITION BY RANGE (a) (PARTITION P1 VALUES LESS THAN (2) ENGINE = InnoDB, PARTITION P2 VALUES LESS THAN (4) TABLESPACE = ts2 ENGINE = InnoDB, PARTITION P3 VALUES LESS THAN (6) TABLESPACE = ts3 ENGINE = InnoDB) */" (total length 354) github.com/pingcap/tidb/parser/yy_parser.go:96: github.com/pingcap/tidb/parser/yy_parser.go:109: /home/jenkins/workspace/build_tidb_tools_master/go/src/github.com/pingcap/tidb-tools/checker/checker.go:122: parse CREATE TABLE `t1` ( `a` int(11) NOT NULL, PRIMARY KEY (`a`) ) /*!50100 TABLESPACE ts1 */ ENGINE=InnoDB DEFAULT CHARSET=latin1 /*!50100 PARTITION BY RANGE (a) (PARTITION P1 VALUES LESS THAN (2) ENGINE = InnoDB, PARTITION P2 VALUES LESS THAN (4) TABLESPACE = ts2 ENGINE = InnoDB, PARTITION P3 VALUES LESS THAN (6) TABLESPACE = ts3 ENGINE = InnoDB) */ error /home/jenkins/workspace/build_tidb_tools_master/go/src/github.com/pingcap/tidb-tools/checker/checker.go:114: 2017/08/04 11:14:35 main.go:83: [error] Check database test with 1 errors and 0 warnings."}, {"url": "https://pingcap.com/news-cn/", "title": "新闻报道", "content": ""}, {"url": "https://pingcap.com/docs-cn/sql/date-and-time-functions/", "title": "日期和时间函数", "content": " 日期和时间函数 TiDB 中日期和时间函数的使用方法与 MySQL 基本一致,详情参见: Date and Time Functions.日期时间函数表 函数名 功能描述 ADDDATE() 将时间间隔添加到日期上 ADDTIME() 时间数值相加 CONVERT_TZ() 转换时区 CURDATE() 返回当前日期 CURRENT_DATE(), CURRENT_DATE 与 CURDATE() 同义 CURRENT_TIME(), CURRENT_TIME 与 CURTIME() 同义 CURRENT_TIMESTAMP(), CURRENT_TIMESTAMP 与 NOW() 同义 CURTIME() 返回当前时间 DATE() 从日期或日期/时间表达式中提取日期部分 DATE_ADD() 将时间间隔添加到日期上 DATE_FORMAT() 返回满足指定格式的日期/时间 DATE_SUB() 从日期减去指定的时间间隔 DATEDIFF() 返回两个日期间隔的天数 DAY() 与 DAYOFMONTH() 同义 DAYNAME() 返回星期名称 DAYOFMONTH() 返回参数对应的天数部分(1-31) DAYOFWEEK() 返回参数对应的星期下标 DAYOFYEAR() 返回参数代表一年的哪一天 (1-366) EXTRACT() 提取日期/时间中的单独部分 FROM_DAYS() 将天数转化为日期 FROM_UNIXTIME() 将 Unix 时间戳格式化为日期 GET_FORMAT() 返回满足日期格式的字符串 HOUR() 提取日期/时间表达式中的小时部分 LAST_DAY 返回参数中月份的最后一天 LOCALTIME(), LOCALTIME 与 NOW() 同义 LOCALTIMESTAMP, LOCALTIMESTAMP() 与 NOW() 同义 MAKEDATE() 根据给定的年份和一年中的天数生成一个日期 MAKETIME() 根据给定的时、分、秒生成一个时间 MICROSECOND() 返回参数的微秒部分 MINUTE() 返回参数的分钟部分 MONTH() 返回参数的月份部分 MONTHNAME() 返回参数的月份名称 NOW() 返回当前日期和时间 PERIOD_ADD() 在年-月表达式上添加一段时间(数个月) PERIOD_DIFF() 返回间隔的月数 QUARTER() 返回参数对应的季度(1-4) SEC_TO_TIME() 将秒数转化为 ‘HH:MM:SS’ 的格式 SECOND() 返回秒数(0-59) STR_TO_DATE() 将字符串转化为日期 SUBDATE() 当传入三个参数时作为 DATE_SUB() 的同义 SUBTIME() 从一个时间中减去一段时间 SYSDATE() 返回该方法执行时的时间 TIME() 返回参数的时间表达式部分 TIME_FORMAT() 格式化时间 TIME_TO_SEC() 返回参数对应的秒数 TIMEDIFF() 返回时间间隔 TIMESTAMP() 传入一个参数时候,该方法返回日期或日期/时间表达式, 传入两个参数时候, 返回参数的和 TIMESTAMPADD() 在日期/时间表达式上增加一段时间间隔 TIMESTAMPDIFF() 从日期/时间表达式中减去一段时间间隔 TO_DAYS() 将参数转化对应的天数(从第 0 年开始) TO_SECONDS() 将日期或日期/时间参数转化为秒数(从第 0 年开始) UNIX_TIMESTAMP() 返回一个 Unix 时间戳 UTC_DATE() 返回当前的 UTC 日期 UTC_TIME() 返回当前的 UTC 时间 UTC_TIMESTAMP() 返回当前的 UTC 日期和时间 WEEK() 返回参数所在的一年中的星期数 WEEKDAY() 返回星期下标 WEEKOFYEAR() 返回参数在日历中对应的一年中的星期数 YEAR() 返回参数对应的年数 YEARWEEK() 返回年数和星期数 "}, {"url": "https://pingcap.com/docs-cn/sql/date-and-time-types/", "title": "日期和时间类型", "content": " 日期和时间类型 用于表示日期和时间类型的值是 DATE,TIME,DATETIME,TIMESTAMP 和 YEAR。每一种类型都有自己的有效值的范围,也有一个零值用于表示它是一个无效的值。TIMESTAMP 类型有个自动更新的行为,后面介绍。处理日期和时间类型时,请记住下面这些: 尽管 TiDB 尝试解释不同的格式,日期部分必须是按 年-月-日 的顺序(比如,’98-09-04’),而不是 月-日-年 或者 日-月-年 的顺序。 日期值中包含两位数字的年份是有歧义的,TiDB 按下面规则解释: 范围在 70-99 之间的被转换成 1970-1999 范围在 00-69 之间的被转换成 2000-2069 如果上下文里面需要的是一个数值,TiDB 自动将日期或时间值转换成数值类型,反之亦然。 如果 TiDB 遇到一个日期或时间值是超过表示范围的,或者无效的,会自动将它转换为该类型的零值。 设置不同的 SQL mode 可以改变 TiDB 的行为。 TiDB 允许 DATE 和 DATETIME 列中出现月份或者日为零的值,比如 ‘2009-00-00’ 或 ‘2009-01-00’。如果这种日期参与计算,比如函数 DATE_SUB() 或者 DATE_ADD(),得到的结果可能会不正确。 TiDB 允许存储零值 ‘0000-00-00’,有时候这会比 NULL 值更方便一些。 下面的表格里面显示了不同类型的零值: Date Type “Zero” Value DATE ‘0000-00-00’ TIME ‘00:00:00’ DATETIME ‘0000-00-00 00:00:00’ TIMESTAMP ‘0000-00-00 00:00:00’ YEAR 0000 DATE,DATETIME 和 TIMESTAMP 类型 DATE,DATETIME,TIMESTAMP 类型都是相关的。这里描述它们的共同点和区别。DATA 用于只有日期部分,没有时间部分。TiDB 按照 ‘YYYY-MM-DD’ 格式接受和显示 DATE 类型的值。支持的值的范围是在 ‘1000-01-01’ 到 ‘9999-12-31’。DATETIME 包含了日期和时间部分,格式是 ‘YYYY-MM-DD HH:MM:SS’。支持的值的范围是在 ‘1000-01-01 00:00:00’ 到 ‘9999-12-31 23:59:59’。TIMESTAMP 包含了日期和时间部分,值的范围是UTC时间 ‘1970-01-01 00:00:01’ 到 ‘2038-01-19 03:14:07’。DATETIME 和 TIMESTAMP 值可以包含一个最多6位的分数部分,精确到毫秒精度。任何 DATETIME 或 TIMESTAMP 类型的列里面,分数部分都会被存储下来,而不是丢弃。如果包含分数部分,那么值的格式就是 ‘YYYY-MM-DD HH:MM:SS[.fraction]‘,分数的范围是 000000-999999。分数和其它部分之间必需用小数点分隔。TiDB 将 TIMESTAMP 从当前时区转成 UTC 时区存储,检索时再从 UTC 时区转化到当前时区(注意,DATETIME 并不会这样处理)。每个连接默认的时区是服务器的本地时区,可以通过 time_zone 环境变量进行修改。只要时区保持不变,存储和取回来的值都是一样的。如果存储的是 TIMESTAMP 值,并且时区改变了,那么存储的值和读出来的值会发生变化。不合法的 DATE,DATETIME,TIMESTAMP 值会被自动地转成相应类型的零值(’0000-00-00’ 或 ‘0000-00-00 00:00:00’)。注意,TIMESTAMP 类型的值是不允许月份或者日里面出现零的,唯一的例外是零值本身 ‘0000-00-00 00:00:00’。两位数的年份是有歧义的,会按照如下规则解释: 00-69 范围被转换成 2000-2069 70-99 范围被转换成 1970-1999 TIME 类型 TIME 类型的值的格式是 ‘HH:MM:SS’,值的范围是 ‘-838:59:59’ 到 ‘838:59:59’。时间部分比较大,是因为 TIME 类型不仅用于表示一天里面的时间,也可以用于两个事件之间的时间间隔。TIME 类型可以包含分数部分,如果包含分数部分,那么 TIME 的表示范围则是 ‘-838:59:59.000000’ 到 ‘838:59:59.000000’。注意缩写的时间,’11:12’ 表示的是 ‘11:12:00’ 而不是 ‘00:11:12’,然而 ‘1112’ 表示的是 ‘00:11:12’。这里的区别是是否包含分号 :,处理起来是不一样的。YEAR 类型 YEAR 的值的格式是 YYYY,表示范围从 1901 到 2155,或者是零值 0000。指定 YEAR 的值可以按下列格式: 4位数字从 1901 到 2155 4位字符串从 ‘1901’ 到 ‘2155’ 1位或者2位数字,从 1 到 99。相应的,1-69 会被转换为 2001-2069,70-99 会被转换为 1970-1999 1位或者2位字符串,从 ‘0’ 到 ‘99’ 数值的 0 会被当作 0000,而字符串的 ‘0’ 或 ‘00’ 会被当作 2000 不合法的的 YEAR 的值被会自动转换成 0000。TIMESTAMP 和 DATETIME 的自动初始化和更新 TIMESTAMP 和 DATETIME 列可以被自动初始化或者更新为当前时间。对于表里面任意的 TIMESTAMP 或者 DATETIME 列,可以将默认值或者自动更新值指定为 current timestamp。通过在列定义时指定 DEFAULT CURRENT_TIMESTAMP 和 ON UPDATE CURRENT_TIMESTAMP 可以设置这些属性。DEFAULT 也可以指定成某个特定的值,比如 DEFAULT 0 或者 DEFAULT '2000-01-01 00:00:00'。CREATE TABLE t1 ( ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, dt DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ); 除非指定了 NOT NULL,否则 DATETIME 的默认值是 NULL,如果 NOT NULL 时不指定默认值,默认值是 0。CREATE TABLE t1 ( dt1 DATETIME ON UPDATE CURRENT_TIMESTAMP, -- default NULL dt2 DATETIME NOT NULL ON UPDATE CURRENT_TIMESTAMP -- default 0 ); 时间值中的小数部分 TIME,DATETIME,TIMESTAMP 支持分数部分,可以精确到毫秒精度。 使用 type_name(fsp) 来定义支持分数精度的列,其中 type_name 可以是 TIME,DATETIME 或者 TIMESTAMP,例如: CREATE TABLE t1 (t TIME(3), dt DATETIME(6)); fsp 必须是从 0 到 6。0 表示没有分数部分,如果 fsp 忽略,则默认就是 0。 插入一条 TIME,DATETIME 或者 TIMESTAMP 涉及到分数部分时,如果分数位不够,或者过多,可能会涉及到 rounding。例如: mysql> CREATE TABLE fractest( c1 TIME(2), c2 DATETIME(2), c3 TIMESTAMP(2) ); Query OK, 0 rows affected (0.33 sec) mysql> INSERT INTO fractest VALUES > ('17:51:04.777', '2014-09-08 17:51:04.777', '2014-09-08 17:51:04.777'); Query OK, 1 row affected (0.03 sec) mysql> SELECT * FROM fractest; +-------------|------------------------|------------------------+ | c1 | c2 | c3 | +-------------|------------------------|------------------------+ | 17:51:04.78 | 2014-09-08 17:51:04.78 | 2014-09-08 17:51:04.78 | +-------------|------------------------|------------------------+ 1 row in set (0.00 sec) 日期和时间类型转换 有时候可能会需要在日期类型间进行转换,某些转换可能会丢失信息。例如,DATE,DATETIME,TIMESTAMP 的值都是有各自的表示范围的。TIMESTAMP 不可以早于 UTC 时间的 1970 年,或者晚于 UTC 时间的 ‘2038-01-19 03:14:07’,这意味着 ‘1968-01-01’ 是一个合理的 DATE 或者 DATETIME 日期值,但是转换成 TIMESTAMP 时会变成 0。DATE 的转换: 转成 DATETIME 或者 TIMESTAMP 会添加时间部分 ‘00:00:00’,因为 DATE 不包含时间信息 转成 TIME 会变成 ‘00:00:00’ DATETIME 和 TIMESTAMP 的转换: 转成 DATE 会丢弃时间和分数部分,比如 ‘1999-12-31 23:59:59.499’ 变成 ‘1999-12-31’ 转成 TIME 会丢弃日期部分,因为 TIME 里面不包含日期信息 将 TIME 转成其它时间日期格式时, 自动地使用 CURRENT_DATE() 作为日期部分,最后生成的是 TIME 的时间加上 CURRENT_DATE() 之后得到的日期,也就是说如果 TIME 的值不是在 ‘00:00:00’ 到 ‘23:59:59’ 范围内,转换之后的日期部分并不是当天。TIME 转成 DATE 也是类似过程,然后丢弃时间部分。使用 CASE() 函数可以显示的转换类型,比如:date_col = CAST(datetime_col AS DATE) 将 TIME 和 DATETIME 转换成数值格式:mysql> SELECT CURTIME(), CURTIME()+0, CURTIME(3)+0; +-----------|-------------|--------------+ | CURTIME() | CURTIME()+0 | CURTIME(3)+0 | +-----------|-------------|--------------+ | 09:28:00 | 92800 | 92800.887 | +-----------|-------------|--------------+ mysql> SELECT NOW(), NOW()+0, NOW(3)+0; +---------------------|----------------|--------------------+ | NOW() | NOW()+0 | NOW(3)+0 | +---------------------|----------------|--------------------+ | 2012-08-15 09:28:00 | 20120815092800 | 20120815092800.889 | +---------------------|----------------|--------------------+ 日期中的两位数字的年 日期中包含两位数字的年是带有歧义的,因为不知道世纪。对于 DATETIME,DATE 和 TIMESTAMP 类型,TiDB 采用如下规则处理歧义: 范围在 00-69 被转换成 2000-2069 范围在 70-99 被转换成 1970-1999 对于 YEAR 也是类似过程,只有一个例外,数字的 00 插入到 YEAR(4) 会变成 0000 而不是 2000。如果想解释成 2000,则必需指定成 2000 或者是 ‘0’ 或 ‘00’。有些函数比如 MIN() 和 MAX() 对于两位数字的年处理可能不太好,使用四位格式会比较合适。"}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/date-and-time-types/", "title": "日期和时间类型", "content": " 日期和时间类型 用于表示日期和时间类型的值是 DATE,TIME,DATETIME,TIMESTAMP 和 YEAR。每一种类型都有自己的有效值的范围,也有一个零值用于表示它是一个无效的值。TIMESTAMP 类型有个自动更新的行为,后面介绍。处理日期和时间类型时,请记住下面这些: 尽管 TiDB 尝试解释不同的格式,日期部分必须是按 年-月-日 的顺序(比如,’98-09-04’),而不是 月-日-年 或者 日-月-年 的顺序。 日期值中包含两位数字的年份是有歧义的,TiDB 按下面规则解释: 范围在 70-99 之间的被转换成 1970-1999 范围在 00-69 之间的被转换成 2000-2069 如果上下文里面需要的是一个数值,TiDB 自动将日期或时间值转换成数值类型,反之亦然。 如果 TiDB 遇到一个日期或时间值是超过表示范围的,或者无效的,会自动将它转换为该类型的零值。 设置不同的 SQL mode 可以改变 TiDB 的行为。 TiDB 允许 DATE 和 DATETIME 列中出现月份或者日为零的值,比如 ‘2009-00-00’ 或 ‘2009-01-00’。如果这种日期参与计算,比如函数 DATE_SUB() 或者 DATE_ADD(),得到的结果可能会不正确。 TiDB 允许存储零值 ‘0000-00-00’,有时候这会比 NULL 值更方便一些。 下面的表格里面显示了不同类型的零值: Date Type “Zero” Value DATE ‘0000-00-00’ TIME ‘00:00:00’ DATETIME ‘0000-00-00 00:00:00’ TIMESTAMP ‘0000-00-00 00:00:00’ YEAR 0000 DATE,DATETIME 和 TIMESTAMP 类型 DATE,DATETIME,TIMESTAMP 类型都是相关的。这里描述它们的共同点和区别。DATA 用于只有日期部分,没有时间部分。TiDB 按照 ‘YYYY-MM-DD’ 格式接受和显示 DATE 类型的值。支持的值的范围是在 ‘1000-01-01’ 到 ‘9999-12-31’。DATETIME 包含了日期和时间部分,格式是 ‘YYYY-MM-DD HH:MM:SS’。支持的值的范围是在 ‘1000-01-01 00:00:00’ 到 ‘9999-12-31 23:59:59’。TIMESTAMP 包含了日期和时间部分,值的范围是UTC时间 ‘1970-01-01 00:00:01’ 到 ‘2038-01-19 03:14:07’。DATETIME 和 TIMESTAMP 值可以包含一个最多6位的分数部分,精确到毫秒精度。任何 DATETIME 或 TIMESTAMP 类型的列里面,分数部分都会被存储下来,而不是丢弃。如果包含分数部分,那么值的格式就是 ‘YYYY-MM-DD HH:MM:SS[.fraction]‘,分数的范围是 000000-999999。分数和其它部分之间必需用小数点分隔。TiDB 将 TIMESTAMP 从当前时区转成 UTC 时区存储,检索时再从 UTC 时区转化到当前时区(注意,DATETIME 并不会这样处理)。每个连接默认的时区是服务器的本地时区,可以通过 time_zone 环境变量进行修改。只要时区保持不变,存储和取回来的值都是一样的。如果存储的是 TIMESTAMP 值,并且时区改变了,那么存储的值和读出来的值会发生变化。不合法的 DATE,DATETIME,TIMESTAMP 值会被自动地转成相应类型的零值(’0000-00-00’ 或 ‘0000-00-00 00:00:00’)。注意,TIMESTAMP 类型的值是不允许月份或者日里面出现零的,唯一的例外是零值本身 ‘0000-00-00 00:00:00’。两位数的年份是有歧义的,会按照如下规则解释: 00-69 范围被转换成 2000-2069 70-99 范围被转换成 1970-1999 TIME 类型 TIME 类型的值的格式是 ‘HH:MM:SS’,值的范围是 ‘-838:59:59’ 到 ‘838:59:59’。时间部分比较大,是因为 TIME 类型不仅用于表示一天里面的时间,也可以用于两个事件之间的时间间隔。TIME 类型可以包含分数部分,如果包含分数部分,那么 TIME 的表示范围则是 ‘-838:59:59.000000’ 到 ‘838:59:59.000000’。注意缩写的时间,’11:12’ 表示的是 ‘11:12:00’ 而不是 ‘00:11:12’,然而 ‘1112’ 表示的是 ‘00:11:12’。这里的区别是是否包含分号 :,处理起来是不一样的。YEAR 类型 YEAR 的值的格式是 YYYY,表示范围从 1901 到 2155,或者是零值 0000。指定 YEAR 的值可以按下列格式: 4位数字从 1901 到 2155 4位字符串从 ‘1901’ 到 ‘2155’ 1位或者2位数字,从 1 到 99。相应的,1-69 会被转换为 2001-2069,70-99 会被转换为 1970-1999 1位或者2位字符串,从 ‘0’ 到 ‘99’ 数值的 0 会被当作 0000,而字符串的 ‘0’ 或 ‘00’ 会被当作 2000 不合法的的 YEAR 的值被会自动转换成 0000。TIMESTAMP 和 DATETIME 的自动初始化和更新 TIMESTAMP 和 DATETIME 列可以被自动初始化或者更新为当前时间。对于表里面任意的 TIMESTAMP 或者 DATETIME 列,可以将默认值或者自动更新值指定为 current timestamp。通过在列定义时指定 DEFAULT CURRENT_TIMESTAMP 和 ON UPDATE CURRENT_TIMESTAMP 可以设置这些属性。DEFAULT 也可以指定成某个特定的值,比如 DEFAULT 0 或者 DEFAULT '2000-01-01 00:00:00'。CREATE TABLE t1 ( ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, dt DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ); 除非指定了 NOT NULL,否则 DATETIME 的默认值是 NULL,如果 NOT NULL 时不指定默认值,默认值是 0。CREATE TABLE t1 ( dt1 DATETIME ON UPDATE CURRENT_TIMESTAMP, -- default NULL dt2 DATETIME NOT NULL ON UPDATE CURRENT_TIMESTAMP -- default 0 ); 时间值中的小数部分 TIME,DATETIME,TIMESTAMP 支持分数部分,可以精确到毫秒精度。 使用 type_name(fsp) 来定义支持分数精度的列,其中 type_name 可以是 TIME,DATETIME 或者 TIMESTAMP,例如: CREATE TABLE t1 (t TIME(3), dt DATETIME(6)); fsp 必须是从 0 到 6。0 表示没有分数部分,如果 fsp 忽略,则默认就是 0。 插入一条 TIME,DATETIME 或者 TIMESTAMP 涉及到分数部分时,如果分数位不够,或者过多,可能会涉及到 rounding。例如: mysql> CREATE TABLE fractest( c1 TIME(2), c2 DATETIME(2), c3 TIMESTAMP(2) ); Query OK, 0 rows affected (0.33 sec) mysql> INSERT INTO fractest VALUES > ('17:51:04.777', '2014-09-08 17:51:04.777', '2014-09-08 17:51:04.777'); Query OK, 1 row affected (0.03 sec) mysql> SELECT * FROM fractest; +-------------|------------------------|------------------------+ | c1 | c2 | c3 | +-------------|------------------------|------------------------+ | 17:51:04.78 | 2014-09-08 17:51:04.78 | 2014-09-08 17:51:04.78 | +-------------|------------------------|------------------------+ 1 row in set (0.00 sec) 日期和时间类型转换 有时候可能会需要在日期类型间进行转换,某些转换可能会丢失信息。例如,DATE,DATETIME,TIMESTAMP 的值都是有各自的表示范围的。TIMESTAMP 不可以早于 UTC 时间的 1970 年,或者晚于 UTC 时间的 ‘2038-01-19 03:14:07’,这意味着 ‘1968-01-01’ 是一个合理的 DATE 或者 DATETIME 日期值,但是转换成 TIMESTAMP 时会变成 0。DATE 的转换: 转成 DATETIME 或者 TIMESTAMP 会添加时间部分 ‘00:00:00’,因为 DATE 不包含时间信息 转成 TIME 会变成 ‘00:00:00’ DATETIME 和 TIMESTAMP 的转换: 转成 DATE 会丢弃时间和分数部分,比如 ‘1999-12-31 23:59:59.499’ 变成 ‘1999-12-31’ 转成 TIME 会丢弃日期部分,因为 TIME 里面不包含日期信息 将 TIME 转成其它时间日期格式时, 自动地使用 CURRENT_DATE() 作为日期部分,最后生成的是 TIME 的时间加上 CURRENT_DATE() 之后得到的日期,也就是说如果 TIME 的值不是在 ‘00:00:00’ 到 ‘23:59:59’ 范围内,转换之后的日期部分并不是当天。TIME 转成 DATE 也是类似过程,然后丢弃时间部分。使用 CASE() 函数可以显示的转换类型,比如:date_col = CAST(datetime_col AS DATE) 将 TIME 和 DATETIME 转换成数值格式:mysql> SELECT CURTIME(), CURTIME()+0, CURTIME(3)+0; +-----------|-------------|--------------+ | CURTIME() | CURTIME()+0 | CURTIME(3)+0 | +-----------|-------------|--------------+ | 09:28:00 | 92800 | 92800.887 | +-----------|-------------|--------------+ mysql> SELECT NOW(), NOW()+0, NOW(3)+0; +---------------------|----------------|--------------------+ | NOW() | NOW()+0 | NOW(3)+0 | +---------------------|----------------|--------------------+ | 2012-08-15 09:28:00 | 20120815092800 | 20120815092800.889 | +---------------------|----------------|--------------------+ 日期中的两位数字的年 日期中包含两位数字的年是带有歧义的,因为不知道世纪。对于 DATETIME,DATE 和 TIMESTAMP 类型,TiDB 采用如下规则处理歧义: 范围在 00-69 被转换成 2000-2069 范围在 70-99 被转换成 1970-1999 对于 YEAR 也是类似过程,只有一个例外,数字的 00 插入到 YEAR(4) 会变成 0000 而不是 2000。如果想解释成 2000,则必需指定成 2000 或者是 ‘0’ 或 ‘00’。有些函数比如 MIN() 和 MAX() 对于两位数字的年处理可能不太好,使用四位格式会比较合适。"}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/date-and-time-types/", "title": "日期和时间类型", "content": " 日期和时间类型 用于表示日期和时间类型的值是 DATE,TIME,DATETIME,TIMESTAMP 和 YEAR。每一种类型都有自己的有效值的范围,也有一个零值用于表示它是一个无效的值。TIMESTAMP 类型有个自动更新的行为,后面介绍。处理日期和时间类型时,请记住下面这些: 尽管 TiDB 尝试解释不同的格式,日期部分必须是按 年-月-日 的顺序(比如,’98-09-04’),而不是 月-日-年 或者 日-月-年 的顺序。 日期值中包含两位数字的年份是有歧义的,TiDB 按下面规则解释: 范围在 70-99 之间的被转换成 1970-1999 范围在 00-69 之间的被转换成 2000-2069 如果上下文里面需要的是一个数值,TiDB 自动将日期或时间值转换成数值类型,反之亦然。 如果 TiDB 遇到一个日期或时间值是超过表示范围的,或者无效的,会自动将它转换为该类型的零值。 设置不同的 SQL mode 可以改变 TiDB 的行为。 TiDB 允许 DATE 和 DATETIME 列中出现月份或者日为零的值,比如 ‘2009-00-00’ 或 ‘2009-01-00’。如果这种日期参与计算,比如函数 DATE_SUB() 或者 DATE_ADD(),得到的结果可能会不正确。 TiDB 允许存储零值 ‘0000-00-00’,有时候这会比 NULL 值更方便一些。 下面的表格里面显示了不同类型的零值: Date Type “Zero” Value DATE ‘0000-00-00’ TIME ‘00:00:00’ DATETIME ‘0000-00-00 00:00:00’ TIMESTAMP ‘0000-00-00 00:00:00’ YEAR 0000 DATE,DATETIME 和 TIMESTAMP 类型 DATE,DATETIME,TIMESTAMP 类型都是相关的。这里描述它们的共同点和区别。DATA 用于只有日期部分,没有时间部分。TiDB 按照 ‘YYYY-MM-DD’ 格式接受和显示 DATE 类型的值。支持的值的范围是在 ‘1000-01-01’ 到 ‘9999-12-31’。DATETIME 包含了日期和时间部分,格式是 ‘YYYY-MM-DD HH:MM:SS’。支持的值的范围是在 ‘1000-01-01 00:00:00’ 到 ‘9999-12-31 23:59:59’。TIMESTAMP 包含了日期和时间部分,值的范围是UTC时间 ‘1970-01-01 00:00:01’ 到 ‘2038-01-19 03:14:07’。DATETIME 和 TIMESTAMP 值可以包含一个最多6位的分数部分,精确到毫秒精度。任何 DATETIME 或 TIMESTAMP 类型的列里面,分数部分都会被存储下来,而不是丢弃。如果包含分数部分,那么值的格式就是 ‘YYYY-MM-DD HH:MM:SS[.fraction]‘,分数的范围是 000000-999999。分数和其它部分之间必需用小数点分隔。TiDB 将 TIMESTAMP 从当前时区转成 UTC 时区存储,检索时再从 UTC 时区转化到当前时区(注意,DATETIME 并不会这样处理)。每个连接默认的时区是服务器的本地时区,可以通过 time_zone 环境变量进行修改。只要时区保持不变,存储和取回来的值都是一样的。如果存储的是 TIMESTAMP 值,并且时区改变了,那么存储的值和读出来的值会发生变化。不合法的 DATE,DATETIME,TIMESTAMP 值会被自动地转成相应类型的零值(’0000-00-00’ 或 ‘0000-00-00 00:00:00’)。注意,TIMESTAMP 类型的值是不允许月份或者日里面出现零的,唯一的例外是零值本身 ‘0000-00-00 00:00:00’。两位数的年份是有歧义的,会按照如下规则解释: 00-69 范围被转换成 2000-2069 70-99 范围被转换成 1970-1999 TIME 类型 TIME 类型的值的格式是 ‘HH:MM:SS’,值的范围是 ‘-838:59:59’ 到 ‘838:59:59’。时间部分比较大,是因为 TIME 类型不仅用于表示一天里面的时间,也可以用于两个事件之间的时间间隔。TIME 类型可以包含分数部分,如果包含分数部分,那么 TIME 的表示范围则是 ‘-838:59:59.000000’ 到 ‘838:59:59.000000’。注意缩写的时间,’11:12’ 表示的是 ‘11:12:00’ 而不是 ‘00:11:12’,然而 ‘1112’ 表示的是 ‘00:11:12’。这里的区别是是否包含分号 :,处理起来是不一样的。YEAR 类型 YEAR 的值的格式是 YYYY,表示范围从 1901 到 2155,或者是零值 0000。指定 YEAR 的值可以按下列格式: 4位数字从 1901 到 2155 4位字符串从 ‘1901’ 到 ‘2155’ 1位或者2位数字,从 1 到 99。相应的,1-69 会被转换为 2001-2069,70-99 会被转换为 1970-1999 1位或者2位字符串,从 ‘0’ 到 ‘99’ 数值的 0 会被当作 0000,而字符串的 ‘0’ 或 ‘00’ 会被当作 2000 不合法的的 YEAR 的值被会自动转换成 0000。TIMESTAMP 和 DATETIME 的自动初始化和更新 TIMESTAMP 和 DATETIME 列可以被自动初始化或者更新为当前时间。对于表里面任意的 TIMESTAMP 或者 DATETIME 列,可以将默认值或者自动更新值指定为 current timestamp。通过在列定义时指定 DEFAULT CURRENT_TIMESTAMP 和 ON UPDATE CURRENT_TIMESTAMP 可以设置这些属性。DEFAULT 也可以指定成某个特定的值,比如 DEFAULT 0 或者 DEFAULT '2000-01-01 00:00:00'。CREATE TABLE t1 ( ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, dt DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ); 除非指定了 NOT NULL,否则 DATETIME 的默认值是 NULL,如果 NOT NULL 时不指定默认值,默认值是 0。CREATE TABLE t1 ( dt1 DATETIME ON UPDATE CURRENT_TIMESTAMP, -- default NULL dt2 DATETIME NOT NULL ON UPDATE CURRENT_TIMESTAMP -- default 0 ); 时间值中的小数部分 TIME,DATETIME,TIMESTAMP 支持分数部分,可以精确到毫秒精度。 使用 type_name(fsp) 来定义支持分数精度的列,其中 type_name 可以是 TIME,DATETIME 或者 TIMESTAMP,例如: CREATE TABLE t1 (t TIME(3), dt DATETIME(6)); fsp 必须是从 0 到 6。0 表示没有分数部分,如果 fsp 忽略,则默认就是 0。 插入一条 TIME,DATETIME 或者 TIMESTAMP 涉及到分数部分时,如果分数位不够,或者过多,可能会涉及到 rounding。例如: mysql> CREATE TABLE fractest( c1 TIME(2), c2 DATETIME(2), c3 TIMESTAMP(2) ); Query OK, 0 rows affected (0.33 sec) mysql> INSERT INTO fractest VALUES > ('17:51:04.777', '2014-09-08 17:51:04.777', '2014-09-08 17:51:04.777'); Query OK, 1 row affected (0.03 sec) mysql> SELECT * FROM fractest; +-------------|------------------------|------------------------+ | c1 | c2 | c3 | +-------------|------------------------|------------------------+ | 17:51:04.78 | 2014-09-08 17:51:04.78 | 2014-09-08 17:51:04.78 | +-------------|------------------------|------------------------+ 1 row in set (0.00 sec) 日期和时间类型转换 有时候可能会需要在日期类型间进行转换,某些转换可能会丢失信息。例如,DATE,DATETIME,TIMESTAMP 的值都是有各自的表示范围的。TIMESTAMP 不可以早于 UTC 时间的 1970 年,或者晚于 UTC 时间的 ‘2038-01-19 03:14:07’,这意味着 ‘1968-01-01’ 是一个合理的 DATE 或者 DATETIME 日期值,但是转换成 TIMESTAMP 时会变成 0。DATE 的转换: 转成 DATETIME 或者 TIMESTAMP 会添加时间部分 ‘00:00:00’,因为 DATE 不包含时间信息 转成 TIME 会变成 ‘00:00:00’ DATETIME 和 TIMESTAMP 的转换: 转成 DATE 会丢弃时间和分数部分,比如 ‘1999-12-31 23:59:59.499’ 变成 ‘1999-12-31’ 转成 TIME 会丢弃日期部分,因为 TIME 里面不包含日期信息 将 TIME 转成其它时间日期格式时, 自动地使用 CURRENT_DATE() 作为日期部分,最后生成的是 TIME 的时间加上 CURRENT_DATE() 之后得到的日期,也就是说如果 TIME 的值不是在 ‘00:00:00’ 到 ‘23:59:59’ 范围内,转换之后的日期部分并不是当天。TIME 转成 DATE 也是类似过程,然后丢弃时间部分。使用 CASE() 函数可以显示的转换类型,比如:date_col = CAST(datetime_col AS DATE) 将 TIME 和 DATETIME 转换成数值格式:mysql> SELECT CURTIME(), CURTIME()+0, CURTIME(3)+0; +-----------|-------------|--------------+ | CURTIME() | CURTIME()+0 | CURTIME(3)+0 | +-----------|-------------|--------------+ | 09:28:00 | 92800 | 92800.887 | +-----------|-------------|--------------+ mysql> SELECT NOW(), NOW()+0, NOW(3)+0; +---------------------|----------------|--------------------+ | NOW() | NOW()+0 | NOW(3)+0 | +---------------------|----------------|--------------------+ | 2012-08-15 09:28:00 | 20120815092800 | 20120815092800.889 | +---------------------|----------------|--------------------+ 日期中的两位数字的年 日期中包含两位数字的年是带有歧义的,因为不知道世纪。对于 DATETIME,DATE 和 TIMESTAMP 类型,TiDB 采用如下规则处理歧义: 范围在 00-69 被转换成 2000-2069 范围在 70-99 被转换成 1970-1999 对于 YEAR 也是类似过程,只有一个例外,数字的 00 插入到 YEAR(4) 会变成 0000 而不是 2000。如果想解释成 2000,则必需指定成 2000 或者是 ‘0’ 或 ‘00’。有些函数比如 MIN() 和 MAX() 对于两位数字的年处理可能不太好,使用四位格式会比较合适。"}, {"url": "https://pingcap.com/docs-cn/sql/time-zone/", "title": "时区支持", "content": " 时区支持 TiDB 使用的时区由 time_zone 全局变量和 session 变量决定。time_zone 的默认值是 System,System 对应的实际时区在 TiDB 集群 bootstrap 初始化时设置。具体逻辑如下: 优先使用 TZ 环境变量 如果失败,则从 /etc/localtime 的实际软链地址提取。 如果上面两种都失败则使用 UTC 作为系统时区。 在运行过程中可以修改全局时区:mysql> SET GLOBAL time_zone = timezone; TiDB 还可以通过设置 session 变量 time_zone 为每个连接维护各自的时区。默认条件下,这个值取的是全局变量 time_zone 的值。修改 session 使用的时区:mysql> SET time_zone = timezone; 查看当前使用的时区的值:mysql> SELECT @@global.time_zone, @@session.time_zone; 设置 time_zone 的值的格式: ‘SYSTEM’ 表明使用系统时间 相对于 UTC 时间的偏移,比如 ‘+10:00’ 或者 ‘-6:00’ 某个时区的名字,比如 ‘Europe/Helsinki’, ‘US/Eastern’ 或 ‘MET’ NOW() 和 CURTIME() 的返回值都受到时区设置的影响。注意,只有 Timestamp 数据类型的值是受时区影响的。可以理解为, Timestamp 数据类型的实际表示使用的是 (字面值 + 时区信息)。其它时间和日期类型,比如 Datetime/Date/Time 是不包含时区信息的,所以也不受到时区变化的影响。mysql> create table t (ts timestamp, dt datetime); Query OK, 0 rows affected (0.02 sec) mysql> set @@time_zone = 'UTC'; Query OK, 0 rows affected (0.00 sec) mysql> insert into t values ('2017-09-30 11:11:11', '2017-09-30 11:11:11'); Query OK, 1 row affected (0.00 sec) mysql> set @@time_zone = '+8:00'; Query OK, 0 rows affected (0.00 sec) mysql> select * from t; +---------------------|---------------------+ | ts | dt | +---------------------|---------------------+ | 2017-09-30 19:11:11 | 2017-09-30 11:11:11 | +---------------------|---------------------+ 1 row in set (0.00 sec) 上面的例子中,无论怎么调整时区的值, Datetime 类型字段的值是不受影响的,而 Timestamp 则随着时区改变,显示的值会发生变化。其实 Timestamp 持久化到存储的值始终没有变化过,只是根据时区的不同显示值不同。Timestamp 类型和 Datetime 等类型的值,两者相互转换的过程中,会涉及到时区。这种情况一律基于 session 的当前 time_zone 时区处理。另外,用户在导数据的过程中,也要需注意主库和从库之间的时区设定是否一致。"}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/time-zone/", "title": "时区支持", "content": "TiDB 使用的时区由 time_zone 全局变量和 session 变量决定。time_zone 的初始值是机器当前的系统时区 ‘SYSTEM’ 。在运行过程中可以修改全局时区:mysql> SET GLOBAL time_zone = timezone; TiDB 还可以通过设置 session 变量 time_zone 为每个连接维护各自的时区。默认条件下,这个值取的是全局变量 time_zone 的值。修改 session 使用的时区:mysql> SET time_zone = timezone; 查看当前使用的时区的值:mysql> SELECT @@global.time_zone, @@session.time_zone; 设置 time_zone 的值的格式: ‘SYSTEM’ 表明使用系统时间 相对于 UTC 时间的偏移,比如 ‘+10:00’ 或者 ‘-6:00’ 某个时区的名字,比如 ‘Europe/Helsinki’, ‘US/Eastern’ 或 ‘MET’ NOW() 和 CURTIME() 的返回值都受到时区设置的影响。注意,只有 Timestamp 数据类型的值是受时区影响的。可以理解为, Timestamp 数据类型的实际表示使用的是 (字面值 + 时区信息)。其它时间和日期类型,比如 Datetime/Date/Time 是不包含时区信息的,所以也不受到时区变化的影响。mysql> create table t (ts timestamp, dt datetime); Query OK, 0 rows affected (0.02 sec) mysql> set @@time_zone = 'UTC'; Query OK, 0 rows affected (0.00 sec) mysql> insert into t values ('2017-09-30 11:11:11', '2017-09-30 11:11:11'); Query OK, 1 row affected (0.00 sec) mysql> set @@time_zone = '+8:00'; Query OK, 0 rows affected (0.00 sec) mysql> select * from t; +---------------------|---------------------+ | ts | dt | +---------------------|---------------------+ | 2017-09-30 19:11:11 | 2017-09-30 11:11:11 | +---------------------|---------------------+ 1 row in set (0.00 sec) 上面的例子中,无论怎么调整时区的值, Datetime 类型字段的值是不受影响的,而 Timestamp 则随着时区改变,显示的值会发生变化。其实 Timestamp 持久化到存储的值始终没有变化过,只是根据时区的不同显示值不同。Timestamp 类型和 Datetime 等类型的值,两者相互转换的过程中,会涉及到时区。这种情况一律基于 session 的当前 time_zone 时区处理。另外,用户在导数据的过程中,也要需注意主库和从库之间的时区设定是否一致。"}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/time-zone/", "title": "时区支持", "content": "TiDB 使用的时区由 time_zone 全局变量和 session 变量决定。time_zone 的初始值是机器当前的系统时区 ‘SYSTEM’ 。在运行过程中可以修改全局时区:mysql> SET GLOBAL time_zone = timezone; TiDB 还可以通过设置 session 变量 time_zone 为每个连接维护各自的时区。默认条件下,这个值取的是全局变量 time_zone 的值。修改 session 使用的时区:mysql> SET time_zone = timezone; 查看当前使用的时区的值:mysql> SELECT @@global.time_zone, @@session.time_zone; 设置 time_zone 的值的格式: ‘SYSTEM’ 表明使用系统时间 相对于 UTC 时间的偏移,比如 ‘+10:00’ 或者 ‘-6:00’ 某个时区的名字,比如 ‘Europe/Helsinki’, ‘US/Eastern’ 或 ‘MET’ NOW() 和 CURTIME() 的返回值都受到时区设置的影响。注意,只有 Timestamp 数据类型的值是受时区影响的。可以理解为, Timestamp 数据类型的实际表示使用的是 (字面值 + 时区信息)。其它时间和日期类型,比如 Datetime/Date/Time 是不包含时区信息的,所以也不受到时区变化的影响。mysql> create table t (ts timestamp, dt datetime); Query OK, 0 rows affected (0.02 sec) mysql> set @@time_zone = 'UTC'; Query OK, 0 rows affected (0.00 sec) mysql> insert into t values ('2017-09-30 11:11:11', '2017-09-30 11:11:11'); Query OK, 1 row affected (0.00 sec) mysql> set @@time_zone = '+8:00'; Query OK, 0 rows affected (0.00 sec) mysql> select * from t; +---------------------|---------------------+ | ts | dt | +---------------------|---------------------+ | 2017-09-30 19:11:11 | 2017-09-30 11:11:11 | +---------------------|---------------------+ 1 row in set (0.00 sec) 上面的例子中,无论怎么调整时区的值, Datetime 类型字段的值是不受影响的,而 Timestamp 则随着时区改变,显示的值会发生变化。其实 Timestamp 持久化到存储的值始终没有变化过,只是根据时区的不同显示值不同。Timestamp 类型和 Datetime 等类型的值,两者相互转换的过程中,会涉及到时区。这种情况一律基于 session 的当前 time_zone 时区处理。另外,用户在导数据的过程中,也要需注意主库和从库之间的时区设定是否一致。"}, {"url": "https://pingcap.com/docs-cn/sql/privilege/", "title": "权限管理", "content": " 权限管理 权限管理概述 TiDB 的权限管理系统是按照 MySQL 的权限管理进行实现,大部分的 MySQL 的语法和权限类型都是支持的。如果发现行为跟 MySQL 不一致的地方,欢迎提 issue。示例 用户账户操作 TiDB 的用户账户名由一个用户名和一个主机名组成。账户名的语法为 'user_name'@'host_name'。 user_name 大小写敏感。 host_name 可以是一个主机名或 IP 地址。主机名或 IP 地址中允许使用通配符 % 和 _。例如,名为 '%' 的主机名可以匹配所有主机,'192.168.1.%' 可以匹配子网中的所有主机。 添加用户 CREATE USER 'test'@'127.0.0.1' IDENTIFIED BY 'xxx'; host 支持模糊匹配,比如:CREATE USER 'test'@'192.168.10.%'; 允许 test 用户从 192.168.10 子网的任何一个主机登陆。如果没有指定 host,则默认是所有 IP 均可登陆。如果没有指定密码,默认为空:CREATE USER 'test'; 等价于CREATE USER 'test'@'%' IDENTIFIED BY ''; 更改密码 SET PASSWORD FOR 'root'@'%' = 'xxx'; 删除用户 DROP USER 'test'@'%'; 这个操作会清除用户在 mysql.user 表里面的记录项,并且清除在授权表里面的相关记录。忘记 root 密码 使用一个特殊的启动参数启动 TiDB(需要 root 权限):sudo ./tidb-server -skip-grant-table=true 这个参数启动,TiDB 会跳过权限系统,然后使用 root 登陆以后修改密码:mysql -h 127.0.0.1 -P 4000 -u root 权限相关操作 授予权限 授予 xxx 用户对数据库 test 的读权限:GRANT SELECT ON test.* TO 'xxx'@'%'; 为 test 用户授予所有数据库,全部权限:GRANT ALL PRIVILEGES ON *.* TO 'xxx'@'%'; 如果 GRANT 的目标用户不存在,TiDB 会自动创建用户。mysql> SELECT * FROM mysql.user WHERE user='xxxx'; Empty set (0.00 sec) mysql> GRANT ALL PRIVILEGES ON test.* TO 'xxxx'@'%' IDENTIFIED BY 'yyyyy'; Query OK, 0 rows affected (0.00 sec) mysql> SELECT user,host FROM mysql.user WHERE user='xxxx'; +------|------+ | user | host | +------|------+ | xxxx | % | +------|------+ 1 row in set (0.00 sec) 例子中 xxxx@% 就是自动添加进去的用户。GRANT 对于数据库或者表的授权,不检查数据库或表是否存在。mysql> SELECT * FROM test.xxxx; ERROR 1146 (42S02): Table 'test.xxxx' doesn't exist mysql> GRANT ALL PRIVILEGES ON test.xxxx TO xxxx; Query OK, 0 rows affected (0.00 sec) mysql> SELECT user,host FROM mysql.tables_priv WHERE user='xxxx'; +------|------+ | user | host | +------|------+ | xxxx | % | +------|------+ 1 row in set (0.00 sec) GRANT 可以模糊匹配地授予数据库和表:mysql> GRANT ALL PRIVILEGES ON `te%`.* TO genius; Query OK, 0 rows affected (0.00 sec) mysql> SELECT user,host,db FROM mysql.db WHERE user='genius'; +--------|------|-----+ | user | host | db | +--------|------|-----+ | genius | % | te% | +--------|------|-----+ 1 row in set (0.00 sec) 这个例子中通过 % 模糊匹配,所有 te 开头的数据库,都被授予了权限。收回权限 REVOKE 语句与 GRANT 对应:REVOKE ALL PRIVILEGES ON `test`.* FROM 'genius'@'localhost'; 注意:revoke 收回权限时只做精确匹配,若找不到记录则报错。而 grant 授予权限时可以使用模糊匹配。 mysql> REVOKE ALL PRIVILEGES ON `te%`.* FROM 'genius'@'%'; ERROR 1141 (42000): There is no such grant defined for user 'genius' on host '%' 关于模糊匹配和转义,字符串和 identifier:mysql> GRANT ALL PRIVILEGES ON `te%`.* TO 'genius'@'localhost'; Query OK, 0 rows affected (0.00 sec) 上述例子是精确匹配名叫 te% 的数据库,注意使用 转义字符。以单引号包含的,是一个字符串。以反引号包含的,是一个 identifier。注意下面的区别:mysql> GRANT ALL PRIVILEGES ON 'test'.* TO 'genius'@'localhost'; ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''test'.* to 'genius'@'localhost'' at line 1 mysql> GRANT ALL PRIVILEGES ON `test`.* TO 'genius'@'localhost'; Query OK, 0 rows affected (0.00 sec) 如果一些特殊的关键字想做为表名,可以用反引号包含起来。比如:mysql> CREATE TABLE `select` (id int); Query OK, 0 rows affected (0.27 sec) 查看为用户分配的权限 SHOW GRANTS 语句可以查看为用户分配了哪些权限。例如:SHOW GRANTS; # 查看当前用户的权限 SHOW GRANTS for 'root'@'%'; # 查看某个特定用户的权限 更精确的方式,可以通过直接查看授权表的数据实现。比如想知道,test@% 该用户是否拥有对 db1.t 的 Insert 权限。先查看该用户是否拥有全局 Insert 权限:SELECT Insert_priv FROM mysql.user WHERE user='test' AND host='%'; 如果没有,再查看该用户是否拥有 db1 数据库级别的 Insert 权限:SELECT Insert_priv FROM mysql.db WHERE user='test' AND host='%'; 如果仍然没有,则继续判断是否拥有 db1.t 这张表的 Insert 权限:SELECT table_priv FROM mysql.tables_priv WHERE user='test' AND host='%' AND db='db1'; 权限系统的实现 授权表 有几张系统表是非常特殊的表,权限相关的数据全部存储在这几张表内。 mysql.user 用户账户,全局权限 mysql.db 数据库级别的权限 mysql.tables_priv 表级别的权限 mysql.columns_priv 列级别的权限,当前暂不支持 这几张表包含了数据的生效范围和权限信息。例如,mysql.user 表的部分数据:mysql> SELECT User,Host,Select_priv,Insert_priv FROM mysql.user LIMIT 1; +------|------|-------------|-------------+ | User | Host | Select_priv | Insert_priv | +------|------|-------------|-------------+ | root | % | Y | Y | +------|------|-------------|-------------+ 1 row in set (0.00 sec) 这条记录中,Host 和 User 决定了 root 用户从任意主机(%)发送过来的连接请求可以被接受,而 Select_priv 和 Insert_priv 表示用户拥有全局的 Select 和 Insert 权限。mysql.user 这张表里面的生效范围是全局的。mysql.db 表里面包含的 Host 和 User 决定了用户可以访问哪些数据库,权限列的生效范围是数据库。理论上,所有权限管理相关的操作,都可以通过直接对授权表的 CRUD 操作完成。实现层面其实也只是包装了一层语法糖。例如删除用户会执行:DELETE FROM mysql.user WHERE user='test'; 但是,不推荐手动修改授权表,建议使用 DROP USER 语句:DROP USER 'test'; 连接验证 当客户端发送连接请求时,TiDB 服务器会对登陆操作进行验证。验证过程先检查 mysql.user 表,当某条记录的 User 和 Host 和连接请求匹配上了,再去验证 Password。用户身份基于两部分信息,发起连接的客户端的 Host,以及用户名 User。如果 User不为空,则用户名必须精确匹配。User+Host 可能会匹配 user 表里面多行,为了处理这种情况,user 表的行是排序过的,客户端连接时会依次去匹配,并使用首次匹配到的那一行做权限验证。排序是按 Host 在前,User 在后。请求验证 连接成功之后,请求验证会检测执行操作是否拥有足够的权限。对于数据库相关请求 (INSERT,UPDATE),先检查 mysql.user 表里面的用户全局权限,如果权限够,则直接可以访问。如果全局权限不足,则再检查 mysql.db 表。user 表的权限是全局的,并且不管默认数据库是哪一个。比如 user 里面有 DELETE 权限,任何一行,任何的表,任何的数据库。db表里面,User 为空是匹配匿名用户,User 里面不能有通配符。Host 和 Db 列里面可以有 % 和 _,可以模式匹配。user 和 db 读到内存也是排序的。tables_priv 和 columns_priv 中使用 % 是类似的,但是在Db, Table_name, Column_name 这些列不能包含 %。加载进来时排序也是类似的。生效时机 TiDB 启动时,将一些权限检查的表加载到内存,之后使用缓存的数据来验证权限。系统会周期性的将授权表从数据库同步到缓存,生效则是由同步的周期决定,目前这个值设定的是5分钟。修改了授权表,如果需要立即生效,可以手动调用:FLUSH PRIVILEGES; 限制和约束 一些使用频率偏低的权限当前版本的实现中还未做检查,比如 FILE/USAGE/SHUTDOWN/EXECUTE/PROCESS/INDEX 等等,未来会陆续完善。现阶段对权限的支持还没有做到 column 级别。CREATE USER 语句 CREATE USER [IF NOT EXISTS] user [auth_spec] [, user [auth_spec]] ... auth_spec: { IDENTIFIED BY 'auth_string' | IDENTIFIED BY PASSWORD 'hash_string' } User 参见用户账号名。 IDENTIFIED BY 'auth_string':设置登录密码时,auth_string 会被 TiDB 经过加密存储在 mysql.user 表中。 IDENTIFIED BY PASSWORD 'hash_string':设置登录密码,hash_string 是一个类似于 *EBE2869D7542FCE37D1C9BBC724B97BDE54428F1 的 41 位字符串,会被 TiDB 直接存储在 mysql.user 表中,该字符串可以通过 SELECT password('auth_string') 加密得到。 "}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/privilege/", "title": "权限管理", "content": " 权限管理 权限管理概述 TiDB的权限管理系统是按照 MySQL 的权限管理进行实现,大部分的 MySQL 的语法和权限类型都是支持的。如果发现行为跟 MySQL 不一致的地方,欢迎报告 issue。示例 用户账户操作 更改密码 set password for 'root'@'%' = 'xxx'; 添加用户 create user 'test'@'127.0.0.1' identified by 'xxx'; 用户名是大小写敏感的。host则支持模糊匹配,比如:create user 'test'@'192.168.10.%'; 允许 test 用户从 192.168.10 子网的任何一个主机登陆。如果没有指定 host,则默认是所有 IP 均可登陆。如果没有指定密码,默认为空:create user 'test'; 等价于create user 'test'@'%' identified by ''; 删除用户 drop user 'test'@'%'; 这个操作会清除用户在 mysql.user 表里面的记录项,并且清除在授权表里面的相关记录。忘记root密码 使用一个特殊的启动参数启动 TiDB(需要root权限):sudo ./tidb-server -skip-grant-table=true 这个参数启动,TiDB 会跳过权限系统,然后使用 root 登陆以后修改密码:mysql -h 127.0.0.1 -P 4000 -u root 权限相关操作 授予权限 授予 xxx 用户对数据库 test 的读权限:grant Select on test.* to 'xxx'@'%'; 为 test 用户授予所有数据库,全部权限:grant all privileges on *.* to 'xxx'@'%'; 如果 grant 的目标用户不存在,TiDB 会自动创建用户。mysql> select * from mysql.user where user='xxxx'; Empty set (0.00 sec) mysql> grant all privileges on test.* to 'xxxx'@'%' identified by 'yyyyy'; Query OK, 0 rows affected (0.00 sec) mysql> select user,host from mysql.user where user='xxxx'; +------|------+ | user | host | +------|------+ | xxxx | % | +------|------+ 1 row in set (0.00 sec) 例子中 xxxx@% 就是自动添加进去的用户。grant 对于数据库或者表的授权,不检查数据库或表是否存在。mysql> select * from test.xxxx; ERROR 1146 (42S02): Table 'test.xxxx' doesn't exist mysql> grant all privileges on test.xxxx to xxxx; Query OK, 0 rows affected (0.00 sec) mysql> select user,host from mysql.tables_priv where user='xxxx'; +------|------+ | user | host | +------|------+ | xxxx | % | +------|------+ 1 row in set (0.00 sec) grant 可以模糊匹配地授予数据库和表mysql> grant all privileges on `te%`.* to genius; Query OK, 0 rows affected (0.00 sec) mysql> select user,host,db from mysql.db where user='genius'; +--------|------|-----+ | user | host | db | +--------|------|-----+ | genius | % | te% | +--------|------|-----+ 1 row in set (0.00 sec) 这个例子中通过 % 模糊匹配,所有 te 开头的数据库,都被授予了权限。收回权限 revoke语句与grant对应:revoke all privileges on `test`.* from 'genius'@'localhost'; 注意 revoke 收回权限时只做精确匹配,若找不到记录则报错。而 grant 授予权限时可以使用模糊匹配。mysql> revoke all privileges on `te%`.* from 'genius'@'%'; ERROR 1141 (42000): There is no such grant defined for user 'genius' on host '%' 关于模糊匹配和转义,字符串和 identifier> mysql> grant all privileges on `te%`.* to 'genius'@'localhost'; > Query OK, 0 rows affected (0.00 sec) > ``` > > 这个例子是精确匹配名叫 `te%` 的数据库,注意到用了 `` 转义字符。 > > 以单引号包含的,是一个字符串。以反引号包含的,是一个 identifier。注意下面区别: > > ``` > mysql> grant all privileges on 'test'.* to 'genius'@'localhost'; > ERROR 1064 (42000): You have an error in your SQL syntax; check the > manual that corresponds to your MySQL server version for the right > syntax to use near ''test'.* to 'genius'@'localhost'' at line 1 > > mysql> grant all privileges on `test`.* to 'genius'@'localhost'; > Query OK, 0 rows affected (0.00 sec) > ``` > > 如果一些特殊的关键字想做为表名,可以用反引号包含起来。比如: > > ``` > mysql> create table `select` (id int); > Query OK, 0 rows affected (0.27 sec) > ``` #### 查看为用户分配的权限 `SHOW GRANT` 语句可以查看为用户分配了哪些权限。 ```sql show grants for 'root'@'%'; 更精确的方式,可以通过直接查看授权表的数据实现。比如想知道,test@% 该用户是否拥有对 db1.t 的 Insert 权限。先查看该用户是否拥有全局 Insert 权限:select Insert from mysql.user where user='test' and host='%'; 如果没有,再查看该用户是否拥有 db1 数据库级别的 Insert权限:select Insert from mysql.db where user='test' and host='%'; 如果仍然没有,则继续判断是否拥有 db1.t 这张表的 Insert 权限:select tables_priv from mysql.tables_priv where user='test' and host='%' and db='db1'; 权限系统的实现 授权表 有几张系统表是非常特殊的表,权限相关的数据全部存储在这几张表内。 mysql.user 用户账户,全局权限 mysql.db 数据库级别的权限 mysql.tables_priv 表级别的权限 mysql.columns_priv 列级别的权限 这几张表包含了数据的生效范围和权限信息。例如,mysql.user 表的部分数据:mysql> select User,Host,Select_priv,Insert_priv from mysql.user limit 1; +------|------|-------------|-------------+ | User | Host | Select_priv | Insert_priv | +------|------|-------------|-------------+ | root | % | Y | Y | +------|------|-------------|-------------+ 1 row in set (0.00 sec) 这条记录中,Host 和 User 决定了 root 用户从任意主机(%)发送过来的连接请求可以被接受,而 Select_priv 和 Insert_priv 表示用户拥有全局的 Select 和 Insert 权限。mysql.user 这张表里面的生效范围是全局的。mysql.db 表里面包含的 Host 和 User 决定了用户可以访问哪些数据库,权限列的生效范围是数据库。理论上,所有权限管理相关的操作,都可以通过直接对授权表的 CRUD 操作完成。实现层面其实也只是包装了一层语法糖。例如删除用户会执行:delete from mysql.user where user='test'; 但是不推荐用户手动修改授权表。连接验证 当客户端发送连接请求时,TiDB 服务器会对登陆操作进行验证。验证过程先检查 mysql.user 表,当某条记录的 User 和 Host 和连接请求匹配上了,再去验证 Password。用户身份基于两部分信息,发起连接的客户端的 Host,以及用户名 User。如果 User不为空,则用户名必须精确匹配。User+Host 可能会匹配 user 表里面多行,为了处理这种情况,user 表的行是排序过的,客户端连接时会依次去匹配,并使用首次匹配到的那一行做权限验证。排序是按 Host 在前,User 在后。请求验证 连接成功之后,请求验证会检测执行操作是否拥有足够的权限。对于数据库相关请求 (INSERT,UPDATE),先检查 mysql.user 表里面的用户全局权限,如果权限够,则直接可以访问。如果全局权限不足,则再检查 mysql.db 表。user 表的权限是全局的,并且不管默认数据库是哪一个。比如 user 里面有 DELETE 权限,任何一行,任何的表,任何的数据库。db表里面,User 为空是匹配匿名用户,User 里面不能有通配符。Host和Db列里面可以有 % 和 _,可以模式匹配。user 和 db 读到内存也是排序的。tables_priv 和 columns_priv 中使用 % 是类似的,但是在Db, Table_name, Column_name 这些列不能包含 %。加载进来时排序也是类似的。生效时机 TiDB 启动时,将一些权限检查的表加载到内存,之后使用缓存的数据来验证权限。系统会周期性的将授权表从数据库同步到缓存,生效则是由同步的周期决定,目前这个值设定的是5分钟。修改了授权表,如果需要立即生效,可以手动调用:flush privileges; 限制和约束 一些使用频率偏低的权限当前版本的实现中还未做检查,比如 FILE/USAGE/SHUTDOWN/EXECUTE/PROCESS/INDEX 等等,未来会陆续完善。现阶段对权限的支持还没有做到 column 级别。Create User 语句 CREATE USER [IF NOT EXISTS] user [auth_spec] [, user [auth_spec]] ... auth_spec: { IDENTIFIED BY 'auth_string' | IDENTIFIED BY PASSWORD 'hash_string' } user 参见用户账号名。 IDENTIFIED BY ‘auth_string’ 设置登录密码,auth_string 将会被 TiDB 经过加密存储在 mysql.user 表中。 IDENTIFIED BY PASSWORD ‘hash_string’ 设置登录密码,hash_string 将会被 TiDB 经过加密存储在 mysql.user 表中。目前这个行为和 MySQL 不一致,会在接下来的版本中修改为和 MySQL 一致的行为。"}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/privilege/", "title": "权限管理", "content": " 权限管理 权限管理概述 TiDB的权限管理系统是按照 MySQL 的权限管理进行实现,大部分的 MySQL 的语法和权限类型都是支持的。如果发现行为跟 MySQL 不一致的地方,欢迎报告 issue。示例 用户账户操作 更改密码 set password for 'root'@'%' = 'xxx'; 添加用户 create user 'test'@'127.0.0.1' identified by 'xxx'; 用户名是大小写敏感的。host则支持模糊匹配,比如:create user 'test'@'192.168.10.%'; 允许 test 用户从 192.168.10 子网的任何一个主机登陆。如果没有指定 host,则默认是所有 IP 均可登陆。如果没有指定密码,默认为空:create user 'test'; 等价于create user 'test'@'%' identified by ''; 删除用户 drop user 'test'@'%'; 这个操作会清除用户在 mysql.user 表里面的记录项,并且清除在授权表里面的相关记录。忘记root密码 使用一个特殊的启动参数启动 TiDB(需要root权限):sudo ./tidb-server -skip-grant-table=true 这个参数启动,TiDB 会跳过权限系统,然后使用 root 登陆以后修改密码:mysql -h 127.0.0.1 -P 4000 -u root 权限相关操作 授予权限 授予 xxx 用户对数据库 test 的读权限:grant Select on test.* to 'xxx'@'%'; 为 test 用户授予所有数据库,全部权限:grant all privileges on *.* to 'xxx'@'%'; 如果 grant 的目标用户不存在,TiDB 会自动创建用户。mysql> select * from mysql.user where user='xxxx'; Empty set (0.00 sec) mysql> grant all privileges on test.* to 'xxxx'@'%' identified by 'yyyyy'; Query OK, 0 rows affected (0.00 sec) mysql> select user,host from mysql.user where user='xxxx'; +------|------+ | user | host | +------|------+ | xxxx | % | +------|------+ 1 row in set (0.00 sec) 例子中 xxxx@% 就是自动添加进去的用户。grant 对于数据库或者表的授权,不检查数据库或表是否存在。mysql> select * from test.xxxx; ERROR 1146 (42S02): Table 'test.xxxx' doesn't exist mysql> grant all privileges on test.xxxx to xxxx; Query OK, 0 rows affected (0.00 sec) mysql> select user,host from mysql.tables_priv where user='xxxx'; +------|------+ | user | host | +------|------+ | xxxx | % | +------|------+ 1 row in set (0.00 sec) grant 可以模糊匹配地授予数据库和表mysql> grant all privileges on `te%`.* to genius; Query OK, 0 rows affected (0.00 sec) mysql> select user,host,db from mysql.db where user='genius'; +--------|------|-----+ | user | host | db | +--------|------|-----+ | genius | % | te% | +--------|------|-----+ 1 row in set (0.00 sec) 这个例子中通过 % 模糊匹配,所有 te 开头的数据库,都被授予了权限。收回权限 revoke语句与grant对应:revoke all privileges on `test`.* from 'genius'@'localhost'; 注意 revoke 收回权限时只做精确匹配,若找不到记录则报错。而 grant 授予权限时可以使用模糊匹配。mysql> revoke all privileges on `te%`.* from 'genius'@'%'; ERROR 1141 (42000): There is no such grant defined for user 'genius' on host '%' 关于模糊匹配和转义,字符串和 identifier> mysql> grant all privileges on `te%`.* to 'genius'@'localhost'; > Query OK, 0 rows affected (0.00 sec) > ``` > > 这个例子是精确匹配名叫 `te%` 的数据库,注意到用了 `` 转义字符。 > > 以单引号包含的,是一个字符串。以反引号包含的,是一个 identifier。注意下面区别: > > ``` > mysql> grant all privileges on 'test'.* to 'genius'@'localhost'; > ERROR 1064 (42000): You have an error in your SQL syntax; check the > manual that corresponds to your MySQL server version for the right > syntax to use near ''test'.* to 'genius'@'localhost'' at line 1 > > mysql> grant all privileges on `test`.* to 'genius'@'localhost'; > Query OK, 0 rows affected (0.00 sec) > ``` > > 如果一些特殊的关键字想做为表名,可以用反引号包含起来。比如: > > ``` > mysql> create table `select` (id int); > Query OK, 0 rows affected (0.27 sec) > ``` #### 查看为用户分配的权限 `SHOW GRANT` 语句可以查看为用户分配了哪些权限。 ```sql show grants for 'root'@'%'; 更精确的方式,可以通过直接查看授权表的数据实现。比如想知道,test@% 该用户是否拥有对 db1.t 的 Insert 权限。先查看该用户是否拥有全局 Insert 权限:select Insert from mysql.user where user='test' and host='%'; 如果没有,再查看该用户是否拥有 db1 数据库级别的 Insert权限:select Insert from mysql.db where user='test' and host='%'; 如果仍然没有,则继续判断是否拥有 db1.t 这张表的 Insert 权限:select tables_priv from mysql.tables_priv where user='test' and host='%' and db='db1'; 权限系统的实现 授权表 有几张系统表是非常特殊的表,权限相关的数据全部存储在这几张表内。 mysql.user 用户账户,全局权限 mysql.db 数据库级别的权限 mysql.tables_priv 表级别的权限 mysql.columns_priv 列级别的权限 这几张表包含了数据的生效范围和权限信息。例如,mysql.user 表的部分数据:mysql> select User,Host,Select_priv,Insert_priv from mysql.user limit 1; +------|------|-------------|-------------+ | User | Host | Select_priv | Insert_priv | +------|------|-------------|-------------+ | root | % | Y | Y | +------|------|-------------|-------------+ 1 row in set (0.00 sec) 这条记录中,Host 和 User 决定了 root 用户从任意主机(%)发送过来的连接请求可以被接受,而 Select_priv 和 Insert_priv 表示用户拥有全局的 Select 和 Insert 权限。mysql.user 这张表里面的生效范围是全局的。mysql.db 表里面包含的 Host 和 User 决定了用户可以访问哪些数据库,权限列的生效范围是数据库。理论上,所有权限管理相关的操作,都可以通过直接对授权表的 CRUD 操作完成。实现层面其实也只是包装了一层语法糖。例如删除用户会执行:delete from mysql.user where user='test'; 但是不推荐用户手动修改授权表。连接验证 当客户端发送连接请求时,TiDB 服务器会对登陆操作进行验证。验证过程先检查 mysql.user 表,当某条记录的 User 和 Host 和连接请求匹配上了,再去验证 Password。用户身份基于两部分信息,发起连接的客户端的 Host,以及用户名 User。如果 User不为空,则用户名必须精确匹配。User+Host 可能会匹配 user 表里面多行,为了处理这种情况,user 表的行是排序过的,客户端连接时会依次去匹配,并使用首次匹配到的那一行做权限验证。排序是按 Host 在前,User 在后。请求验证 连接成功之后,请求验证会检测执行操作是否拥有足够的权限。对于数据库相关请求 (INSERT,UPDATE),先检查 mysql.user 表里面的用户全局权限,如果权限够,则直接可以访问。如果全局权限不足,则再检查 mysql.db 表。user 表的权限是全局的,并且不管默认数据库是哪一个。比如 user 里面有 DELETE 权限,任何一行,任何的表,任何的数据库。db表里面,User 为空是匹配匿名用户,User 里面不能有通配符。Host和Db列里面可以有 % 和 _,可以模式匹配。user 和 db 读到内存也是排序的。tables_priv 和 columns_priv 中使用 % 是类似的,但是在Db, Table_name, Column_name 这些列不能包含 %。加载进来时排序也是类似的。生效时机 TiDB 启动时,将一些权限检查的表加载到内存,之后使用缓存的数据来验证权限。系统会周期性的将授权表从数据库同步到缓存,生效则是由同步的周期决定,目前这个值设定的是5分钟。修改了授权表,如果需要立即生效,可以手动调用:flush privileges; 限制和约束 一些使用频率偏低的权限当前版本的实现中还未做检查,比如 FILE/USAGE/SHUTDOWN/EXECUTE/PROCESS/INDEX 等等,未来会陆续完善。现阶段对权限的支持还没有做到 column 级别。Create User 语句 CREATE USER [IF NOT EXISTS] user [auth_spec] [, user [auth_spec]] ... auth_spec: { IDENTIFIED BY 'auth_string' | IDENTIFIED BY PASSWORD 'hash_string' } user 参见用户账号名。 IDENTIFIED BY ‘auth_string’ 设置登录密码,auth_string 将会被 TiDB 经过加密存储在 mysql.user 表中。 IDENTIFIED BY PASSWORD ‘hash_string’ 设置登录密码,hash_string 将会被 TiDB 经过加密存储在 mysql.user 表中。目前这个行为和 MySQL 不一致,会在接下来的版本中修改为和 MySQL 一致的行为。"}, {"url": "https://pingcap.com/cases-cn/", "title": "案例", "content": ""}, {"url": "https://pingcap.com/docs-cn/sql/comment-syntax/", "title": "注释语法", "content": " 注释语法 TiDB 支持三种注释风格: 用 # 注释一行 用 -- 注释一行,用 -- 注释必须要在其之后留出至少一个空格。 用 /* */ 注释一块,可以注释多行。 例:mysql> SELECT 1+1; # This comment continues to the end of line +------+ | 1+1 | +------+ | 2 | +------+ 1 row in set (0.00 sec) mysql> SELECT 1+1; -- This comment continues to the end of line +------+ | 1+1 | +------+ | 2 | +------+ 1 row in set (0.00 sec) mysql> SELECT 1 /* this is an in-line comment */ + 1; +--------+ | 1 + 1 | +--------+ | 2 | +--------+ 1 row in set (0.01 sec) mysql> SELECT 1+ -> /* /*> this is a /*> multiple-line comment /*> */ -> 1; +-------+ | 1+ 1 | +-------+ | 2 | +-------+ 1 row in set (0.00 sec) mysql> SELECT 1+1--1; +--------+ | 1+1--1 | +--------+ | 3 | +--------+ 1 row in set (0.01 sec) TiDB 也跟 MySQL 保持一致,支持一种 C 风格注释的变体:/*! Specific code */ 在这种格式中,TiDB 会执行注释中的语句,这个语法是为了让这些 SQL 在其他的数据库中被忽略,而在 TiDB 中被执行。例如: SELECT /*! STRAIGHT_JOIN */ col1 FROM table1,table2 WHERE ...在 TiDB 中,这种写法等价于 SELECT STRAIGHT_JOIN col1 FROM table1,table2 WHERE ...如果注释中指定了 Server 版本号,例如 /*!50110 KEY_BLOCK_SIZE=1024 */,在 MySQL 中表示只有 MySQL 的版本大于等于 5.1.10 才会处理这个 comment 中的内容。但是在 TiDB 中,这个版本号不会起作用,所有的 comment 都会处理。还有一种注释会被当做是优化器 Hint 特殊对待:SELECT /*+ hint */ FROM ...; 由于 hint 包含在类似 /*+ xxx */ 的 comment 里,MySQL 客户端在 5.7.7 之前,会默认把 comment 清除掉,如果需要在旧的客户端使用 hint,需要在启动客户端时加上 –comments 选项,例如 mysql -h 127.0.0.1 -P 4000 -uroot –commentsTiDB 支持的相关优化器 hint 详见这里更多细节。"}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/comment-syntax/", "title": "注释语法", "content": " 注释语法 TiDB 支持三种注释风格: 用 # 注释一行 用 -- 注释一行,用 -- 注释必须要在其之后留出至少一个空格。 用 /* */ 注释一块,可以注释多行。 例:mysql> SELECT 1+1; # This comment continues to the end of line +------+ | 1+1 | +------+ | 2 | +------+ 1 row in set (0.00 sec) mysql> SELECT 1+1; -- This comment continues to the end of line +------+ | 1+1 | +------+ | 2 | +------+ 1 row in set (0.00 sec) mysql> SELECT 1 /* this is an in-line comment */ + 1; +--------+ | 1 + 1 | +--------+ | 2 | +--------+ 1 row in set (0.01 sec) mysql> SELECT 1+ -> /* /*> this is a /*> multiple-line comment /*> */ -> 1; +-------+ | 1+ 1 | +-------+ | 2 | +-------+ 1 row in set (0.00 sec) mysql> SELECT 1+1--1; +--------+ | 1+1--1 | +--------+ | 3 | +--------+ 1 row in set (0.01 sec) TiDB 也跟 MySQL 保持一致,支持一种 C 风格注释的变体:/*! Specific code */ 在这种格式中,TiDB 会执行注释中的语句,这个语法是为了让这些 SQL 在其他的数据库中被忽略,而在 TiDB 中被执行。例如: SELECT /*! STRAIGHT_JOIN */ col1 FROM table1,table2 WHERE ...在 TiDB 中,这种写法等价于 SELECT STRAIGHT_JOIN col1 FROM table1,table2 WHERE ...如果注释中指定了 Server 版本号,例如 /*!50110 KEY_BLOCK_SIZE=1024 */,在 MySQL 中表示只有 MySQL 的版本大于等于 5.1.10 才会处理这个 comment 中的内容。但是在 TiDB 中,这个版本号不会起作用,所有的 comment 都会处理。还有一种注释会被当做是优化器 Hint 特殊对待:SELECT /*+ hint */ FROM ...; 由于 hint 包含在类似 /*+ xxx */ 的 comment 里,MySQL 客户端在 5.7.7 之前,会默认把 comment 清除掉,如果需要在旧的客户端使用 hint,需要在启动客户端时加上 –comments 选项,例如 mysql -h 127.0.0.1 -P 4000 -uroot –comments目前支持的 TiDB 特有的 Hint 有以下: TIDB_SMJ(t1, t2)SELECT /*+ TIDB_SMJ(t1, t2) */ * from t1,t2 where t1.id = t2.id提示优化器使用 Sort Merge Join 算法,这个算法通常会占用更少的内存,但执行时间会更久。当数据量太大,或系统内存不足时,建议尝试使用。 TIDB_INLJ(t1, t2)SELECT /*+ TIDB_INLJ(t1, t2) */ * from t1,t2 where t1.id = t2.id提示优化器使用 Index Nested Loop Join 算法,这个算法可能会在某些场景更快,消耗更少系统资源,有的场景会更慢,消耗更多系统资源。对于外表经过 WHERE 条件过滤后结果集较小(小于 1 万行)的场景,可以尝试使用。TIDB_INLJ() 中的参数是建立查询计划时,驱动表(外表)的候选表。即 TIDB_INLJ(t1) 只会考虑使用 t1 作为驱动表构建查询计划。 更多细节。"}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/comment-syntax/", "title": "注释语法", "content": " 注释语法 TiDB 支持三种注释风格: 用 # 注释一行 用 -- 注释一行,用 -- 注释必须要在其之后留出至少一个空格。 用 /* */ 注释一块,可以注释多行。 例:mysql> SELECT 1+1; # This comment continues to the end of line +------+ | 1+1 | +------+ | 2 | +------+ 1 row in set (0.00 sec) mysql> SELECT 1+1; -- This comment continues to the end of line +------+ | 1+1 | +------+ | 2 | +------+ 1 row in set (0.00 sec) mysql> SELECT 1 /* this is an in-line comment */ + 1; +--------+ | 1 + 1 | +--------+ | 2 | +--------+ 1 row in set (0.01 sec) mysql> SELECT 1+ -> /* /*> this is a /*> multiple-line comment /*> */ -> 1; +-------+ | 1+ 1 | +-------+ | 2 | +-------+ 1 row in set (0.00 sec) mysql> SELECT 1+1--1; +--------+ | 1+1--1 | +--------+ | 3 | +--------+ 1 row in set (0.01 sec) TiDB 也跟 MySQL 保持一致,支持一种 C 风格注释的变体:/*! Specific code */ 在这种格式中,TiDB 会执行注释中的语句,这个语法是为了让这些 SQL 在其他的数据库中被忽略,而在 TiDB 中被执行。例如: SELECT /*! STRAIGHT_JOIN */ col1 FROM table1,table2 WHERE ...在 TiDB 中,这种写法等价于 SELECT STRAIGHT_JOIN col1 FROM table1,table2 WHERE ...如果注释中指定了 Server 版本号,例如 /*!50110 KEY_BLOCK_SIZE=1024 */,在 MySQL 中表示只有 MySQL 的版本大于等于 5.1.10 才会处理这个 comment 中的内容。但是在 TiDB 中,这个版本号不会起作用,所有的 comment 都会处理。还有一种注释会被当做是优化器 Hint 特殊对待:SELECT /*+ hint */ FROM ...; 由于 hint 包含在类似 /*+ xxx */ 的 comment 里,MySQL 客户端在 5.7.7 之前,会默认把 comment 清除掉,如果需要在旧的客户端使用 hint,需要在启动客户端时加上 –comments 选项,例如 mysql -h 127.0.0.1 -P 4000 -uroot –comments目前支持的 TiDB 特有的 Hint 有以下: TIDB_SMJ(t1, t2)SELECT /*+ TIDB_SMJ(t1, t2) */ * from t1,t2 where t1.id = t2.id提示优化器使用 Sort Merge Join 算法,这个算法通常会占用更少的内存,但执行时间会更久。当数据量太大,或系统内存不足时,建议尝试使用。 TIDB_INLJ(t1, t2)SELECT /*+ TIDB_INLJ(t1, t2) */ * from t1,t2 where t1.id = t2.id提示优化器使用 Index Nested Loop Join 算法,这个算法可能会在某些场景更快,消耗更少系统资源,有的场景会更慢,消耗更多系统资源。对于外表经过 WHERE 条件过滤后结果集较小(小于 1 万行)的场景,可以尝试使用。TIDB_INLJ() 中的参数是建立查询计划时,驱动表(外表)的候选表。即 TIDB_INLJ(t1) 只会考虑使用 t1 作为驱动表构建查询计划。 更多细节。"}, {"url": "https://pingcap.com/docs-cn/sql/understanding-the-query-execution-plan/", "title": "理解 TiDB 执行计划", "content": " 理解 TiDB 执行计划 TiDB 优化器会根据当前数据表的实际情况来选择最优的执行计划,执行计划由一系列的算子构成。本文将详细解释 TiDB 中 EXPLAIN 语句返回的执行计划信息。使用 EXPLAIN 来优化 SQL 语句 EXPLAIN 语句的返回结果提供了 TiDB 执行 SQL 查询的详细信息: EXPLAIN 可以和 SELECT,DELETE 语句一起使用; 执行 EXPLAIN,TiDB 会返回被 EXPLAIN 的 SQL 语句经过优化器后的最终物理执行计划。也就是说,EXPLAIN 展示了 TiDB 执行该 SQL 语句的完整信息,比如以什么样的顺序,什么方式 JOIN 两个表,表达式树长什么样等等。详见 EXPLAIN 输出格式; TiDB 目前还不支持 EXPLAIN [options] FOR CONNECTION connection_id,将在未来支持它,详见 #4351; 通过观察 EXPLAIN 的结果,你可以知道如何给数据表添加索引使得执行计划使用索引从而加速 SQL 语句的执行速度;你也可以使用 EXPLAIN 来检查优化器是否选择了最优的顺序来 JOIN 数据表。EXPLAIN 输出格式 目前 TiDB 的 EXPLAIN 会输出 4 列,分别是:id,count,task,operator info。执行计划中每个算子都由这 4 列属性来描述,EXPLAIN 结果中每一行描述一个算子。每个属性的具体含义如下: 属性名 含义 id 算子的 ID,在整个执行计划中唯一的标识一个算子。在 TiDB 2.1 中,id 会格式化显示算子的树状结构。数据从 child 流向 parent,每个 算子的 parent 有且仅有一个。 count 预计当前算子将会输出的数据条数,基于统计信息以及算子的执行逻辑估算而来。 task 当前这个算子属于什么 task。目前的执行计划分成为两种 task,一种叫 root task,在 tidb-server 上执行,一种叫 cop task,并行的在 TiKV 上执行。当前的执行计划在 task 级别的拓扑关系是一个 root task 后面可以跟许多 cop task,root task 使用 cop task 的输出结果作为输入。cop task 中执行的也即是 TiDB 下推到 TiKV 上的任务,每个 cop task 分散在 TiKV 集群中,由多个进程共同执行。 operator info 每个算子的详细信息。各个算子的 operator info 各有不同,详见 Operator Info。 EXPLAIN ANALYZE 输出格式 作为 EXPLAIN 语句的扩展,EXPLAIN ANALYZE 语句执行查询并在 execution info 列中提供额外的执行统计信息。具体如下: time 显示从进入算子到离开算子的全部 wall time,包括所有子算子操作的全部执行时间。如果该算子被父算子多次调用 (loops),这个时间就是累积的时间。 loops 是当前算子被父算子的调用次数。 rows 是当前算子返回的行的总数。例如,可以将 count 列的精度和 execution_info 列中的 rows/loops 值进行对比,据此评定查询优化器估算的精确度。 用例 使用 bikeshare example database:mysql> EXPLAIN SELECT count(*) FROM trips WHERE start_date BETWEEN '2017-07-01 00:00:00' AND '2017-07-01 23:59:59'; +--------------------------+-------------+------+------------------------------------------------------------------------------------------------------------------------+ | id | count | task | operator info | +--------------------------+-------------+------+------------------------------------------------------------------------------------------------------------------------+ | StreamAgg_20 | 1.00 | root | funcs:count(col_0) | | └─TableReader_21 | 1.00 | root | data:StreamAgg_9 | | └─StreamAgg_9 | 1.00 | cop | funcs:count(1) | | └─Selection_19 | 8166.73 | cop | ge(bikeshare.trips.start_date, 2017-07-01 00:00:00.000000), le(bikeshare.trips.start_date, 2017-07-01 23:59:59.000000) | | └─TableScan_18 | 19117643.00 | cop | table:trips, range:[-inf,+inf], keep order:false | +--------------------------+-------------+------+------------------------------------------------------------------------------------------------------------------------+ 5 rows in set (0.00 sec) 在上面的例子中,coprocessor 上读取 trips 表上的数据(TableScan_18),寻找满足 start_date BETWEEN '2017-07-01 00:00:00' AND '2017-07-01 23:59:59' 条件的数据(Selection_19),然后计算满足条件的数据行数(StreamAgg_9),最后把结果返回给 TiDB。TiDB 汇总各个 coprocessor 返回的结果(TableReader_21),并进一步计算所有数据的行数(StreamAgg_20),最终把结果返回给客户端。在上面这个查询中,TiDB 根据 trips 表的统计信息估算出 TableScan_18 的输出结果行数为 19117643.00,满足条件 start_date BETWEEN '2017-07-01 00:00:00' AND '2017-07-01 23:59:59' 的有 8166.73 条,经过聚合运算后,只有 1 条结果。上述查询中,虽然大部分计算逻辑都下推到了 TiKV 的 coprocessor 上,但是其执行效率还是不够高,可以添加适当的索引来消除 TableScan_18 对 trips 的全表扫,进一步加速查询的执行:mysql> ALTER TABLE trips ADD INDEX (start_date); .. mysql> EXPLAIN SELECT count(*) FROM trips WHERE start_date BETWEEN '2017-07-01 00:00:00' AND '2017-07-01 23:59:59'; +------------------------+---------+------+--------------------------------------------------------------------------------------------------+ | id | count | task | operator info | +------------------------+---------+------+--------------------------------------------------------------------------------------------------+ | StreamAgg_25 | 1.00 | root | funcs:count(col_0) | | └─IndexReader_26 | 1.00 | root | index:StreamAgg_9 | | └─StreamAgg_9 | 1.00 | cop | funcs:count(1) | | └─IndexScan_24 | 8166.73 | cop | table:trips, index:start_date, range:[2017-07-01 00:00:00,2017-07-01 23:59:59], keep order:false | +------------------------+---------+------+--------------------------------------------------------------------------------------------------+ 4 rows in set (0.01 sec) 在添加完索引后的新执行计划中,使用 IndexScan_24 直接读取满足条件 start_date BETWEEN '2017-07-01 00:00:00' AND '2017-07-01 23:59:59' 的数据,可以看到,估算的要扫描的数据行数从之前的 19117643.00 降到了现在的 8166.73。在测试环境中显示,这个查询的执行时间从 50.41 秒降到了 0.00 秒!概述 Task 简介 目前 TiDB 的计算任务隶属于两种不同的 task:cop task 和 root task。cop task 是指被下推到 KV 端分布式执行的计算任务,root task 是指在 TiDB 端单点执行的计算任务。SQL 优化的目标之一是将计算尽可能的下推到 KV 端执行。表数据和索引数据 TiDB 的表数据是指一张表的原始数据,存放在 TiKV 中。对于每行表数据,它的 key 是一个 64 位整数,称为 Handle ID。如果一张表存在 int 类型的主键,TiDB 会把主键的值当作表数据的 Handle ID,否则由系统自动生成 Handle ID。表数据的 value 由这一行的所有数据编码而成。在读取表数据的时候,可以按照 Handle ID 递增的顺序返回。TiDB 的索引数据和表数据一样,也存放在 TiKV 中。它的 key 是由索引列编码的有序 bytes,value 是这一行索引数据对应的 Handle ID,通过 Handle ID 可以读取这一行的非索引列。在读取索引数据的时候,TiKV 会按照索引列递增的顺序返回,如果有多个索引列,首先保证第 1 列递增,并且在第 i 列相等的情况下,保证第 i + 1 列递增。范围查询 在 WHERE/HAVING/ON 条件中,TiDB 优化器会分析主键或索引键的查询返回。如数字、日期类型的比较符,如大于、小于、等于以及大于等于、小于等于,字符类型的 LIKE 符号等。 值得注意的是,TiDB 目前只支持比较符一端是列,另一端是常量,或可以计算成某一常量的情况,类似 year(birth_day) < 1992 的查询条件是不能利用索引的。还要注意应尽可能使用同一类型进行比较,以避免引入额外的 cast 操作而导致不能利用索引,如 user_id = 123456,如果 user_id 是字符串,需要将 123456 也写成字符串常量的形式。 针对同一列的范围查询条件使用 AND 和 OR 组合后,等于对范围求交集或者并集。对于多维组合索引,可以写多个列的条件。例如对组合索引(a, b, c),当 a 为等值查询时,可以继续求 b 的查询范围,当 b 也为等值查询时,可以继续求 c 的查询范围,反之如果 a 为非等值查询,则只能求 a 的范围。Operator Info TableReader 和 TableScan TableScan 表示在 KV 端对表数据进行扫描,TableReader 表示在 TiDB 端从 TiKV 端读取,属于同一功能的两个算子。table 表示 SQL 语句中的表名,如果表名被重命名,则显示重命名。range 表示扫描的数据范围,如果在查询中不指定 WHERE/HAVING/ON 条件,则会选择全表扫描,如果在 int 类型的主键上有范围查询条件,会选择范围查询。keep order 表示 table scan 是否按顺序返回。IndexReader 和 IndexLookUp Index 在 TiDB 端的读取方式有两种:IndexReader 表示直接从索引中读取索引列,适用于 SQL 语句中仅引用了该索引相关的列或主键;IndexLookUp 表示从索引中过滤部分数据,仅返回这些数据的 Handle ID,通过 Handle ID 再次查找表数据,这种方式需要两次从 TiKV 获取数据。Index 的读取方式是由优化器自动选择的。IndexScan 是 KV 端读取索引数据的算子,和 TableScan 功能类似。table 表示 SQL 语句中的表名,如果表名被重命名,则显示重命名。index 表示索引名。range 表示扫描的数据范围。out of order 表示 index scan 是否按照顺序返回。注意在 TiDB 中,多列或者非 int 列构成的主键是当作唯一索引处理的。Selection Selection 表示 SQL 语句中的选择条件,通常出现在 WHERE/HAVING/ON 子句中。Projection Projection 对应 SQL 语句中的 SELECT 列表,功能是将每一条输入数据映射成新的输出数据。Aggregation Aggregation 对应 SQL 语句中的 Group By 语句或者没有 Group By 语句但是存在聚合函数,例如 count 或 sum 函数等。TiDB 支持两种聚合算法:Hash Aggregation 以及 Stream Aggregation(待补充)。Hash Aggregation 是基于哈希的聚合算法,如果 Hash Aggregation 紧邻 Table 或者 Index 的读取算子,则聚合算子会在 TiKV 端进行预聚合,以提高计算的并行度和减少网络开销。Join TiDB 支持 Inner Join 以及 Left/Right Outer Join,并会自动将可以化简的外连接转换为 Inner Join。TiDB 支持三种 Join 算法:Hash Join,Sort Merge Join 和 Index Look up Join。Hash Join 的原理是将参与连接的小表预先装载到内存中,读取大表的所有数据进行连接。Sort Merge Join 会利用输入数据的有序信息,同时读取两张表的数据并依次进行比较。Index Look Up Join 会读取外表的数据,并对内表进行主键或索引键查询。Apply Apply 是 TiDB 用来描述子查询的一种算子,行为类似于 Nested Loop,即每次从外表中取一条数据,带入到内表的关联列中,并执行,最后根据 Apply 内联的 Join 算法进行连接计算。值得注意的是,Apply 一般会被查询优化器自动转换为 Join 操作。用户在编写 SQL 的过程中应尽量避免 Apply 算子的出现。"}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/understanding-the-query-execution-plan/", "title": "理解 TiDB 执行计划", "content": " 理解 TiDB 执行计划 TiDB 优化器会根据当前数据表的实际情况来选择最优的执行计划,执行计划由一系列的 operator 构成,这里我们详细解释一下 TiDB 中 EXPLAIN 语句返回的执行计划信息。使用 EXPLAIN 来优化 SQL 语句 EXPLAIN 语句的返回结果提供了 TiDB 执行 SQL 查询的详细信息: EXPLAIN 可以和 SELECT, DELETE, INSERT, REPLACE, 以及 UPDATE 语句一起使用; 执行 EXPLAIN,TiDB 会返回被 EXPLAIN 的 SQL 语句经过优化器后的最终物理执行计划。也就是说,EXPLAIN 展示了 TiDB 执行该 SQL 语句的完整信息,比如以什么样的顺序,什么方式 JOIN 两个表,表达式树长什么样等等。详细请看 EXPLAIN 输出格式; TiDB 目前还不支持 EXPLAIN [options] FOR CONNECTION connection_id,我们将在未来支持它,详细请看:#4351; 通过观察 EXPLAIN 的结果,你可以知道如何给数据表添加索引使得执行计划使用索引从而加速 SQL 语句的执行速度;你也可以使用 EXPLAIN 来检查优化器是否选择了最优的顺序来 JOIN 数据表。EXPLAIN 输出格式 目前 TiDB 的 EXPLAIN 会输出 6 列,分别是:id,parents,children,task,operator info 和 count,执行计划中每个 operator 都由这 6 列属性来描述,EXPLAIN 结果中每一行描述一个 operator。下面详细解释每个属性的含义: 属性名 含义 id operator 的 id,在整个执行计划中唯一的标识一个 operator parents 这个 operator 的 parent。目前的执行计划可以看做是一个 operator 构成的树状结构,数据从 child 流向 parent,每个 operator 的 parent 有且仅有一个 children 这个 operator 的 children,也即是这个 operator 的数据来源 task 当前这个 operator 属于什么 task。目前的执行计划分成为两种 task,一种叫 root task,在 tidb-server 上执行,一种叫 cop task,并行的在 tikv 上执行。当前的执行计划在 task 级别的拓扑关系是一个 root task 后面可以跟许多 cop task,root task 使用 cop task 的输出结果作为输入。cop task 中执行的也即是 tidb 下推到 tikv 上的任务,每个 cop task 分散在 tikv 集群中,由多个进程共同执行 operator info 每个 operator 的详细信息。各个 operator 的 operator info 各有不同,我们将在 Operator Info 中详细介绍 count 预计当前 operator 将会输出的数据条数,基于统计信息以及 operator 的执行逻辑估算而来 概述 Task 简介 目前 TiDB 的计算任务隶属于两种不同的 task: cop task 和 root task。cop task 是指被下推到 KV 端分布式执行的计算任务,root task 是指在 TiDB 端单点执行的计算任务。SQL 优化的目标之一是将计算尽可能的下推到 KV 端执行。表数据和索引数据 TiDB 的表数据是指一张表的原始数据,存放在 TiKV 中。对于每行表数据,它的 key 是一个 64 位整数,称为 Handle ID。如果一张表存在 int 类型的主键,我们会把主键的值当作表数据的 Handle ID,否则由系统自动生成 Handle ID。表数据的 value 由这一行的所有数据编码而成。在读取表数据的时候,我们可以按照 Handle ID 递增的顺序返回。TiDB 的索引数据和表数据一样,也存放在 TiKV 中。它的 key 是由索引列编码的有序 bytes,value 是这一行索引数据对应的 Handle ID,通过 Handle ID 我们可以读取这一行的非索引列。在读取索引数据的时候,我们按照索引列递增的顺序返回,如果有多个索引列,我们首先保证第 1 列递增,并且在第 i 列相等的情况下,保证第 i + 1 列递增。范围查询 在 WHERE/HAVING/ON 条件中,我们会分析主键或索引键的查询返回。如数字、日期类型的比较符,如大于、小于、等于以及大于等于、小于等于,字符类型的 LIKE 符号等。 值得注意的是,我们只支持比较符一端是列,另一端是常量,或可以计算成某一常量的情况,类似 year(birth_day) < 1992 的查询条件是不能利用索引的。还要注意应尽可能使用同一类型进行比较,以避免引入额外的 cast 操作而导致不能利用索引,如 user_id = 123456,如果 user_id 是字符串,需要将 123456 也写成字符串常量的形式。 针对同一列的范围查询条件使用 AND 和 OR 组合后,等于对范围求交集或者并集。对于多维组合索引,我们可以写多个列的条件。例如对组合索引(a, b, c),当 a 为等值查询时,可以继续求 b 的查询范围,当 b 也为等值查询时,可以继续求 c 的查询范围,反之如果 a 为非等值查询,则只能求 a 的范围。Operator Info TableReader 和 TableScan TableScan 表示在 KV 端对表数据进行扫描,TableReader 表示在 TiDB 端从 TiKV 端读取,属于同一功能的两个算子。table 表示 SQL 语句中的表名,如果表名被重命名,则显示重命名。range 表示扫描的数据范围,如果在查询中不指定 WHERE/HAVING/ON 条件,则会选择全表扫描,如果在 int 类型的主键上有范围查询条件,会选择范围查询。keep order 表示 table scan 是否按顺序返回。IndexReader 和 IndexLookUp Index 在 TiDB 端的读取方式有两种:IndexReader 表示直接从索引中读取索引列,适用于 SQL 语句中仅引用了该索引相关的列或主键;IndexLookUp 表示从索引中过滤部分数据,仅返回这些数据的 Handle ID,通过 Handle ID 再次查找表数据,这种方式需要两次从 TiKV 获取数据。Index 的读取方式是由优化器自动选择的。IndexScan 是 KV 端读取索引数据的算子,和 TableScan 功能类似。table 表示 SQL 语句中的表名,如果表名被重命名,则显示重命名。index 表示索引名。range 表示扫描的数据范围。out of order 表示 index scan 是否按照顺序返回。注意在 TiDB 中,多列或者非 int 列构成的主键是当作唯一索引处理的。Selection Selection 表示 SQL 语句中的选择条件,通常出现在 WHERE/HAVING/ON 子句中。Projection Projection 对应 SQL 语句中的 SELECT 列表,功能是将每一条输入数据映射成新的输出数据。Aggregation Aggregation 对应 SQL 语句中的 Group By 语句或者没有 Group By 语句但是存在聚合函数,例如 count 或 sum 函数等。TiDB 支持两种聚合算法:Hash Aggregation 以及 Stream Aggregation(待补充)。Hash Aggregation 是基于哈希的聚合算法,如果 Hash Aggregation 紧邻 Table 或者 Index 的读取算子,则聚合算子会在 TiKV 端进行预聚合,以提高计算的并行度和减少网络开销。Join TiDB 支持 Inner Join 以及 Left/Right Outer Join,并会自动将可以化简的外连接转换为 Inner Join。TiDB 支持三种 Join 算法:Hash Join,Sort Merge Join 和 Index Look up Join。Hash Join 的原理是将参与连接的小表预先装载到内存中,读取大表的所有数据进行连接。Sort Merge Join 会利用输入数据的有序信息,同时读取两张表的数据并依次进行比较。Index Look Up Join 会读取外表的数据,并对内表进行主键或索引键查询。Apply Apply 是 TiDB 用来描述子查询的一种算子,行为类似于 Nested Loop,即每次从外表中取一条数据,带入到内表的关联列中,并执行,最后根据 Apply 内联的 Join 算法进行连接计算。值得注意的是,Apply 一般会被查询优化器自动转换为 Join 操作。用户在编写 SQL 的过程中应尽量避免 Apply 算子的出现。"}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/understanding-the-query-execution-plan/", "title": "理解 TiDB 执行计划", "content": " 理解 TiDB 执行计划 TiDB 优化器会根据当前数据表的实际情况来选择最优的执行计划,执行计划由一系列的 operator 构成,这里我们详细解释一下 TiDB 中 EXPLAIN 语句返回的执行计划信息。使用 EXPLAIN 来优化 SQL 语句 EXPLAIN 语句的返回结果提供了 TiDB 执行 SQL 查询的详细信息: EXPLAIN 可以和 SELECT, DELETE, INSERT, REPLACE, 以及 UPDATE 语句一起使用; 执行 EXPLAIN,TiDB 会返回被 EXPLAIN 的 SQL 语句经过优化器后的最终物理执行计划。也就是说,EXPLAIN 展示了 TiDB 执行该 SQL 语句的完整信息,比如以什么样的顺序,什么方式 JOIN 两个表,表达式树长什么样等等。详细请看 EXPLAIN 输出格式; TiDB 目前还不支持 EXPLAIN [options] FOR CONNECTION connection_id,我们将在未来支持它,详细请看:#4351; 通过观察 EXPLAIN 的结果,你可以知道如何给数据表添加索引使得执行计划使用索引从而加速 SQL 语句的执行速度;你也可以使用 EXPLAIN 来检查优化器是否选择了最优的顺序来 JOIN 数据表。EXPLAIN 输出格式 目前 TiDB 的 EXPLAIN 会输出 6 列,分别是:id,parents,children,task,operator info 和 count,执行计划中每个 operator 都由这 6 列属性来描述,EXPLAIN 结果中每一行描述一个 operator。下面详细解释每个属性的含义: 属性名 含义 id operator 的 id,在整个执行计划中唯一的标识一个 operator parents 这个 operator 的 parent。目前的执行计划可以看做是一个 operator 构成的树状结构,数据从 child 流向 parent,每个 operator 的 parent 有且仅有一个 children 这个 operator 的 children,也即是这个 operator 的数据来源 task 当前这个 operator 属于什么 task。目前的执行计划分成为两种 task,一种叫 root task,在 tidb-server 上执行,一种叫 cop task,并行的在 tikv 上执行。当前的执行计划在 task 级别的拓扑关系是一个 root task 后面可以跟许多 cop task,root task 使用 cop task 的输出结果作为输入。cop task 中执行的也即是 tidb 下推到 tikv 上的任务,每个 cop task 分散在 tikv 集群中,由多个进程共同执行 operator info 每个 operator 的详细信息。各个 operator 的 operator info 各有不同,我们将在 Operator Info 中详细介绍 count 预计当前 operator 将会输出的数据条数,基于统计信息以及 operator 的执行逻辑估算而来 概述 Task 简介 目前 TiDB 的计算任务隶属于两种不同的 task: cop task 和 root task。cop task 是指被下推到 KV 端分布式执行的计算任务,root task 是指在 TiDB 端单点执行的计算任务。SQL 优化的目标之一是将计算尽可能的下推到 KV 端执行。表数据和索引数据 TiDB 的表数据是指一张表的原始数据,存放在 TiKV 中。对于每行表数据,它的 key 是一个 64 位整数,称为 Handle ID。如果一张表存在 int 类型的主键,我们会把主键的值当作表数据的 Handle ID,否则由系统自动生成 Handle ID。表数据的 value 由这一行的所有数据编码而成。在读取表数据的时候,我们可以按照 Handle ID 递增的顺序返回。TiDB 的索引数据和表数据一样,也存放在 TiKV 中。它的 key 是由索引列编码的有序 bytes,value 是这一行索引数据对应的 Handle ID,通过 Handle ID 我们可以读取这一行的非索引列。在读取索引数据的时候,我们按照索引列递增的顺序返回,如果有多个索引列,我们首先保证第 1 列递增,并且在第 i 列相等的情况下,保证第 i + 1 列递增。范围查询 在 WHERE/HAVING/ON 条件中,我们会分析主键或索引键的查询返回。如数字、日期类型的比较符,如大于、小于、等于以及大于等于、小于等于,字符类型的 LIKE 符号等。 值得注意的是,我们只支持比较符一端是列,另一端是常量,或可以计算成某一常量的情况,类似 year(birth_day) < 1992 的查询条件是不能利用索引的。还要注意应尽可能使用同一类型进行比较,以避免引入额外的 cast 操作而导致不能利用索引,如 user_id = 123456,如果 user_id 是字符串,需要将 123456 也写成字符串常量的形式。 针对同一列的范围查询条件使用 AND 和 OR 组合后,等于对范围求交集或者并集。对于多维组合索引,我们可以写多个列的条件。例如对组合索引(a, b, c),当 a 为等值查询时,可以继续求 b 的查询范围,当 b 也为等值查询时,可以继续求 c 的查询范围,反之如果 a 为非等值查询,则只能求 a 的范围。Operator Info TableReader 和 TableScan TableScan 表示在 KV 端对表数据进行扫描,TableReader 表示在 TiDB 端从 TiKV 端读取,属于同一功能的两个算子。table 表示 SQL 语句中的表名,如果表名被重命名,则显示重命名。range 表示扫描的数据范围,如果在查询中不指定 WHERE/HAVING/ON 条件,则会选择全表扫描,如果在 int 类型的主键上有范围查询条件,会选择范围查询。keep order 表示 table scan 是否按顺序返回。IndexReader 和 IndexLookUp Index 在 TiDB 端的读取方式有两种:IndexReader 表示直接从索引中读取索引列,适用于 SQL 语句中仅引用了该索引相关的列或主键;IndexLookUp 表示从索引中过滤部分数据,仅返回这些数据的 Handle ID,通过 Handle ID 再次查找表数据,这种方式需要两次从 TiKV 获取数据。Index 的读取方式是由优化器自动选择的。IndexScan 是 KV 端读取索引数据的算子,和 TableScan 功能类似。table 表示 SQL 语句中的表名,如果表名被重命名,则显示重命名。index 表示索引名。range 表示扫描的数据范围。out of order 表示 index scan 是否按照顺序返回。注意在 TiDB 中,多列或者非 int 列构成的主键是当作唯一索引处理的。Selection Selection 表示 SQL 语句中的选择条件,通常出现在 WHERE/HAVING/ON 子句中。Projection Projection 对应 SQL 语句中的 SELECT 列表,功能是将每一条输入数据映射成新的输出数据。Aggregation Aggregation 对应 SQL 语句中的 Group By 语句或者没有 Group By 语句但是存在聚合函数,例如 count 或 sum 函数等。TiDB 支持两种聚合算法:Hash Aggregation 以及 Stream Aggregation(待补充)。Hash Aggregation 是基于哈希的聚合算法,如果 Hash Aggregation 紧邻 Table 或者 Index 的读取算子,则聚合算子会在 TiKV 端进行预聚合,以提高计算的并行度和减少网络开销。Join TiDB 支持 Inner Join 以及 Left/Right Outer Join,并会自动将可以化简的外连接转换为 Inner Join。TiDB 支持三种 Join 算法:Hash Join,Sort Merge Join 和 Index Look up Join。Hash Join 的原理是将参与连接的小表预先装载到内存中,读取大表的所有数据进行连接。Sort Merge Join 会利用输入数据的有序信息,同时读取两张表的数据并依次进行比较。Index Look Up Join 会读取外表的数据,并对内表进行主键或索引键查询。Apply Apply 是 TiDB 用来描述子查询的一种算子,行为类似于 Nested Loop,即每次从外表中取一条数据,带入到内表的关联列中,并执行,最后根据 Apply 内联的 Join 算法进行连接计算。值得注意的是,Apply 一般会被查询优化器自动转换为 Join 操作。用户在编写 SQL 的过程中应尽量避免 Apply 算子的出现。"}, {"url": "https://pingcap.com/docs-cn/op-guide/generate-self-signed-certificates/", "title": "生成自签名证书", "content": " 生成自签名证书 概述 本文档提供使用 cfssl 生成自签名证书的示例。假设实例集群拓扑如下: Name Host IP Services node1 172.16.10.1 PD1, TiDB1 node2 172.16.10.2 PD2, TiDB2 node3 172.16.10.3 PD3 node4 172.16.10.4 TiKV1 node5 172.16.10.5 TiKV2 node6 172.16.10.6 TiKV3 下载 cfssl 假设使用 x86_64 Linux 主机:mkdir ~/bin curl -s -L -o ~/bin/cfssl https://pkg.cfssl.org/R1.2/cfssl_linux-amd64 curl -s -L -o ~/bin/cfssljson https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64 chmod +x ~/bin/{cfssl,cfssljson} export PATH=$PATH:~/bin 初始化证书颁发机构 生成 cfssl 的默认配置,以便于之后修改:mkdir ~/cfssl cd ~/cfssl cfssl print-defaults config > ca-config.json cfssl print-defaults csr > ca-csr.json 生成证书 证书介绍 tidb-server certificate 由 TiDB 使用,为其他组件和客户端验证 TiDB 身份。 tikv-server certificate 由 TiKV 使用,为其他组件和客户端验证 TiKV 身份。 pd-server certificate 由 PD 使用,为其他组件和客户端验证 PD 身份。 client certificate 用于通过 PD、TiKV、TiDB 验证客户端。例如 pd-ctl,tikv-ctl,pd-recover。 配置 CA 选项 根据实际需求修改 ca-config.json:{ "signing": { "default": { "expiry": "43800h" }, "profiles": { "server": { "expiry": "43800h", "usages": [ "signing", "key encipherment", "server auth", "client auth" ] }, "client": { "expiry": "43800h", "usages": [ "signing", "key encipherment", "client auth" ] } } } } 根据实际需求修改 ca-csr.json :{ "CN": "My own CA", "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "CN", "L": "Beijing", "O": "PingCAP", "ST": "Beijing" } ] } 生成 CA 证书 cfssl gencert -initca ca-csr.json | cfssljson -bare ca - 将会生成以下几个文件:ca-key.pem ca.csr ca.pem 生成服务器端证书 hostname 中为各组件的 IP 地址,以及 127.0.0.1echo '{"CN":"tidb-server","hosts":[""],"key":{"algo":"rsa","size":2048}}' | cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=server -hostname="172.16.10.1,172.16.10.2,127.0.0.1" - | cfssljson -bare tidb-server echo '{"CN":"tikv-server","hosts":[""],"key":{"algo":"rsa","size":2048}}' | cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=server -hostname="172.16.10.4,172.16.10.5,172.16.10.6,127.0.0.1" - | cfssljson -bare tikv-server echo '{"CN":"pd-server","hosts":[""],"key":{"algo":"rsa","size":2048}}' | cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=server -hostname="172.16.10.1,172.16.10.2,172.16.10.3,127.0.0.1" - | cfssljson -bare pd-server 将会生成以下几个文件:tidb-server-key.pem tikv-server-key.pem pd-server-key.pem tidb-server.csr tikv-server.csr pd-server.csr tidb-server.pem tikv-server.pem pd-server.pem 生成客户端证书 echo '{"CN":"client","hosts":[""],"key":{"algo":"rsa","size":2048}}' | cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=client -hostname="" - | cfssljson -bare client 将会生成以下几个文件:client-key.pem client.csr client.pem"}, {"url": "https://pingcap.com/docs-cn/v1.0/op-guide/generate-self-signed-certificates/", "title": "生成自签名证书", "content": " 生成自签名证书 概述 本文档提供使用 cfssl 生成自签名证书的示例。假设实例集群拓扑如下: Name Host IP Services node1 172.16.10.1 PD1, TiDB1 node2 172.16.10.2 PD2, TiDB2 node3 172.16.10.3 PD3 node4 172.16.10.4 TiKV1 node5 172.16.10.5 TiKV2 node6 172.16.10.6 TiKV3 下载 cfssl 假设使用 x86_64 Linux 主机:mkdir ~/bin curl -s -L -o ~/bin/cfssl https://pkg.cfssl.org/R1.2/cfssl_linux-amd64 curl -s -L -o ~/bin/cfssljson https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64 chmod +x ~/bin/{cfssl,cfssljson} export PATH=$PATH:~/bin 初始化证书颁发机构 生成 cfssl 的默认配置,以便于之后修改:mkdir ~/cfssl cd ~/cfssl cfssl print-defaults config > ca-config.json cfssl print-defaults csr > ca-csr.json 生成证书 证书介绍 tidb-server certificate 由 TiDB 使用,为其他组件和客户端验证 TiDB 身份。 tikv-server certificate 由 TiKV 使用,为其他组件和客户端验证 TiKV 身份。 pd-server certificate 由 PD 使用,为其他组件和客户端验证 PD 身份。 client certificate 用于通过 PD、TiKV、TiDB 验证客户端。例如 pd-ctl,tikv-ctl,pd-recover。 配置 CA 选项 根据实际需求修改 ca-config.json :{ "signing": { "default": { "expiry": "43800h" }, "profiles": { "server": { "expiry": "43800h", "usages": [ "signing", "key encipherment", "server auth", "client auth" ] }, "client": { "expiry": "43800h", "usages": [ "signing", "key encipherment", "client auth" ] } } } } 根据实际需求修改 ca-csr.json :{ "CN": "My own CA", "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "CN", "L": "Beijing", "O": "PingCAP", "ST": "Beijing" } ] } 生成 CA 证书 cfssl gencert -initca ca-csr.json | cfssljson -bare ca - 将会生成以下几个文件:ca-key.pem ca.csr ca.pem 生成服务器端证书 hostname 中为各组件的 IP 地址,以及 127.0.0.1echo '{"CN":"tidb-server","hosts":[""],"key":{"algo":"rsa","size":2048}}' | cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=server -hostname="172.16.10.1,172.16.10.2,127.0.0.1" - | cfssljson -bare tidb-server echo '{"CN":"tikv-server","hosts":[""],"key":{"algo":"rsa","size":2048}}' | cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=server -hostname="172.16.10.4,172.16.10.5,172.16.10.6,127.0.0.1" - | cfssljson -bare tikv-server echo '{"CN":"pd-server","hosts":[""],"key":{"algo":"rsa","size":2048}}' | cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=server -hostname="172.16.10.1,172.16.10.2,172.16.10.3,127.0.0.1" - | cfssljson -bare pd-server 将会生成以下几个文件:tidb-server-key.pem tikv-server-key.pem pd-server-key.pem tidb-server.csr tikv-server.csr pd-server.csr tidb-server.pem tikv-server.pem pd-server.pem 生成客户端证书 echo '{"CN":"client","hosts":[""],"key":{"algo":"rsa","size":2048}}' | cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=client -hostname="" - | cfssljson -bare client 将会生成以下几个文件:client-key.pem client.csr client.pem "}, {"url": "https://pingcap.com/docs-cn/v2.0/op-guide/generate-self-signed-certificates/", "title": "生成自签名证书", "content": " 生成自签名证书 概述 本文档提供使用 cfssl 生成自签名证书的示例。假设实例集群拓扑如下: Name Host IP Services node1 172.16.10.1 PD1, TiDB1 node2 172.16.10.2 PD2, TiDB2 node3 172.16.10.3 PD3 node4 172.16.10.4 TiKV1 node5 172.16.10.5 TiKV2 node6 172.16.10.6 TiKV3 下载 cfssl 假设使用 x86_64 Linux 主机:mkdir ~/bin curl -s -L -o ~/bin/cfssl https://pkg.cfssl.org/R1.2/cfssl_linux-amd64 curl -s -L -o ~/bin/cfssljson https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64 chmod +x ~/bin/{cfssl,cfssljson} export PATH=$PATH:~/bin 初始化证书颁发机构 生成 cfssl 的默认配置,以便于之后修改:mkdir ~/cfssl cd ~/cfssl cfssl print-defaults config > ca-config.json cfssl print-defaults csr > ca-csr.json 生成证书 证书介绍 tidb-server certificate 由 TiDB 使用,为其他组件和客户端验证 TiDB 身份。 tikv-server certificate 由 TiKV 使用,为其他组件和客户端验证 TiKV 身份。 pd-server certificate 由 PD 使用,为其他组件和客户端验证 PD 身份。 client certificate 用于通过 PD、TiKV、TiDB 验证客户端。例如 pd-ctl,tikv-ctl,pd-recover。 配置 CA 选项 根据实际需求修改 ca-config.json :{ "signing": { "default": { "expiry": "43800h" }, "profiles": { "server": { "expiry": "43800h", "usages": [ "signing", "key encipherment", "server auth", "client auth" ] }, "client": { "expiry": "43800h", "usages": [ "signing", "key encipherment", "client auth" ] } } } } 根据实际需求修改 ca-csr.json :{ "CN": "My own CA", "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "CN", "L": "Beijing", "O": "PingCAP", "ST": "Beijing" } ] } 生成 CA 证书 cfssl gencert -initca ca-csr.json | cfssljson -bare ca - 将会生成以下几个文件:ca-key.pem ca.csr ca.pem 生成服务器端证书 hostname 中为各组件的 IP 地址,以及 127.0.0.1echo '{"CN":"tidb-server","hosts":[""],"key":{"algo":"rsa","size":2048}}' | cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=server -hostname="172.16.10.1,172.16.10.2,127.0.0.1" - | cfssljson -bare tidb-server echo '{"CN":"tikv-server","hosts":[""],"key":{"algo":"rsa","size":2048}}' | cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=server -hostname="172.16.10.4,172.16.10.5,172.16.10.6,127.0.0.1" - | cfssljson -bare tikv-server echo '{"CN":"pd-server","hosts":[""],"key":{"algo":"rsa","size":2048}}' | cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=server -hostname="172.16.10.1,172.16.10.2,172.16.10.3,127.0.0.1" - | cfssljson -bare pd-server 将会生成以下几个文件:tidb-server-key.pem tikv-server-key.pem pd-server-key.pem tidb-server.csr tikv-server.csr pd-server.csr tidb-server.pem tikv-server.pem pd-server.pem 生成客户端证书 echo '{"CN":"client","hosts":[""],"key":{"algo":"rsa","size":2048}}' | cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=client -hostname="" - | cfssljson -bare client 将会生成以下几个文件:client-key.pem client.csr client.pem "}, {"url": "https://pingcap.com/docs-cn/sql/user-defined-variables/", "title": "用户自定义变量", "content": " 用户自定义变量 用户自定义变量格式为 @var_name。var_name 目前只支持字母,数字,_$组成。用户自定义变量是大小写不敏感的。用户自定义变量是跟 session 绑定的,也就是说只有当前连接可以看见设置的用户变量,其他客户端连接无法查看到。用 SET 语句可以设置用户自定义变量:SET @var_name = expr [, @var_name = expr] ... 或 SET @var_name := expr 对于 SET 语句,赋值操作符可以是 = 也可以是 :=例:mysql> SET @a1=1, @a2=2, @a3:=4; mysql> SELECT @a1, @a2, @t3, @a4 := @a1+@a2+@a3; +------+------+------+--------------------+ | @a1 | @a2 | @a3 | @a4 := @a1+@a2+@a3 | +------+------+------+--------------------+ | 1 | 2 | 4 | 7 | +------+------+------+--------------------+ 如果设置用户变量用了 HEX 或者 BIT 值,TiDB会把它当成二进制字符串。如果你要将其设置成数字,那么需要手动加上 CAST转换: CAST(.. AS UNSIGNED):mysql> SELECT @v1, @v2, @v3; +------+------+------+ | @v1 | @v2 | @v3 | +------+------+------+ | A | 65 | 65 | +------+------+------+ 1 row in set (0.00 sec) mysql> SET @v1 = b'1000001'; Query OK, 0 rows affected (0.00 sec) mysql> SET @v2 = b'1000001'+0; Query OK, 0 rows affected (0.00 sec) mysql> SET @v3 = CAST(b'1000001' AS UNSIGNED); Query OK, 0 rows affected (0.00 sec) mysql> SELECT @v1, @v2, @v3; +------+------+------+ | @v1 | @v2 | @v3 | +------+------+------+ | A | 65 | 65 | +------+------+------+ 1 row in set (0.00 sec) 如果获取一个没有设置过的变量,会返回一个 NULL:mysql> select @not_exist; +------------+ | @not_exist | +------------+ | NULL | +------------+ 1 row in set (0.00 sec) 用户自定义变量不能直接在 SQL 语句中被当成 identifier,例:mysql> select * from t; +------+ | a | +------+ | 1 | +------+ 1 row in set (0.00 sec) mysql> SET @col = "a"; Query OK, 0 rows affected (0.00 sec) mysql> SELECT @col FROM t; +------+ | @col | +------+ | a | +------+ 1 row in set (0.00 sec) mysql> SELECT `@col` FROM t; ERROR 1054 (42S22): Unknown column '@col' in 'field list' mysql> SET @col = "`a`"; Query OK, 0 rows affected (0.00 sec) mysql> SELECT @col FROM t; +------+ | @col | +------+ | `a` | +------+ 1 row in set (0.01 sec) 但是有一个例外是如果你在 PREPARE 语句中使用它,是可以的:mysql> PREPARE stmt FROM "SELECT @c FROM t"; Query OK, 0 rows affected (0.00 sec) mysql> EXECUTE stmt; +------+ | @c | +------+ | a | +------+ 1 row in set (0.01 sec) mysql> DEALLOCATE PREPARE stmt; Query OK, 0 rows affected (0.00 sec) 更多细节。"}, {"url": "https://pingcap.com/recruit-cn/market/community-operation/", "title": "社区运营", "content": " 社区运营 岗位职责: 社区活动的维护运营,包括活动的主题策划、内容统筹、人员沟通、现场执行等运营工作; 企业自媒体平台的日常运营,包括内容编辑、发布、维护、管理、互动、提高影响力和关注度; 了解技术社区用户需求,收集反馈,根据运营数据挖掘和分析用户需求; 资料的搜集与编辑整理。 任职要求: 对 ToB 的商业和市场具备一定的感知,了解 ToB 或技术社区类运营的特点和调性; 有亲和力,具有较强的表达与理解能力以及极强的团队合作意识,善于主动发现问题并及时沟通并解决; 认真负责,逻辑清晰,有良好的文字和语言表达能力; 性格开朗,积极热情,能够快速学习。 待遇:8K -20K,13薪 + 奖金,优秀者可面议工作地点:北京"}, {"url": "https://pingcap.com/docs-cn/op-guide/offline-ansible-deployment/", "title": "离线 TiDB-Ansible 部署方案", "content": " 离线 TiDB-Ansible 部署方案 准备机器 下载机一台 该机器需开放外网访问,用于下载 TiDB-Ansible、TiDB 及相关软件安装包。 推荐安装 CentOS 7.3 及以上版本 Linux 操作系统。 部署目标机器若干及部署中控机一台 系统要求及配置参考准备机器。 可以无法访问外网。 在中控机上安装系统依赖包 下载系统依赖离线安装包,上传至中控机。该离线包仅支持 CentOS 7 系统,包含 pip 及 sshpass。 # tar -xzvf ansible-system-rpms.el7.tar.gz # cd ansible-system-rpms.el7 # chmod u+x install_ansible_system_rpms.sh # ./install_ansible_system_rpms.sh 安装完成后,可通过 pip -V 验证 pip 是否安装成功:# pip -V pip 8.1.2 from /usr/lib/python2.7/site-packages (python 2.7) 如果你的系统已安装 pip,请确认版本 >= 8.1.2,否则离线安装 ansible 及其依赖时,会有兼容问题。 在中控机上创建 tidb 用户,并生成 ssh key 参考在中控机上创建 tidb 用户,并生成 ssh key 即可。在中控机器上离线安装 Ansible 及其依赖 以下是 CentOS 7 系统 Ansible 离线安装方式:目前 release-2.0 及 master 版本兼容 Ansible 2.5 版本,Ansible 及相关依赖版本记录在 tidb-ansible/requirements.txt 文件中,请下载 Ansible 2.5 离线安装包上传至中控机。 下载 Ansible 2.5 离线安装包 下面以安装 Ansible 2.5 为例:# tar -xzvf ansible-2.5.0-pip.tar.gz # cd ansible-2.5.0-pip/ # chmod u+x install_ansible.sh # ./install_ansible.sh 安装完成后,可通过 ansible --version 查看版本:# ansible --version ansible 2.5.0 在下载机上下载 TiDB-Ansible 及 TiDB 安装包 在下载机上安装 Ansible请按以下方式在 CentOS 7 系统的下载机上在线安装 Ansible。安装完成后,可通过 ansible --version 查看版本,请务必确认是 Ansible 2.5.0 版本,否则会有兼容问题。# yum install epel-release # yum install ansible curl # ansible --version ansible 2.5.0 下载 tidb-ansible使用以下命令从 Github TiDB-Ansible 项目上下载 TiDB-Ansible 相应版本,默认的文件夹名称为 tidb-ansible,以下为各版本下载示例,版本选择可以咨询官方。下载 2.0 GA 版本:git clone -b release-2.0 https://github.com/pingcap/tidb-ansible.git 或下载 master 版本:git clone https://github.com/pingcap/tidb-ansible.git 执行 local_prepare.yml playbook,联网下载 TiDB binary 到下载机cd tidb-ansible ansible-playbook local_prepare.yml 将执行完以上命令之后的 tidb-ansible 文件夹拷贝到中控机 /home/tidb 目录下,文件属主权限需是 tidb 用户。 在中控机上配置部署机器 ssh 互信及 sudo 规则 参考在中控机上配置部署机器 ssh 互信及 sudo 规则即可。在部署目标机器上安装 NTP 服务 如果你的部署目标机器时间、时区设置一致,已开启 NTP 服务且在正常同步时间,此步骤可忽略,可参考如何检测 NTP 服务是否正常。 参考在部署目标机器上安装 NTP 服务即可。在部署目标机器上配置 CPUfreq 调节器模式 参考在部署目标机器上配置 CPUfreq 调节器模式即可。在部署目标机器上添加数据盘 ext4 文件系统挂载参数 参考在部署目标机器上添加数据盘 ext4 文件系统挂载参数即可。分配机器资源,编辑 inventory.ini 文件 参考分配机器资源,编辑 inventory.ini 文件即可。部署任务 ansible-playbook local_prepare.yml 该 playbook 不需要再执行。 Grafana Dashboard 上的 Report 按钮可用来生成 PDF 文件,此功能依赖 fontconfig 包及英文字体,如需使用该功能,请下载 font 离线安装包上传至 grafana_servers 机器上安装。该离线包仅支持 CentOS 7 系统,包含 fontconfig 及 open-sans-fonts。$ tar -xzvf grafana-font-rpms.el7.tar.gz $ cd grafana-font-rpms.el7 $ chmod u+x install_grafana_font_rpms.sh $ ./install_grafana_font_rpms.sh 参考部署任务即可。 测试集群 参考测试集群即可。"}, {"url": "https://pingcap.com/docs-cn/v1.0/op-guide/offline-ansible-deployment/", "title": "离线 TiDB-Ansible 部署方案", "content": " 离线 TiDB-Ansible 部署方案 准备机器 下载机一台 该机器需开放外网访问,用于下载 TiDB-Ansible、TiDB 及相关软件安装包。 推荐安装 CentOS 7.3 及以上版本 Linux 操作系统。 部署目标机器若干及部署中控机一台 系统要求及配置参考准备机器。 可以无法访问外网。 在中控机器上离线安装 Ansible 及其依赖 CentOS 7 系统 Ansible 离线安装方式: 下载 Ansible 离线安装包 ,上传至中控机。 # tar -xzvf ansible-2.4-rpms.el7.tar.gz # cd ansible-2.4-rpms.el7 # rpm -ivh PyYAML*rpm libyaml*rpm python-babel*rpm python-backports*rpm python-backports-ssl_match_hostname*rpm python-cffi*rpm python-enum34*rpm python-httplib2*rpm python-idna*rpm python-ipaddress*rpm python-jinja2*rpm python-markupsafe*rpm python-paramiko*rpm python-passlib*rpm python-ply*rpm python-pycparser*rpm python-setuptools*rpm python-six*rpm python2-cryptography*rpm python2-jmespath*rpm python2-pyasn1*rpm sshpass*rpm # rpm -ivh ansible-2.4.2.0-2.el7.noarch.rpm 安装完成后,可通过 ansible --version 查看版本:# ansible --version ansible 2.4.2.0 在下载机上下载 TiDB-Ansible 及 TiDB 安装包 在下载机上安装 Ansible请按以下方式在 CentOS 7 系统的下载机上在线安装 Ansible。 通过 epel 源安装, 会自动安装 Ansible 相关依赖(如 Jinja2==2.7.2 MarkupSafe==0.11),安装完成后,可通过 ansible --version 查看版本,请务必确认是 Ansible 2.4 及以上版本,否则会有兼容问题。# yum install epel-release # yum install ansible curl # ansible --version ansible 2.4.2.0 下载 tidb-ansible使用以下命令从 Github TiDB-Ansible 项目 上下载 TiDB-Ansible 相应版本,默认的文件夹名称为 tidb-ansible。下载 GA 版本:git clone -b release-1.0 https://github.com/pingcap/tidb-ansible.git 或下载 master 版本:git clone https://github.com/pingcap/tidb-ansible.git 注: 生产环境请下载 GA 版本部署 TiDB。 执行 local_prepare.yml playbook,联网下载 TiDB binary 到下载机cd tidb-ansible ansible-playbook local_prepare.yml 将执行完以上命令之后的 tidb-ansible 文件夹拷贝到中控机 /home/tidb 目录下,文件属主权限需是 tidb 用户。 分配机器资源,编辑 inventory.ini 文件 参考分配机器资源,编辑 inventory.ini 文件即可。部署任务 参考部署任务即可。 ansible-playbook local_prepare.yml 该 playbook 不需要再执行。 测试集群 参考测试集群即可。"}, {"url": "https://pingcap.com/docs-cn/v2.0/op-guide/offline-ansible-deployment/", "title": "离线 TiDB-Ansible 部署方案", "content": " 离线 TiDB-Ansible 部署方案 准备机器 下载机一台 该机器需开放外网访问,用于下载 TiDB-Ansible、TiDB 及相关软件安装包。 推荐安装 CentOS 7.3 及以上版本 Linux 操作系统。 部署目标机器若干及部署中控机一台 系统要求及配置参考准备机器。 可以无法访问外网。 在中控机器上离线安装 Ansible 及其依赖 CentOS 7 系统 Ansible 离线安装方式: 下载 Ansible 2.4.2 离线安装包 ,上传至中控机。 # tar -xzvf ansible-2.4.2-rpms.el7.tar.gz # cd ansible-2.4-rpms.el7 # chmod u+x install_ansible.sh # ./install_ansible.sh 安装完成后,可通过 ansible --version 查看版本:# ansible --version ansible 2.4.2.0 在下载机上下载 TiDB-Ansible 及 TiDB 安装包 在下载机上安装 Ansible请按以下方式在 CentOS 7 系统的下载机上在线安装 Ansible。 通过 epel 源安装, 会自动安装 Ansible 相关依赖(如 Jinja2==2.7.2 MarkupSafe==0.11),安装完成后,可通过 ansible --version 查看版本,请务必确认是 Ansible 2.4 及以上版本,否则会有兼容问题。# yum install epel-release # yum install ansible curl # ansible --version ansible 2.4.2.0 下载 tidb-ansible使用以下命令从 Github TiDB-Ansible 项目 上下载 TiDB-Ansible 相应版本,默认的文件夹名称为 tidb-ansible。下载 GA 版本:git clone -b release-1.0 https://github.com/pingcap/tidb-ansible.git 或下载 master 版本:git clone https://github.com/pingcap/tidb-ansible.git 注: 生产环境请下载 GA 版本部署 TiDB。 执行 local_prepare.yml playbook,联网下载 TiDB binary 到下载机cd tidb-ansible ansible-playbook local_prepare.yml 将执行完以上命令之后的 tidb-ansible 文件夹拷贝到中控机 /home/tidb 目录下,文件属主权限需是 tidb 用户。 分配机器资源,编辑 inventory.ini 文件 参考分配机器资源,编辑 inventory.ini 文件即可。部署任务 参考部署任务即可。 ansible-playbook local_prepare.yml 该 playbook 不需要再执行。 测试集群 参考测试集群即可。"}, {"url": "https://pingcap.com/docs-cn/sql/precision-math/", "title": "精度数学", "content": " 精度数学 TiDB 中精度数学计算与 MySQL 中基本一致, 详情请参见: Precision Math. 数值类型 DECIMAL 数据类型的特性 数值类型 精确数值运算的范围包括精确值数据类型(整型和 DECIMAL 类型), 以及精确值数字字面量. 近似值数据类型和近似值数字字面量被作为浮点数来处理.精确值数字字面量包含整数部分或小数部分, 或二者都包含. 精确值数字字面量可以包含符号位. 例如: 1, .2, 3.4, -5, -6.78, +9.10.近似值数字字面量以一个包含尾数和指数的科学计数法表示(基数为 10). 其中尾数和指数可以分别或同时带有符号位. 例如: 1.2E3, 1.2E-3, -1.2E3, -1.2E-3.两个看起来相似的数字可能会被以不同的方式进行处理. 例如, 2.34 是精确值(定点数), 而 2.3E0 是近似值(浮点数).DECIMAL 数据类型是定点数类型, 其运算是精确计算. FLOAT 和 DOUBLE 数据类型是浮点类型, 其运算是近似计算.DECIMAL 数据类型的特性 本节讨论 DECIMAL 数据类型的特性, 主要涉及以下几点: 最大位数 存储格式 存储要求 DECIMAL 列的声明语法为 DECIMAL(M, D). 其中参数值意义及其范围如下: M 表示最大的数字位数 (精度). 1<= M <= 65. D 表示小数点右边数字的位数 (标度). 1 <= D <= 30 且 不大于 M. M 的最大值 65 表示 DECIMAL 值的计算精确到 65 位数字. 该精度同样适用于其精确值字面量.DECIMAL 列的值采用二进制进行存储, 其将每 9 位十进制数字包装成 4 个字节. 其中整数和小数部分分别确定所需的存储空间. 如果数字位数为 9 的倍数, 则每 9 位十进制数字各采用 4 个字节进行存储, 对于剩余不足 9 位的数字, 所需的存储空间如下表所示. 剩余数字位数 存储所需字节数 0 0 1–2 1 3–4 2 5–6 3 7–9 4 例如, 定义类型为 DECIMAL(18, 9) 的列, 其小数点两侧均各包含 9 位十进制数字, 因此, 分别需要 4 个字节的存储空间. 定义类型为 DECIMAL(20, 6) 的列, 其小数部分包含 6 位十进制数字, 整数部分包含 14 位十进制数字. 整数部分中 9 位数字需要 4 个字节进行存储, 其余 5 位数字需要 3 个字节进行存储. 小数部分 6 位数字需要 3 个字节进行存储.DECIMAL 列不存储前导的字符 + 或字符 - 或数字 0. 如果将 +0003.1 插入到 DECIMAL(5, 1) 列中, 则将其存储为3.1. 对于负数, 不存储字符 - 的字面值.DECIMAL 列不允许插入大于列定义的隐含范围的值. 例如, DECIMAL(3, 0) 列范围为 -999 到 999. DECIMAL(M, D) 列小数点左边部分最多支持 M-D 位数字.有关 DECIMAL 值的内部格式完整说明, 请参阅 TiDB 源码文件 types/mydecimal.go.表达式计算 在涉及精度数学计算的表达式中,TiDB 会尽可能不做任何修改的使用每个输入的数值。比如:在计算比较函数时,参与运算的数字将不做任何改变。在严格 SQL 模式下,向一个数据列插入一个值时,如果该值处于这一列的值域范围内,这个值将直接不做任何修改的直接插入进去,提取这个值的时候,取得的值和插入的值将会是同一个值。当处于非严格 SQL 模式时,TiDB 会允许数据插入过程中发生的数据截断。处理数值类型表达式取决于这个表达式参数的具体值: 当表达式参数中包含近似值时,这个表达式的结果也是近似值,TiDB 会使用浮点数对应的计算逻辑返回一个浮点数的结果 当表达式参数中不包含任何近似值时(也就是说表达式的参数全部是精确值),如果某个精确值包含小数部分,TIDB 会对这个表达式使用 DECIMAL 对应的计算逻辑,返回一个 DECIMAL 的结果,精确到 65 位数字 其他情况下,表达式只会包含整数参数,这个表达式的结果也是精确的,TiDB 会使用整数对应的计算逻辑返回一个整数结果,精度和 BIGINT 保持一致(64位) 如果数值类型表达式中包含字符串参数,这些字符串参数将被转换成双精度浮点数,这个表达式的计算结果将是个近似值。向一个数值类型列插入数据的具体行为会受到 SQL 模式的影响。接下来的讨论将围绕严格模式以及 ERROR_FOR_DIVISION_BY_ZERO 模式展开,如果要打开所有的限制,可以简单的使用 TRADITIONAL 模式,这个模式将同时使用严格模式以及 ERROR_FOR_DIVISION_BY_ZERO 模式:SET sql_mode = 'TRADITIONAL'; 向一个具有精确值类型(DECIMAL 或者整数类型)的列插入数据时,如果插入的数据位于该列的值域范围内将使用该数据的精确值。如果该数据的小数部分太长,将会发生数值修约,这时会有 warning 产生,具体内容可以看”数值修约”。如果该数据整数部分太长: 如果没有开启严格模式,这个值会被截断并产生一个 warning 如果开启了严格模式,将会产生一个数据溢出的 error 如果向一个数值类型列插入字符串,如果该字符串中包含非数值部分,TiDB 将这样做类型转换: 在严格模式下,没有以数字开头的字符串(即使是一个空字符串)不能被被用作数字值并会返回一个 error 或者是 warning; 以数字开头的字符串可以被转换,不过末尾的非数字部分会被截断。如果被截断的部分包含的不全是空格,在严格模式下这回产生一个 error 或者 warning 默认情况下,如果计算的过程中发生了除数是 0 的现象将会得到一个 NULL 结果,并且不会有 warning 产生。通过设置适当的 SQL 模式,除以 0 的操作可以被限制:当设置 ERROR_FOR_DIVISION_BY_ZERO SQL 模式时,TiDB 的行为是: 如果设置了严格 SQL 模式,INSERT 和 UPDATE 的过程中如果发生了除以 0 的操作,正在进行的 INSERT 或者 UPDATE 操作会被禁止,并且会返回一个 error 如果没有设置严格 SQL 模式,除以 0 的操作仅会返回一个 warning 假设我们有如下的 SQL 语句:INSERT INTO t SET i = 1/0; 不同的 SQL 模式将会导致不同的结果如下: sql_mode 的值 结果 “ 没有 warning,没有 error,i 被设为 NULL strict 没有 warning,没有 error,i 被设为 NULL ERROR_FOR_DIVISION_BY_ZERO 有 warning,没有 error,i 被设为 NULL strict, ERROR_FOR_DIVISION_BY_ZERO 有 error,插入失败 数值修约 round() 函数的结果取决于他的参数是否是精确值: 如果参数是精确值,round() 函数将使用四舍五入的规则 如果参数是一个近似值,round() 表达式的结果可能和 MySQL 不太一样 TiDB > SELECT ROUND(2.5), ROUND(25E-1); +------------+--------------+ | ROUND(2.5) | ROUND(25E-1) | +------------+--------------+ | 3 | 3 | +------------+--------------+ 1 row in set (0.00 sec) 向一个 DECIMAL 或者整数类型列插入数据时,round 的规则将采用 round half away from zero 的方式:TiDB > CREATE TABLE t (d DECIMAL(10,0)); Query OK, 0 rows affected (0.01 sec) TiDB > INSERT INTO t VALUES(2.5),(2.5E0); Query OK, 2 rows affected, 2 warnings (0.00 sec) TiDB > SELECT d FROM t; +------+ | d | +------+ | 3 | | 3 | +------+ 2 rows in set (0.00 sec)"}, {"url": "https://pingcap.com/docs-cn/sql/variable/", "title": "系统变量", "content": " 系统变量 MySQL 系统变量 (System Variables) 是一些系统参数,用于调整数据库运行时的行为,根据变量的作用范围分为全局范围有效(Global Scope)以及会话级别有效(Session Scope)。TiDB 支持 MySQL5.7 的所有系统变量,大部分变量仅仅是为了兼容性而支持,不会影响运行时行为。设置系统变量 通过 SET 语句可以修改系统变量的值。进行修改时,还要考虑变量可修改的范围,不是所有的变量都能在全局/会话范围内进行修改。具体的可修改范围参考 MySQL 动态变量文档。全局范围值 在变量名前加 GLOBAL 关键词或者是使用 @@global. 作为修饰符: SET GLOBAL autocommit = 1; SET @@global.autocommit = 1; 会话范围值 在变量名前加 SESSION 关键词或者是使用 @@session. 作为修饰符,或者是不加任何修饰符: SET SESSION autocommit = 1; SET @@session.autocommit = 1; SET @@autocommit = 1; LOCAL 以及 @@local. 是 SESSION 以及 @@session. 的同义词 TiDB 支持的 MySQL 系统变量 下列系统变量是 TiDB 真正支持并且行为和 MySQL 一致: 变量名 作用域 说明 autocommit GLOBAL | SESSION 是否自动 Commit 事务 sql_mode GLOBAL | SESSION 支持部分 MySQL SQL mode, time_zone GLOBAL | SESSION 数据库所使用的时区 tx_isolation GLOBAL | SESSION 事务隔离级别 TiDB 特有的系统变量 参见 TiDB 专用系统变量。"}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/variable/", "title": "系统变量", "content": " 系统变量 MySQL 系统变量 (System Variables) 是一些系统参数,用于调整数据库运行时的行为,根据变量的作用范围分为全局范围有效(Global Scope)以及会话级别有效(Session Scope)。TiDB 支持 MySQL5.7 的所有系统变量,大部分变量仅仅是为了兼容性而支持,不会影响运行时行为。设置系统变量 通过 SET 语句可以修改系统变量的值。进行修改时,还要考虑变量可修改的范围,不是所有的变量都能在全局/会话范围内进行修改。具体的可修改范围参考 MySQL 动态变量文档。全局范围值 在变量名前加 GLOBAL 关键词或者是使用 @@global. 作为修饰符: SET GLOBAL autocommit = 1; SET @@global.autocommit = 1; 会话范围值 在变量名前加 SESSION 关键词或者是使用 @@session. 作为修饰符,或者是不加任何修饰符: SET SESSION autocommit = 1; SET @@session.autocommit = 1; SET @@autocommit = 1; LOCAL 以及 @@local. 是 SESSION 以及 @@session. 的同义词 TiDB 支持的 MySQL 系统变量 下列系统变量是 TiDB 真正支持并且行为和 MySQL 一致: 变量名 作用域 说明 autocommit GLOBAL | SESSION 是否自动 Commit 事务 sql_mode GLOBAL | SESSION 支持部分 MySQL SQL mode, time_zone GLOBAL | SESSION 数据库所使用的时区 tx_isolation GLOBAL | SESSION 事务隔离级别 TiDB 特有的系统变量 参见 TiDB 专用系统变量。"}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/variable/", "title": "系统变量", "content": " 系统变量 MySQL 系统变量 (System Variables) 是一些系统参数,用于调整数据库运行时的行为,根据变量的作用范围分为全局范围有效(Global Scope)以及会话级别有效(Session Scope)。TiDB 支持 MySQL5.7 的所有系统变量,大部分变量仅仅是为了兼容性而支持,不会影响运行时行为。设置系统变量 通过 SET 语句可以修改系统变量的值。进行修改时,还要考虑变量可修改的范围,不是所有的变量都能在全局/会话范围内进行修改。具体的可修改范围参考 MySQL 动态变量文档。全局范围值 在变量名前加 GLOBAL 关键词或者是使用 @@global. 作为修饰符: SET GLOBAL autocommit = 1; SET @@global.autocommit = 1; 会话范围值 在变量名前加 SESSION 关键词或者是使用 @@session. 作为修饰符,或者是不加任何修饰符: SET SESSION autocommit = 1; SET @@session.autocommit = 1; SET @@autocommit = 1; LOCAL 以及 @@local. 是 SESSION 以及 @@session. 的同义词 TiDB 支持的 MySQL 系统变量 下列系统变量是 TiDB 真正支持并且行为和 MySQL 一致: 变量名 作用域 说明 autocommit GLOBAL | SESSION 是否自动 Commit 事务 sql_mode GLOBAL | SESSION 支持部分 MySQL SQL mode, time_zone GLOBAL | SESSION 数据库所使用的时区 tx_isolation GLOBAL | SESSION 事务隔离级别 TiDB 特有的系统变量 参见 TiDB 专用系统变量。"}, {"url": "https://pingcap.com/docs-cn/sql/statistics/", "title": "统计信息简介", "content": " 统计信息简介 TiDB 优化器会根据统计信息来选择最优的执行计划。统计信息收集了表级别和列级别的信息,表的统计信息包括总行数,以及修改的行数。列的统计信息包括不同值的数量,NULL 的数量,直方图,以及该列的 Count-Min Sketch 信息。统计信息的收集 手动收集 你可以通过执行 ANALYZE 语句来收集统计信息。语法:ANALYZE TABLE TableNameList [WITH NUM BUCKETS] > 该语句会收集 TableNameList 中所有表的统计信息。 > WITH NUM BUCKETS 可以用来指定生成直方图的桶数量上限。 ANALYZE TABLE TableName INDEX [IndexNameList] [WITH NUM BUCKETS] > 该语句会收集 TableName 中所有的 IndexNameList 中的索引列的统计信息。 > IndexNameList 为空时会收集所有索引列的统计信息。 ANALYZE TABLE TableName PARTITION PartitionNameList [WITH NUM BUCKETS] > 该语句会收集 TableName 中所有的 PartitionNameList 中分区的统计信息。 ANALYZE TABLE TableName PARTITION PartitionNameList [IndexNameList] [WITH NUM BUCKETS] > 该语句会收集 TableName 中所有的 PartitionNameList 中分区的索引列统计信息。 自动更新 在发生增加,删除以及修改语句时,TiDB 会自动更新表的总行数以及修改的行数。这些信息会定期持久化下来, 更新的周期是 5 * stats-lease, stats-lease 的默认值是 3s,如果将其指定为 0,那么将不会自动更新。和统计信息自动更新相关的三个系统变量如下: 系统变量名 默认值 功能 tidb_auto_analyze_ratio 0.5 自动更新阈值 tidb_auto_analyze_start_time 00:00 +0000 一天中能够进行自动更新的开始时间 tidb_auto_analyze_end_time 23:59 +0000 一天中能够进行自动更新的结束时间 当某个表 tbl 的修改行数与总行数的比值大于 tidb_auto_analyze_ratio,并且当前时间在 tidb_auto_analyze_start_time 和 tidb_auto_analyze_end_time 之间时,TiDB 会在后台执行 ANALYZE TABLE tbl 语句自动更新这个表的统计信息。在查询语句执行时,TiDB 会以 feedback-probability 的概率收集反馈信息,并将其用于更新直方图和 Count-Min Sketch。feedback-probability 可通过配置文件修改,其默认值是 0。控制 ANALYZE 并发度 执行 ANALYZE 语句的时候,你可以通过一些参数来调整并发度,以控制对系统的影响。tidb_build_stats_concurrency 目前 ANALYZE 执行的时候会被切分成一个个小的任务,每个任务只负责某一个列或者索引。tidb_build_stats_concurrency 可以控制同时执行的任务的数量,其默认值是 4。tidb_distsql_scan_concurrency 在执行分析普通列任务的时候,tidb_distsql_scan_concurrency 可以用于控制一次读取的 Region 数量,其默认值是 10。tidb_index_serial_scan_concurrency 在执行分析索引列任务的时候,tidb_index_serial_scan_concurrency 可以用于控制一次读取的 Region 数量,其默认值是 1。统计信息的查看 你可以通过一些语句来查看统计信息的状态。表的元信息 你可以通过 SHOW STATS_META 来查看表的总行数以及修改的行数等信息。语法:SHOW STATS_META [ShowLikeOrWhere] > 该语句会输出所有表的总行数以及修改行数等信息,你可以通过使用 ShowLikeOrWhere 来筛选需要的信息。 目前 SHOW STATS_META 会输出 6 列,具体如下: 语法元素 说明 db_name 数据库名 table_name 表名 partition_name 分区名 update_time 更新时间 modify_count 修改的行数 row_count 总行数 列的元信息 你可以通过 SHOW STATS_HISTOGRAMS 来查看列的不同值数量以及 NULL 数量等信息。语法:SHOW STATS_HISTOGRAMS [ShowLikeOrWhere] > 该语句会输出所有列的不同值数量以及 NULL 数量等信息,你可以通过使用 ShowLikeOrWhere 来筛选需要的信息。 目前 SHOW STATS_HISTOGRAMS 会输出 8 列,具体如下: 语法元素 说明 db_name 数据库名 table_name 表名 partition_name 分区名 column_name 列名 is_index 是否是索引列 update_time 更新时间 distinct_count 不同值数量 null_count NULL 的数量 avg_col_size 列平均长度 直方图桶的信息 你可以通过 SHOW STATS_BUCKETS 来查看直方图每个桶的信息。语法:SHOW STATS_BUCKETS [ShowLikeOrWhere] > 该语句会输出所有桶的信息,你可以通过使用 ShowLikeOrWhere 来筛选需要的信息。 目前 SHOW STATS_BUCKETS 会输出 10 列,具体如下: 语法元素 说明 db_name 数据库名 table_name 表名 partition_name 分区名 column_name 列名 is_index 是否是索引列 bucket_id 桶的编号 count 所有落在这个桶及之前桶中值的数量 repeats 最大值出现的次数 lower_bound 最小值 upper_bound 最大值 删除统计信息 可以通过执行 DROP STATS 语句来删除统计信息。语法:DROP STATS TableName > 该语句会删除 TableName 中所有的统计信息。 统计信息的导入导出 导出统计信息 统计信息的导出接口为:http://${tidb-server-ip}:${tidb-server-status-port}/stats/dump/${db_name}/${table_name} > 通过该接口可以获取数据库 `${db_name}` 中的表 `${table_name}` 的 json 格式的统计信息。 导入统计信息 导入的统计信息一般是通过统计信息导出接口得到的 json 文件。语法:LOAD STATS 'file_name' > `file_name` 为要导入的统计信息的文件名。"}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/statistics/", "title": "统计信息简介", "content": " 统计信息简介 TiDB 优化器会根据统计信息来选择最优的执行计划。统计信息收集了表级别和列级别的信息,表的统计信息包括总行数,以及修改的行数。列的统计信息包括不同值的数量,NULL 的数量,以及该列的直方图信息。统计信息的收集 手动收集 你可以通过执行 ANALYZE 语句来收集统计信息。语法:ANALYZE TABLE TableNameList > 该语句会收集 TableNameList 中所有表的统计信息。 ANALYZE TABLE TableName INDEX IndexNameList > 该语句会收集 TableName 中所有的 IndexNameList 中的索引列的统计信息。 自动更新 在发生增加,删除以及修改语句时,TiDB 会自动更新表的总行数以及修改的行数。这些信息会定期持久化下来, 更新的周期是 5 * stats-lease, stats-lease 的默认值是 3s,如果将其指定为 0,那么将不会自动更新。控制 ANALYZE 并发度 执行 ANALYZE 语句的时候,你可以通过一些参数来调整并发度,以控制对系统的影响。tidb_build_stats_concurrency 目前 ANALYZE 执行的时候会被切分成一个个小的任务,每个任务只负责某一个列或者索引。tidb_build_stats_concurrency 可以控制同时执行的任务的数量,其默认值是 4。tidb_distsql_scan_concurrency 在执行分析普通列任务的时候,tidb_distsql_scan_concurrency 可以用于控制一次读取的 Region 数量,其默认值是 10。tidb_index_serial_scan_concurrency 在执行分析索引列任务的时候,tidb_index_serial_scan_concurrency 可以用于控制一次读取的 Region 数量,其默认值是 1。统计信息的查看 你可以通过一些语句来查看统计信息的状态。表的元信息 你可以通过 SHOW STATS_META 来查看表的总行数以及修改的行数等信息。语法:SHOW STATS_META [ShowLikeOrWhere] > 该语句会输出所有表的总行数以及修改行数等信息,你可以通过使用 ShowLikeOrWhere 来筛选需要的信息。 目前 SHOW STATS_META 会输出 5 列,具体如下: 语法元素 说明 db_name 数据库名 table_name 表名 update_time 更新时间 modify_count 修改的行数 row_count 总行数 列的元信息 你可以通过 SHOW STATS_HISTOGRAMS 来查看列的不同值数量以及 NULL 数量等信息。语法:SHOW STATS_HISTOGRAMS [ShowLikeOrWhere] > 该语句会输出所有列的不同值数量以及 NULL 数量等信息,你可以通过使用 ShowLikeOrWhere 来筛选需要的信息。 目前 SHOW STATS_HISTOGRAMS 会输出 7 列,具体如下: 语法元素 说明 db_name 数据库名 table_name 表名 column_name 列名 is_index 是否是索引列 update_time 更新时间 distinct_count 不同值数量 null_count NULL 的数量 直方图桶的信息 你可以通过 SHOW STATS_BUCKETS 来查看直方图每个桶的信息。语法:SHOW STATS_BUCKETS [ShowLikeOrWhere] > 该语句会输出所有桶的信息,你可以通过使用 ShowLikeOrWhere 来筛选需要的信息。 目前 SHOW STATS_BUCKETS 会输出 9 列,具体如下: 语法元素 说明 db_name 数据库名 table_name 表名 column_name 列名 is_index 是否是索引列 bucket_id 桶的编号 count 所有落在这个桶及之前桶中值的数量 repeats 最大值出现的次数 lower_bound 最小值 upper_bound 最大值 删除统计信息 可以通过执行 DROP STATS 语句来删除统计信息。语法:DROP STATS TableName > 该语句会删除 TableName 中所有的统计信息。"}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/statistics/", "title": "统计信息简介", "content": " 统计信息简介 TiDB 优化器会根据统计信息来选择最优的执行计划。统计信息收集了表级别和列级别的信息,表的统计信息包括总行数,以及修改的行数。列的统计信息包括不同值的数量,NULL 的数量,以及该列的直方图信息。统计信息的收集 手动收集 你可以通过执行 ANALYZE 语句来收集统计信息。语法:ANALYZE TABLE TableNameList > 该语句会收集 TableNameList 中所有表的统计信息。 ANALYZE TABLE TableName INDEX IndexNameList > 该语句会收集 TableName 中所有的 IndexNameList 中的索引列的统计信息。 自动更新 在发生增加,删除以及修改语句时,TiDB 会自动更新表的总行数以及修改的行数。这些信息会定期持久化下来, 更新的周期是 5 * stats-lease, stats-lease 的默认值是 3s,如果将其指定为 0,那么将不会自动更新。控制 ANALYZE 并发度 执行 ANALYZE 语句的时候,你可以通过一些参数来调整并发度,以控制对系统的影响。tidb_build_stats_concurrency 目前 ANALYZE 执行的时候会被切分成一个个小的任务,每个任务只负责某一个列或者索引。tidb_build_stats_concurrency 可以控制同时执行的任务的数量,其默认值是 4。tidb_distsql_scan_concurrency 在执行分析普通列任务的时候,tidb_distsql_scan_concurrency 可以用于控制一次读取的 Region 数量,其默认值是 10。tidb_index_serial_scan_concurrency 在执行分析索引列任务的时候,tidb_index_serial_scan_concurrency 可以用于控制一次读取的 Region 数量,其默认值是 1。统计信息的查看 你可以通过一些语句来查看统计信息的状态。表的元信息 你可以通过 SHOW STATS_META 来查看表的总行数以及修改的行数等信息。语法:SHOW STATS_META [ShowLikeOrWhere] > 该语句会输出所有表的总行数以及修改行数等信息,你可以通过使用 ShowLikeOrWhere 来筛选需要的信息。 目前 SHOW STATS_META 会输出 5 列,具体如下: 语法元素 说明 db_name 数据库名 table_name 表名 update_time 更新时间 modify_count 修改的行数 row_count 总行数 列的元信息 你可以通过 SHOW STATS_HISTOGRAMS 来查看列的不同值数量以及 NULL 数量等信息。语法:SHOW STATS_HISTOGRAMS [ShowLikeOrWhere] > 该语句会输出所有列的不同值数量以及 NULL 数量等信息,你可以通过使用 ShowLikeOrWhere 来筛选需要的信息。 目前 SHOW STATS_HISTOGRAMS 会输出 7 列,具体如下: 语法元素 说明 db_name 数据库名 table_name 表名 column_name 列名 is_index 是否是索引列 update_time 更新时间 distinct_count 不同值数量 null_count NULL 的数量 直方图桶的信息 你可以通过 SHOW STATS_BUCKETS 来查看直方图每个桶的信息。语法:SHOW STATS_BUCKETS [ShowLikeOrWhere] > 该语句会输出所有桶的信息,你可以通过使用 ShowLikeOrWhere 来筛选需要的信息。 目前 SHOW STATS_BUCKETS 会输出 9 列,具体如下: 语法元素 说明 db_name 数据库名 table_name 表名 column_name 列名 is_index 是否是索引列 bucket_id 桶的编号 count 所有落在这个桶及之前桶中值的数量 repeats 最大值出现的次数 lower_bound 最小值 upper_bound 最大值 删除统计信息 可以通过执行 DROP STATS 语句来删除统计信息。语法:DROP STATS TableName > 该语句会删除 TableName 中所有的统计信息。"}, {"url": "https://pingcap.com/docs-cn/sql/type-conversion-in-expression-evaluation/", "title": "表达式求值的类型转换", "content": " 表达式求值的类型转换 TiDB 中表达式求值的类型转换与 MySQL 基本一致,详情参见 MySQL 表达式求值的类型转换。"}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/type-conversion-in-expression-evaluation/", "title": "表达式求值的类型转换", "content": " 表达式求值的类型转换 TiDB 中表达式求值的类型转换与 MySQL 基本一致,详情参见 MySQL 表达式求值的类型转换。"}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/type-conversion-in-expression-evaluation/", "title": "表达式求值的类型转换", "content": " 表达式求值的类型转换 TiDB 中表达式求值的类型转换与 MySQL 基本一致,详情参见 MySQL 表达式求值的类型转换。"}, {"url": "https://pingcap.com/docs-cn/sql/expression-syntax/", "title": "表达式语法", "content": " 表达式语法 (Expression Syntax) 在 TiDB 中,以下规则是表达式的语法,你可以在 parser/parser.y 中找到定义。TiDB 的语法解析是基于 yacc 的。Expression: singleAtIdentifier assignmentEq Expression | Expression logOr Expression | Expression "XOR" Expression | Expression logAnd Expression | "NOT" Expression | Factor IsOrNotOp trueKwd | Factor IsOrNotOp falseKwd | Factor IsOrNotOp "UNKNOWN" | Factor Factor: Factor IsOrNotOp "NULL" | Factor CompareOp PredicateExpr | Factor CompareOp singleAtIdentifier assignmentEq PredicateExpr | Factor CompareOp AnyOrAll SubSelect | PredicateExpr PredicateExpr: PrimaryFactor InOrNotOp '(' ExpressionList ')' | PrimaryFactor InOrNotOp SubSelect | PrimaryFactor BetweenOrNotOp PrimaryFactor "AND" PredicateExpr | PrimaryFactor LikeOrNotOp PrimaryExpression LikeEscapeOpt | PrimaryFactor RegexpOrNotOp PrimaryExpression | PrimaryFactor PrimaryFactor: PrimaryFactor '|' PrimaryFactor | PrimaryFactor '&' PrimaryFactor | PrimaryFactor "<<" PrimaryFactor | PrimaryFactor ">>" PrimaryFactor | PrimaryFactor '+' PrimaryFactor | PrimaryFactor '-' PrimaryFactor | PrimaryFactor '*' PrimaryFactor | PrimaryFactor '/' PrimaryFactor | PrimaryFactor '%' PrimaryFactor | PrimaryFactor "DIV" PrimaryFactor | PrimaryFactor "MOD" PrimaryFactor | PrimaryFactor '^' PrimaryFactor | PrimaryExpression PrimaryExpression: Operand | FunctionCallKeyword | FunctionCallNonKeyword | FunctionCallAgg | FunctionCallGeneric | Identifier jss stringLit | Identifier juss stringLit | SubSelect | '!' PrimaryExpression | '~' PrimaryExpression | '-' PrimaryExpression | '+' PrimaryExpression | "BINARY" PrimaryExpression | PrimaryExpression "COLLATE" StringName "}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/expression-syntax/", "title": "表达式语法", "content": " 表达式语法(Expression Syntax) 在 TiDB 中,以下规则是表达式的语法,你可以在 parser/parser.y 中找到定义。TiDB 的语法解析是基于 yacc 的。Expression: singleAtIdentifier assignmentEq Expression | Expression logOr Expression | Expression "XOR" Expression | Expression logAnd Expression | "NOT" Expression | Factor IsOrNotOp trueKwd | Factor IsOrNotOp falseKwd | Factor IsOrNotOp "UNKNOWN" | Factor Factor: Factor IsOrNotOp "NULL" | Factor CompareOp PredicateExpr | Factor CompareOp singleAtIdentifier assignmentEq PredicateExpr | Factor CompareOp AnyOrAll SubSelect | PredicateExpr PredicateExpr: PrimaryFactor InOrNotOp '(' ExpressionList ')' | PrimaryFactor InOrNotOp SubSelect | PrimaryFactor BetweenOrNotOp PrimaryFactor "AND" PredicateExpr | PrimaryFactor LikeOrNotOp PrimaryExpression LikeEscapeOpt | PrimaryFactor RegexpOrNotOp PrimaryExpression | PrimaryFactor PrimaryFactor: PrimaryFactor '|' PrimaryFactor | PrimaryFactor '&' PrimaryFactor | PrimaryFactor "<<" PrimaryFactor | PrimaryFactor ">>" PrimaryFactor | PrimaryFactor '+' PrimaryFactor | PrimaryFactor '-' PrimaryFactor | PrimaryFactor '*' PrimaryFactor | PrimaryFactor '/' PrimaryFactor | PrimaryFactor '%' PrimaryFactor | PrimaryFactor "DIV" PrimaryFactor | PrimaryFactor "MOD" PrimaryFactor | PrimaryFactor '^' PrimaryFactor | PrimaryExpression PrimaryExpression: Operand | FunctionCallKeyword | FunctionCallNonKeyword | FunctionCallAgg | FunctionCallGeneric | Identifier jss stringLit | Identifier juss stringLit | SubSelect | '!' PrimaryExpression | '~' PrimaryExpression | '-' PrimaryExpression | '+' PrimaryExpression | "BINARY" PrimaryExpression | PrimaryExpression "COLLATE" StringName "}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/expression-syntax/", "title": "表达式语法", "content": " 表达式语法(Expression Syntax) 在 TiDB 中,以下规则是表达式的语法,你可以在 parser/parser.y 中找到定义。TiDB 的语法解析是基于 yacc 的。Expression: singleAtIdentifier assignmentEq Expression | Expression logOr Expression | Expression "XOR" Expression | Expression logAnd Expression | "NOT" Expression | Factor IsOrNotOp trueKwd | Factor IsOrNotOp falseKwd | Factor IsOrNotOp "UNKNOWN" | Factor Factor: Factor IsOrNotOp "NULL" | Factor CompareOp PredicateExpr | Factor CompareOp singleAtIdentifier assignmentEq PredicateExpr | Factor CompareOp AnyOrAll SubSelect | PredicateExpr PredicateExpr: PrimaryFactor InOrNotOp '(' ExpressionList ')' | PrimaryFactor InOrNotOp SubSelect | PrimaryFactor BetweenOrNotOp PrimaryFactor "AND" PredicateExpr | PrimaryFactor LikeOrNotOp PrimaryExpression LikeEscapeOpt | PrimaryFactor RegexpOrNotOp PrimaryExpression | PrimaryFactor PrimaryFactor: PrimaryFactor '|' PrimaryFactor | PrimaryFactor '&' PrimaryFactor | PrimaryFactor "<<" PrimaryFactor | PrimaryFactor ">>" PrimaryFactor | PrimaryFactor '+' PrimaryFactor | PrimaryFactor '-' PrimaryFactor | PrimaryFactor '*' PrimaryFactor | PrimaryFactor '/' PrimaryFactor | PrimaryFactor '%' PrimaryFactor | PrimaryFactor "DIV" PrimaryFactor | PrimaryFactor "MOD" PrimaryFactor | PrimaryFactor '^' PrimaryFactor | PrimaryExpression PrimaryExpression: Operand | FunctionCallKeyword | FunctionCallNonKeyword | FunctionCallAgg | FunctionCallGeneric | Identifier jss stringLit | Identifier juss stringLit | SubSelect | '!' PrimaryExpression | '~' PrimaryExpression | '-' PrimaryExpression | '+' PrimaryExpression | "BINARY" PrimaryExpression | PrimaryExpression "COLLATE" StringName "}, {"url": "https://pingcap.com/recruit-cn/business/tidb-dba/", "title": "资深/高级/中级 TiDB DBA", "content": " 资深/高级/中级 TiDB DBA 岗位职责: 负责对客户进行 TiDB 技术支持(线上为主),包括配置管理、升级、扩容、备份、数据迁移等工作。 负责用户 TiDB 集群监控、故障响应、问题跟踪及性能分析处理。 负责与用户进行需求沟通、技术培训,介绍 TiDB 的原理、使用方式、最佳实践等。 研究 TiDB,对某细分方向,如 TiDB 自动化管理、SQL 优化、故障诊断、数据迁移等有持续产出、贡献。 对各种数据库、大数据库技术栈进行调研、测试,对数据库生态工具(如数据迁移等)进行调研、测试,方案落地。 (可选)Ansible 开发,Docker & Kubernetes 的维护,脚本开发等 DevOps 工作。 任职要求: 3 年以上 DBA 相关工作经验(MySQL、Oracle、PostgreSQL 等),或者 3 年以上大数据工作经验(Hadoop、HBase、MongoDB 等)。 精通一种关系型数据库的(如 MySQL )配置、备份、优化、监控、管理。 熟悉 Linux 操作系统,如常用命令、文件系统、系统配置等,具有较强的故障定位和问题解决能力,有丰富处理重大故障的经历。 熟悉 shell、python、perl 等脚本语言,有 DevOPS 工作经验,或对 Ansible、Cloud、Docker、Prometheus 等技术领域有一定使用经验。 高度的责任心、良好的沟通技巧和团队合作精神. 对前沿技术有一定研究者,如分布式系统、ES、RocksDB 等加分,对 go、rust、raft 熟悉者加分。 待遇:10K - 35K,14薪 + 奖金,优秀者可面议工作地点:北京"}, {"url": "https://pingcap.com/recruit-cn/business/tidb-delivery-dba/", "title": "资深/高级/中级 TiDB 交付 DBA", "content": " 资深/高级/中级 TiDB 交付 DBA 岗位职责: 负责客户 POC ,TiDB 项目落地、客户关系、项目管理; 负责与用户进行需求沟通、技术培训,介绍 TiDB 的原理、使用方式、最佳实践等; 负责客户技术支持,包括配置管理、升级、扩容、备份、数据迁移等工作; 负责用户 TiDB 集群监控、故障响应、问题跟踪及性能分析处理; 负责 POC 相关文档编写、流程建设、优化; 研究 TiDB,对某细分方向,如 TiDB 自动化管理、SQL 优化、故障诊断等有持续产出、贡献。 任职要求: 3 年以上 DBA 或者 大数据工程师 相关工作经验(MySQL、Oracle、Hadoop等),2 年以上的企业服务工作经验; 精通一种关系型数据库的(如 MySQL )配置、备份、优化、监控、管理; 熟悉 Linux 操作系统,如常用命令、文件系统、系统配置等,具有较强的故障定位和问题解决能力,有丰富处理重大故障的经历; 丰富的项目管理、项目实施经验,能够独立完成数据库架构设计,标准化建设及 POC 文档编写; 良好的沟通、技术演讲、资源协调能力,高度的责任心和团队合作精神; 对某一行业比较熟悉,有丰富的企业服务、管理经验。 待遇:10K - 35K,14薪 + 奖金,优秀者可面议工作地点:北京,上海,广州,深圳,杭州,成都"}, {"url": "https://pingcap.com/recruit-cn/business/internet-architect/", "title": "资深互联网架构师", "content": " 资深互联网架构师 岗位职责: 负责 TiDB 技术推广,步道; 负责互联网用户的技术交流、数据库架构设计; 作为桥梁连通 TiDB 用户与开发,反馈、整理用户需求,调研主流技术和方案; 与社区、市场部门密切配合,负责相关的沟通、技术支持、技术文档撰写等工作。 任职要求: 5 年以上主流互联网公司数据库、大数据等领域工作经历; 精通至少两种以上的数据库、大数据产品(如 MySQL、Oracle、各种 NoSQL 等); 对云计算、大数据及数据库前沿领域有深入的认识和实践; 熟悉互联网行业,对互联网业务发展、技术演变有比较深刻的理解; 优秀的技术演讲,技术文章编写,方案设计、用户交流经验; 工作条理性强,具有很强的责任心和团队合作精神。 待遇:Base 25K - 40K,13薪 + 期权 + 丰厚的业绩奖金,优秀者可面议工作地点:北京,上海,杭州"}, {"url": "https://pingcap.com/recruit-cn/business/presales-director/", "title": "资深售前技术总监", "content": " 资深售前技术总监 岗位职责: 负责组织制定公司数据库产品、数据库解决方案的技术方案编写、标书的准备、讲解及用户答疑等工作; 负责用户的技术交流、技术支持、POC 等工作,及合作伙伴厂商的技术交流; 和产品、市场部门密切配合,负责相关的沟通、技术支持、技术文档撰写等工作。 任职要求: 5 年以上 IT 领域售前工作经验; 熟悉传统商业数据库(如 Oracle)及开源数据库,对云计算、大数据及数据库前沿领域有深入的认识和实践; 熟悉 1~2个行业,熟悉行业发展方向、技术趋势、商务模式、行业主流 IT 供应商等,熟悉金融行业尤佳; 丰富的方案设计、标书应答、用户交流经验,良好的写作和口才、良好的沟通能力; 工作条理性强,具有很强的责任心和团队合作精神。 待遇:Base 25K - 40K,13薪 + 期权 + 丰厚的业绩奖金,优秀者可面议工作地点:北京,上海,杭州,广州,深圳,成都"}, {"url": "https://pingcap.com/recruit-cn/business/channel-sales-director/", "title": "资深渠道合作总监", "content": " 资深渠道合作总监 岗位职责: 根据公司产品(分布式数据库),负责相关合作伙伴的建立、维护、发展与管理; 制定相关合作伙伴的拓展计划,执行并完成相关合作伙伴拓展计划和销售任务; 配合销售及市场部门完成相关工作。 任职要求: 5 年以上软件行业渠道销售经验; 与主要 IT 系统集成商、行业应用软件开发商具有良好的合作关系,金融行业尤佳; 具有良好的渠道拓展能力和丰富的渠道资源和渠道管理经验; 具有数据库软件等基础软件渠道销售经验者优先,有技术背景优先; 强烈的责任心、良好的沟通能力、团队协作能力。 待遇:Base 25K - 40K,期权 + 丰厚的业绩奖金,优秀者可面议工作地点:北京"}, {"url": "https://pingcap.com/recruit-cn/business/sales-director/", "title": "资深行业销售总监", "content": " 资深行业销售总监 岗位职责: 负责分布式数据库产品的业务拓展、合作及销售; 完成整体业绩指标,包括销售额和回款额。 任职要求: 5 年以上 IT 软件产品(通用软件/行业应用软件)销售经验,出色的过往销售业绩; 有特定政企行业的客户和渠道资源,比如金融、制造业、电信等; 出众的沟通表达能力、抗压能力、管理能力,具有敬业精神及团队合作意识; 如有数据库技术经验或售前经验有加分。 待遇:Base 25K - 40K,期权 + 丰厚的业绩奖金,优秀者可面议工作地点:北京,上海,杭州,广州,深圳,成都"}, {"url": "https://pingcap.com/docs-cn/op-guide/cross-dc-deployment/", "title": "跨数据中心部署方案", "content": " 跨数据中心部署方案 作为 NewSQL 数据库,TiDB 兼顾了传统关系型数据库的优秀特性以及 NoSQL 数据库可扩展性,以及跨数据中心(下文简称“中心”)场景下的高可用。本文档旨在介绍跨数据中心部署的不同解决方案。三中心部署方案 TiDB, TiKV, PD 分别分布在 3 个不同的中心,这是最常规,可用性最高的方案。优点 所有数据的副本分布在三个数据中心,任何一个数据中心失效后,另外两个数据中心会自动发起 leader election,并在合理长的时间内(通常情况 20s 以内)恢复服务,并且不会产生数据丢失。缺点 性能受网络延迟影响。 对于写入的场景,所有写入的数据需要同步复制到至少 2 个数据中心,由于 TiDB 写入过程使用两阶段提交,故写入延迟至少需要 2 倍数据中心间的延迟。 对于读请求来说,如果数据 leader 与发起读取的 TiDB 节点不在同一个数据中心,也会受网络延迟影响。 TiDB 中的每个事务都需要向 PD leader 获取 TSO,当 TiDB 与 PD leader 不在同一个数据中心时,它上面运行的事务也会因此受网络延迟影响,每个有写入的事务会获取两次 TSO。 读性能优化 如果不需要每个数据中心同时对外提供服务,可以将业务流量全部派发到一个数据中心,并通过调度策略把 Region leader 和 PD leader 都迁移到同一个数据中心(我们在上文所述的测试中也做了这个优化)。这样一来,不管是从 PD 获取 TSO 还是读取 Region 都不受数据中心间网络的影响。当该数据中心失效后,PD leader 和 Region leader 会自动在其它数据中心选出,只需要把业务流量转移至其他存活的数据中心即可。两地三中心部署方案 两地三中心的方案与三数据中心类似,算是三机房方案根据业务特点进行的优化,区别是其中有两个数据中心距离很近(通常在同一个城市),网络延迟相对很小。这种场景下,我们可以把业务流量同时派发到同城的两个数据中心,同时控制 Region leader 和 PD leader 也分布在同城的两个数据中心。与三数据中心方案相比,两地三中心有以下优势: 写入速度更优 两中心同时提供服务资源利用率更高 依然能保证任何一个数据中心失效后保持可用并且不发生数据丢失 但是,缺陷是如果同城的两个数据中心同时失效(理论上讲要高于异地三数据中心损失 2 个的概率),将会导致不可用以及部分数据丢失。两数据中心 + binlog 同步方案 两数据中心 + binlog 同步类似于传统的 MySQL 中 master/slave 方案。两个数据中心分别部署一套完整的 TiDB 集群,我们称之为主集群和从集群。正常情况下所有的请求都在主集群,写入的数据通过 binlog 异步同步至从集群并写入。当主集群整个数据中心失效后,业务可以切换至从集群,与 MySQL 类似,这种情况下会有一些数据缺失。对比 MySQL,这个方案的优势是数据中心内的 HA – 少部分节点故障时,通过重新选举 leader 自动恢复服务,不需要人工干预。另外部分用户采用这种方式做双数据中心多活,两个数据中心各有一个集群,将业务分为两个库,每个库服务一部分数据,每个数据中心的业务只会访问一个库,两个集群之间通过 binlog 将本数据中心业务所涉及的库中的数据变更同步到对端机房,形成环状备份。注意:在两数据中心 + binlog 同步部署方案中,数据中心之间只有 binlog 异步复制。在数据中心间的延迟较高的情况下,从集群落后主集群的数据量会增大。当主集群故障后(DR),会造成数据丢失,丢失的数据量受网络延迟等因素影响。高可用和容灾分析 对于三数据中心方案和两地三中心方案,我们能得到的保障是任意一个数据中心故障时,集群能自动恢复服务,不需要人工介入,并能保证数据一致性。注意各种调度策略都是用于帮助性能优化的,当发生故障时调度机制总是第一优先考虑可用性而不是性能。对于两数据中心 + binlog 同步的方案,主集群内少量节点故障时也能自动恢复服务,不需要人工介入,并能保证数据一致性。当整个主集群故障时,需要人工切换至从集群,并可能发生一些数据丢失,数据丢失的数量取决于同步延迟,和网络条件有关。"}, {"url": "https://pingcap.com/docs-cn/v1.0/op-guide/location-awareness/", "title": "跨机房部署方案", "content": " 跨机房部署方案 概述 PD 能够根据 TiKV 集群的拓扑结构进行调度,使得 TiKV 的容灾能力最大化。阅读本章前,请先确保阅读 Binary 部署方案 和 Docker 部署方案。TiKV 上报拓扑信息 可以通过 TiKV 的启动参数或者配置文件来让 TiKV 上报拓扑信息给 PD。假设拓扑结构分为三级:zone > rack > host,可以通过 labels 来指定这些信息。启动参数:tikv-server --labels zone=<zone>,rack=<rack>,host=<host> 配置文件:[server] labels = "zone=<zone>,rack=<rack>,host=<host>" PD 理解 TiKV 拓扑结构 可以通过 PD 的配置文件让 PD 理解 TiKV 集群的拓扑结构。[replication] max-replicas = 3 location-labels = ["zone", "rack", "host"] 其中 location-labels 需要与 TiKV 的 labels 名字对应,这样 PD 才能知道这些 labels 代表了 TiKV 的拓扑结构。PD 基于 TiKV 拓扑结构进行调度 PD 能够根据我们提供的拓扑信息作出最优的调度,我们只需要关心什么样的拓扑结构能够达到我们想要的效果。假设我们使用三副本,并且希望一个数据中心挂掉的情况下能够正常服务,我们至少需要四个数据中心 (理论上三个数据中心即可,但是当前实现无法保证)。假设我们有四个数据中心 (zone),每个数据中心有两个机架 (rack),每个机架上有两个主机 (host)。 每个主机上面启动一个 TiKV 实例:# zone=z1 tikv-server --labels zone=z1,rack=r1,host=h1 tikv-server --labels zone=z1,rack=r1,host=h2 tikv-server --labels zone=z1,rack=r2,host=h1 tikv-server --labels zone=z1,rack=r2,host=h2 # zone=z2 tikv-server --labels zone=z2,rack=r1,host=h1 tikv-server --labels zone=z2,rack=r1,host=h2 tikv-server --labels zone=z2,rack=r2,host=h1 tikv-server --labels zone=z2,rack=r2,host=h2 # zone=z3 tikv-server --labels zone=z3,rack=r1,host=h1 tikv-server --labels zone=z3,rack=r1,host=h2 tikv-server --labels zone=z3,rack=r2,host=h1 tikv-server --labels zone=z3,rack=r2,host=h2 # zone=z4 tikv-server --labels zone=z4,rack=r1,host=h1 tikv-server --labels zone=z4,rack=r1,host=h2 tikv-server --labels zone=z4,rack=r2,host=h1 tikv-server --labels zone=z4,rack=r2,host=h2 也就是说,我们有 16 个 TiKV 实例,分布在 4 个不同的数据中心,8 个不同的机架,16 个不同的机器。在这种拓扑结构下,PD 会优先把每一份数据的不同副本调度到不同的数据中心。 这时候如果其中一个数据中心挂了,不会影响正常服务。 如果这个数据中心一段时间内恢复不了,PD 会把这个数据中心的副本迁移出去。总的来说,PD 能够根据当前的拓扑结构使得集群容灾能力最大化,所以如果我们希望达到某个级别的容灾能力, 就需要根据拓扑机构在不同的地理位置提供多于备份数 (max-replicas) 的机器。"}, {"url": "https://pingcap.com/docs-cn/v2.0/op-guide/location-awareness/", "title": "跨机房部署方案", "content": " 跨机房部署方案 概述 PD 能够根据 TiKV 集群的拓扑结构进行调度,使得 TiKV 的容灾能力最大化。阅读本章前,请先确保阅读 Binary 部署方案 和 Docker 部署方案。TiKV 上报拓扑信息 可以通过 TiKV 的启动参数或者配置文件来让 TiKV 上报拓扑信息给 PD。假设拓扑结构分为三级:zone > rack > host,可以通过 labels 来指定这些信息。启动参数:tikv-server --labels zone=<zone>,rack=<rack>,host=<host> 配置文件:[server] labels = "zone=<zone>,rack=<rack>,host=<host>" PD 理解 TiKV 拓扑结构 可以通过 PD 的配置文件让 PD 理解 TiKV 集群的拓扑结构。[replication] max-replicas = 3 location-labels = ["zone", "rack", "host"] 其中 location-labels 需要与 TiKV 的 labels 名字对应,这样 PD 才能知道这些 labels 代表了 TiKV 的拓扑结构。PD 基于 TiKV 拓扑结构进行调度 PD 能够根据我们提供的拓扑信息作出最优的调度,我们只需要关心什么样的拓扑结构能够达到我们想要的效果。假设我们使用三副本,并且希望一个数据中心挂掉的情况下能够正常服务,我们至少需要四个数据中心 (理论上三个数据中心即可,但是当前实现无法保证)。假设我们有四个数据中心 (zone),每个数据中心有两个机架 (rack),每个机架上有两个主机 (host)。 每个主机上面启动一个 TiKV 实例:# zone=z1 tikv-server --labels zone=z1,rack=r1,host=h1 tikv-server --labels zone=z1,rack=r1,host=h2 tikv-server --labels zone=z1,rack=r2,host=h1 tikv-server --labels zone=z1,rack=r2,host=h2 # zone=z2 tikv-server --labels zone=z2,rack=r1,host=h1 tikv-server --labels zone=z2,rack=r1,host=h2 tikv-server --labels zone=z2,rack=r2,host=h1 tikv-server --labels zone=z2,rack=r2,host=h2 # zone=z3 tikv-server --labels zone=z3,rack=r1,host=h1 tikv-server --labels zone=z3,rack=r1,host=h2 tikv-server --labels zone=z3,rack=r2,host=h1 tikv-server --labels zone=z3,rack=r2,host=h2 # zone=z4 tikv-server --labels zone=z4,rack=r1,host=h1 tikv-server --labels zone=z4,rack=r1,host=h2 tikv-server --labels zone=z4,rack=r2,host=h1 tikv-server --labels zone=z4,rack=r2,host=h2 也就是说,我们有 16 个 TiKV 实例,分布在 4 个不同的数据中心,8 个不同的机架,16 个不同的机器。在这种拓扑结构下,PD 会优先把每一份数据的不同副本调度到不同的数据中心。 这时候如果其中一个数据中心挂了,不会影响正常服务。 如果这个数据中心一段时间内恢复不了,PD 会把这个数据中心的副本迁移出去。总的来说,PD 能够根据当前的拓扑结构使得集群容灾能力最大化,所以如果我们希望达到某个级别的容灾能力, 就需要根据拓扑机构在不同的地理位置提供多于备份数 (max-replicas) 的机器。"}, {"url": "https://pingcap.com/docs-cn/v1.0/op-guide/recommendation/", "title": "软件和硬件环境要求", "content": " TiDB 软件和硬件环境要求 概述 TiDB 作为一款开源分布式 NewSQL 数据库,可以很好的部署和运行在 Intel 架构服务器环境及主流虚拟化环境,并支持绝大多数的主流硬件网络。作为一款高性能数据库系统,TiDB 支持主流的 Linux 操作系统环境。Linux 操作系统版本要求 Linux 操作系统平台 版本 Red Hat Enterprise Linux 7.3 及以上 CentOS 7.3 及以上 Oracle Enterprise Linux 7.3 及以上 Ubuntu LTS 16.04 及以上 注: TiDB 只支持 Red Hat 兼容内核 (RHCK) 的 Oracle Enterprise Linux,不支持 Oracle Enterprise Linux 提供的 Unbreakable Enterprise Kernel。 TiDB 对 Linux 操作系统的以上支持包括部署和运行在物理服务器以及 VMware、KVM、XEN 主流虚拟化环境。 服务器要求 TiDB 支持部署和运行在 Intel x86-64 架构的 64 位通用硬件服务器平台。对于开发,测试,及生产环境的服务器硬件配置有以下要求和建议:开发及测试环境 组件 CPU 内存 本地存储 网络 实例数量(最低要求) TiDB 8核+ 16 GB+ SAS, 200 GB+ 千兆网卡 1(可与 PD 同机器) PD 8核+ 16 GB+ SAS, 200 GB+ 千兆网卡 1(可与 TiDB 同机器) TiKV 8核+ 32 GB+ SSD, 200 GB+ 千兆网卡 3 服务器总计 4 注: 验证测试环境中的 TiDB 和 PD 可以部署在同一台服务器上。 如进行性能相关的测试,避免采用低性能存储和网络硬件配置,防止对测试结果的正确性产生干扰。 如果仅验证功能,建议使用 Docker Compose 部署方案单机进行测试。 生产环境 组件 CPU 内存 硬盘类型 网络 实例数量(最低要求) TiDB 16核+ 48 GB+ SAS 万兆网卡(2块最佳) 2 PD 8核+ 16 GB+ SSD 万兆网卡(2块最佳) 3 TiKV 16核+ 48 GB+ SSD 万兆网卡(2块最佳) 3 监控 8核+ 16 GB+ SAS 千兆网卡 1 服务器总计 9 注: 生产环境中的 TiDB 和 PD 可以部署和运行在同服务器上,如对性能和可靠性有更高的要求,应尽可能分开部署。 生产环境强烈推荐使用更高的配置。 TiKV 硬盘大小建议不要超过 800G 以防止硬盘损坏时,数据恢复耗时过长 网络要求 TiDB 作为开源分布式 NewSQL 数据库,其正常运行需要网络环境提供如下的网络端口配置要求,管理员可根据实际环境中 TiDB 组件部署的方案,在网络侧和主机侧启用相关端口: 组件 默认端口 说明 TiDB 4000 应用及 DBA 工具访问通信端口 TiDB 10080 TiDB 状态信息上报通信端口 TiKV 20160 TiKV 通信端口 PD 2379 提供 TiDB 和 PD 通信端口 PD 2380 PD 集群节点间通信端口 Prometheus 9090 Prometheus 服务通信端口 Pushgateway 9091 TiDB, TiKV, PD 监控聚合和上报端口 Node_exporter 9100 TiDB 集群每个节点的系统信息上报通信端口 Grafana 3000 Web 监控服务对外服务和客户端(浏览器)访问端口 客户端 Web 浏览器要求 TiDB 提供了基于 Prometheus 和 Grafana 技术平台作为 TiDB 分布式数据库集群的可视化监控数据展现方案。建议用户采用高版本的微软 IE, Google Chrome,Mozilla Firefox 访问 Grafana 监控入口。"}, {"url": "https://pingcap.com/docs-cn/v2.0/op-guide/recommendation/", "title": "软件和硬件环境要求", "content": " TiDB 软件和硬件环境要求 概述 TiDB 作为一款开源分布式 NewSQL 数据库,可以很好的部署和运行在 Intel 架构服务器环境及主流虚拟化环境,并支持绝大多数的主流硬件网络。作为一款高性能数据库系统,TiDB 支持主流的 Linux 操作系统环境。Linux 操作系统版本要求 Linux 操作系统平台 版本 Red Hat Enterprise Linux 7.3 及以上 CentOS 7.3 及以上 Oracle Enterprise Linux 7.3 及以上 Ubuntu LTS 16.04 及以上 注: TiDB 只支持 Red Hat 兼容内核 (RHCK) 的 Oracle Enterprise Linux,不支持 Oracle Enterprise Linux 提供的 Unbreakable Enterprise Kernel。 TiDB 对 Linux 操作系统的以上支持包括部署和运行在物理服务器以及 VMware、KVM、XEN 主流虚拟化环境。 服务器要求 TiDB 支持部署和运行在 Intel x86-64 架构的 64 位通用硬件服务器平台。对于开发,测试,及生产环境的服务器硬件配置有以下要求和建议:开发及测试环境 组件 CPU 内存 本地存储 网络 实例数量(最低要求) TiDB 8核+ 16 GB+ SAS, 200 GB+ 千兆网卡 1(可与 PD 同机器) PD 8核+ 16 GB+ SAS, 200 GB+ 千兆网卡 1(可与 TiDB 同机器) TiKV 8核+ 32 GB+ SSD, 200 GB+ 千兆网卡 3 服务器总计 4 注: 验证测试环境中的 TiDB 和 PD 可以部署在同一台服务器上。 如进行性能相关的测试,避免采用低性能存储和网络硬件配置,防止对测试结果的正确性产生干扰。 如果仅验证功能,建议使用 Docker Compose 部署方案单机进行测试。 生产环境 组件 CPU 内存 硬盘类型 网络 实例数量(最低要求) TiDB 16核+ 48 GB+ SAS 万兆网卡(2块最佳) 2 PD 8核+ 16 GB+ SSD 万兆网卡(2块最佳) 3 TiKV 16核+ 48 GB+ SSD 万兆网卡(2块最佳) 3 监控 8核+ 16 GB+ SAS 千兆网卡 1 服务器总计 9 注: 生产环境中的 TiDB 和 PD 可以部署和运行在同服务器上,如对性能和可靠性有更高的要求,应尽可能分开部署。 生产环境强烈推荐使用更高的配置。 TiKV 硬盘大小建议不要超过 800G 以防止硬盘损坏时,数据恢复耗时过长 网络要求 TiDB 作为开源分布式 NewSQL 数据库,其正常运行需要网络环境提供如下的网络端口配置要求,管理员可根据实际环境中 TiDB 组件部署的方案,在网络侧和主机侧启用相关端口: 组件 默认端口 说明 TiDB 4000 应用及 DBA 工具访问通信端口 TiDB 10080 TiDB 状态信息上报通信端口 TiKV 20160 TiKV 通信端口 PD 2379 提供 TiDB 和 PD 通信端口 PD 2380 PD 集群节点间通信端口 Prometheus 9090 Prometheus 服务通信端口 Pushgateway 9091 TiDB, TiKV, PD 监控聚合和上报端口 Node_exporter 9100 TiDB 集群每个节点的系统信息上报通信端口 Grafana 3000 Web 监控服务对外服务和客户端(浏览器)访问端口 客户端 Web 浏览器要求 TiDB 提供了基于 Prometheus 和 Grafana 技术平台作为 TiDB 分布式数据库集群的可视化监控数据展现方案。建议用户采用高版本的微软 IE, Google Chrome,Mozilla Firefox 访问 Grafana 监控入口。"}, {"url": "https://pingcap.com/docs-cn/sql/connection-and-APIs/", "title": "连接器和 API", "content": " 连接器和 API 数据库连接器为客户端提供了连接数据库服务端的方式,APIs 提供了使用 MySQL 协议和资源的底层接口。无论是连接器还是 API,都可以用来在不同的语言和环境内连接服务器并执行 sql 语句,包括 odbc、java(jdbc)、Perl、Python、PHP、Ruby 和 C。TiDB 兼容 MySQL(5.6、5.7) 的所有连接器和 API,包括: MySQL Connector/C MySQL Connector/C++ MySQL Connector/J MySQL Connector/Net MySQL Connector/ODBC MySQL Connector/Python MySQL C API MySQL PHP API MySQL Perl API MySQL Python API MySQL Ruby APIs MySQL Tcl API MySQL Eiffel Wrapper Mysql Go API 使用 MySQL 连接器连接 TiDB Oracle 官方提供了以下 API,TiDB 可以兼容所有这些 API。 MySQL Connector/C:C 语言的客户端库,是 libmysqlclient 的替代品 MySQL Connector/C++:C++ 语言的客户端库 MySQL Connector/J:Java 语言的客户端库,基于标准 JDBC 接口 MySQL Connector/Net:.Net 语言的客户端库,MySQL for Visual Studio使用这个库,支持 Microsoft Visual Studio 2012,2013,2015和2017版本 MySQL Connector/ODBC:标准的 ODBC 接口,支持 Windows,Unix 和 OS X MySQL Connector/Python:Python 语言的客户端包,和 Python DB API version 2.0 一致 使用 MySQL C API 连接 TiDB 如果使用 C 语言程序直接连接 TiDB,可以直接链接 libmysqlclient 库,使用 MySQL 的 C API,这是最主要的一种 C 语言连接方式,被各种客户端和 API 广泛使用,包括 Connector/C。使用 MySQL 第三方 API 连接 TiDB 第三方 API 非 Oracle 官方提供,下表列出了常用的第三方 API: Environment API Type Notes Ada GNU Ada MySQL Bindings libmysqlclient See MySQL Bindings for GNU Ada C C API libmysqlclient See Section 27.8, “MySQL C API”. C Connector/C Replacement for libmysqlclient See MySQL Connector/C Developer Guide. C++ Connector/C++ libmysqlclient See MySQL Connector/C++ Developer Guide. MySQL++ libmysqlclient See MySQL++ Web site. MySQL wrapped libmysqlclient See MySQL wrapped. Go go-sql-driver Native Driver See Mysql Go API Cocoa MySQL-Cocoa libmysqlclient Compatible with the Objective-C Cocoa environment. Seehttp://mysql-cocoa.sourceforge.net/ D MySQL for D libmysqlclient See MySQL for D. Eiffel Eiffel MySQL libmysqlclient See Section 27.14, “MySQL Eiffel Wrapper”. Erlang erlang-mysql-driver libmysqlclient See erlang-mysql-driver. Haskell Haskell MySQL Bindings Native Driver See Brian O’Sullivan’s pure Haskell MySQL bindings. hsql-mysql libmysqlclient See MySQL driver for Haskell. Java/JDBC Connector/J Native Driver See MySQL Connector/J 5.1 Developer Guide. Kaya MyDB libmysqlclient See MyDB. Lua LuaSQL libmysqlclient See LuaSQL. .NET/Mono Connector/Net Native Driver See MySQL Connector/Net Developer Guide. Objective Caml OBjective Caml MySQL Bindings libmysqlclient See MySQL Bindings for Objective Caml. Octave Database bindings for GNU Octave libmysqlclient See Database bindings for GNU Octave. ODBC Connector/ODBC libmysqlclient See MySQL Connector/ODBC Developer Guide. Perl DBI/DBD::mysql libmysqlclient See Section 27.10, “MySQL Perl API”. Net::MySQL Native Driver See Net::MySQL at CPAN PHP mysql, ext/mysqlinterface (deprecated) libmysqlclient See Original MySQL API. mysqli, ext/mysqliinterface libmysqlclient See MySQL Improved Extension. PDO_MYSQL libmysqlclient See MySQL Functions (PDO_MYSQL). PDO mysqlnd Native Driver Python Connector/Python Native Driver See MySQL Connector/Python Developer Guide. Python Connector/Python C Extension libmysqlclient See MySQL Connector/Python Developer Guide. MySQLdb libmysqlclient See Section 27.11, “MySQL Python API”. Ruby MySQL/Ruby libmysqlclient Uses libmysqlclient. See Section 27.12.1, “The MySQL/Ruby API”. Ruby/MySQL Native Driver See Section 27.12.2, “The Ruby/MySQL API”. Scheme Myscsh libmysqlclient See Myscsh. SPL sql_mysql libmysqlclient See sql_mysql for SPL. Tcl MySQLtcl libmysqlclient See Section 27.13, “MySQL Tcl API”. TiDB 支持的连接器版本 Connector Connector version Connector/C 6.1.0 GA Connector/C++ 1.0.5 GA Connector/J 5.1.8 Connector/Net 6.9.9 GA Connector/Net 6.8.8 GA Connector/ODBC 5.1 Connector/ODBC 3.51 (Unicode not supported) Connector/Python 2.0 Connector/Python 1.2 "}, {"url": "https://pingcap.com/docs-cn/v1.0/op-guide/dashboard-overview-info/", "title": "重要监控指标详解", "content": " 重要监控指标详解 使用 ansible 部署 tidb 集群时,一键部署监控系统 (prometheus/grafana),监控架构请看 TiDB 监控框架概述目前 grafana dashboard 整体分为四个 dashboard,node_export,PD,TIDB,TIKV。 内容较多,主要在于尽快让 TIDB 开发确认问题。对于日常运维,我们单独挑选出重要的 metrics 放在 overview 页面,方便日常运维人员观察集群组件(PD, TIDB, TIKV)使用状态以及集群使用状态 。以下为 overview dashboard 说明:说明 PD Storage Capacity : tidb 集群总可用数据库空间大小 Current Storage Size : tidb 集群目前已用数据库空间大小 Store Status – up store : tikv 正常节点数量 Store Status – down store : tikv 异常节点数量如果大于0,证明有节点不正常 Store Status – offline store : 手动执行下线操作tikv节点数量 Store Status – Tombstone store : 下线成功的tikv节点数量 Current storage usage : tikv 集群存储空间占用率超过 80% 应考虑添加 tikv 节点 99% completed_cmds_duration_seconds : 99% pd-server 请求完成时间小于 5ms average completed_cmds_duration_seconds : pd-server 请求平均完成时间小于 50ms leader balance ratio : leader ratio 最大的节点与最小的节点的差均衡状况下一般小于 5%,节点重启时会比较大 region balance ratio : region ratio 最大的节点与最小的节点的差均衡状况下一般小于 5%,新增/下线节点时会比较大 TiDB handle_requests_duration_seconds : 请求PD获取TSO响应时间小于100ms tidb server QPS : 集群的请求量和业务相关 connection count : 从业务服务器连接到数据库的连接数和业务相关。但是如果连接数发生跳变,需要查明原因。比如突然掉为0,可以检查网络是否中断;如果突然上涨,需要检查业务。 statement count : 单位时间内不同类型语句执行的数目这个和业务相关 Query Duration 99th percentile : 99% 的query时间 TiKV 99% & 99.99% scheduler command duration : 99% & 99.99% 命令执行的时间99% 小于 50ms;99.99% 小于100ms 95% & 99% storage async_request duration : 95% & 99% Raft 命令执行时间95% 小于 50ms;99% 小于100ms server report failure message : 发送失败或者收到了错误的 message如果出现了大量的 unreachadble 的消息,表明系统网络出现了问题。如果有 store not match 这样的错误,表明收到了不属于这个集群发过来的消息 Vote : Raft vote 的频率通常这个值只会在发生 split 的时候有变动,如果长时间出现了 vote 偏高的情况,证明系统出现了严重的问题,有一些节点无法工作了 95% & 99% coprocessor request duration : 95% & 99% coprocessor 执行时间和业务相关,但通常不会出现持续高位的值 Pending task : 累积的任务数量除了 pd worker,其他任何偏高都属于异常 stall : RocksDB Stall 时间大于 0,表明 RocksDB 忙不过来,需要注意 IO 和 CPU 了 channel full : channel 满了,表明线程太忙无法处理如果大于 0,表明线程已经没法处理了 95% send_message_duration_seconds : 95% 发送消息的时间小于50ms leader/region : 每个tikv的leader/region数量和业务相关 图例 "}, {"url": "https://pingcap.com/docs-cn/v2.0/op-guide/dashboard-overview-info/", "title": "重要监控指标详解", "content": " 重要监控指标详解 使用 ansible 部署 tidb 集群时,一键部署监控系统 (prometheus/grafana),监控架构请看 TiDB 监控框架概述目前 grafana dashboard 整体分为四个 dashboard,node_export,PD,TIDB,TIKV。 内容较多,主要在于尽快让 TIDB 开发确认问题。对于日常运维,我们单独挑选出重要的 metrics 放在 overview 页面,方便日常运维人员观察集群组件(PD, TIDB, TIKV)使用状态以及集群使用状态 。以下为 overview dashboard 说明:说明 PD Storage Capacity : tidb 集群总可用数据库空间大小 Current Storage Size : tidb 集群目前已用数据库空间大小 Store Status – up store : tikv 正常节点数量 Store Status – down store : tikv 异常节点数量如果大于0,证明有节点不正常 Store Status – offline store : 手动执行下线操作tikv节点数量 Store Status – Tombstone store : 下线成功的tikv节点数量 Current storage usage : tikv 集群存储空间占用率超过 80% 应考虑添加 tikv 节点 99% completed_cmds_duration_seconds : 99% pd-server 请求完成时间小于 5ms average completed_cmds_duration_seconds : pd-server 请求平均完成时间小于 50ms leader balance ratio : leader ratio 最大的节点与最小的节点的差均衡状况下一般小于 5%,节点重启时会比较大 region balance ratio : region ratio 最大的节点与最小的节点的差均衡状况下一般小于 5%,新增/下线节点时会比较大 TiDB handle_requests_duration_seconds : 请求PD获取TSO响应时间小于100ms tidb server QPS : 集群的请求量和业务相关 connection count : 从业务服务器连接到数据库的连接数和业务相关。但是如果连接数发生跳变,需要查明原因。比如突然掉为0,可以检查网络是否中断;如果突然上涨,需要检查业务。 statement count : 单位时间内不同类型语句执行的数目这个和业务相关 Query Duration 99th percentile : 99% 的query时间 TiKV 99% & 99.99% scheduler command duration : 99% & 99.99% 命令执行的时间99% 小于 50ms;99.99% 小于100ms 95% & 99% storage async_request duration : 95% & 99% Raft 命令执行时间95% 小于 50ms;99% 小于100ms server report failure message : 发送失败或者收到了错误的 message如果出现了大量的 unreachadble 的消息,表明系统网络出现了问题。如果有 store not match 这样的错误,表明收到了不属于这个集群发过来的消息 Vote : Raft vote 的频率通常这个值只会在发生 split 的时候有变动,如果长时间出现了 vote 偏高的情况,证明系统出现了严重的问题,有一些节点无法工作了 95% & 99% coprocessor request duration : 95% & 99% coprocessor 执行时间和业务相关,但通常不会出现持续高位的值 Pending task : 累积的任务数量除了 pd worker,其他任何偏高都属于异常 stall : RocksDB Stall 时间大于 0,表明 RocksDB 忙不过来,需要注意 IO 和 CPU 了 channel full : channel 满了,表明线程太忙无法处理如果大于 0,表明线程已经没法处理了 95% send_message_duration_seconds : 95% 发送消息的时间小于50ms leader/region : 每个tikv的leader/region数量和业务相关 图例 "}, {"url": "https://pingcap.com/docs-cn/sql/error/", "title": "错误码与故障诊断", "content": " 错误码与故障诊断 本篇文档描述在使用 TiDB 过程中会遇到的问题以及解决方法。错误码 TiDB 兼容 MySQL 的错误码,在大多数情况下,返回和 MySQL 一样的错误码。另外还有一些特有的错误码: 错误码 说明 8001 请求使用的内存超过 TiDB 内存使用的阈值限制 8002 带有 SELECT FOR UPDATE 语句的事务,在遇到写入冲突时,为保证一致性无法进行重试,事务将进行回滚并返回该错误 8003 ADMIN CHECK TABLE 命令在遇到行数据跟索引不一致的时候返回该错误 9001 请求 PD 超时,请检查 PD Server 状态/监控/日志以及 TiDB Server 与 PD Server 之间的网络 9002 请求 TiKV 超时,请检查 TiKV Server 状态/监控/日志以及 TiDB Server 与 TiKV Server 之间的网络 9003 TiKV 操作繁忙,一般出现在数据库负载比较高时,请检查 TiKV Server 状态/监控/日志 9004 当数据库上承载的业务存在大量的事务冲突时,会遇到这种错误,请检查业务代码 9005 某个 Raft Group 不可用,如副本数目不足,出现在 TiKV 比较繁忙或者是 TiKV 节点停机的时候,请检查 TiKV Server 状态/监控/日志 9006 GC Life Time 间隔时间过短,长事务本应读到的数据可能被清理了,应增加GC Life Time 9500 单个事务过大,原因及解决方法请参考这里 故障诊断 参见故障诊断文档以及 FAQ。"}, {"url": "https://pingcap.com/docs-cn/v1.0/sql/error/", "title": "错误码与故障诊断", "content": " 错误码与故障诊断 本篇文档描述在使用 TiDB 过程中会遇到的问题以及解决方法。错误码 TiDB 兼容 MySQL 的错误码,在大多数情况下,返回和 MySQL 一样的错误码。另外还有一些特有的错误码: 错误码 说明 9001 请求 PD 超时,请检查 PD Server 状态/监控/日志以及 TiDB Server 与 PD Server 之间的网络 9002 请求 TiKV 超时,请检查 TiKV Server 状态/监控/日志以及 TiDB Server 与 TiKV Server 之间的网络 9003 TiKV 操作繁忙,一般出现在数据库负载比较高时,请检查 TiKV Server 状态/监控/日志 9004 当数据库上承载的业务存在大量的事务冲突时,会遇到这种错误,请检查业务代码 9005 某个 Raft Group 不可用,如副本数目不足,出现在 TiKV 比较繁忙或者是 TiKV 节点停机的时候,请检查 TiKV Server 状态/监控/日志 9006 GC Life Time 间隔时间过短,长事务本应读到的数据可能被清理了,应增加GC Life Time 9500 单个事务过大,原因及解决方法请参考这里 故障诊断 参见故障诊断文档以及 FAQ。"}, {"url": "https://pingcap.com/docs-cn/v2.0/sql/error/", "title": "错误码与故障诊断", "content": " 错误码与故障诊断 本篇文档描述在使用 TiDB 过程中会遇到的问题以及解决方法。错误码 TiDB 兼容 MySQL 的错误码,在大多数情况下,返回和 MySQL 一样的错误码。另外还有一些特有的错误码: 错误码 说明 9001 请求 PD 超时,请检查 PD Server 状态/监控/日志以及 TiDB Server 与 PD Server 之间的网络 9002 请求 TiKV 超时,请检查 TiKV Server 状态/监控/日志以及 TiDB Server 与 TiKV Server 之间的网络 9003 TiKV 操作繁忙,一般出现在数据库负载比较高时,请检查 TiKV Server 状态/监控/日志 9004 当数据库上承载的业务存在大量的事务冲突时,会遇到这种错误,请检查业务代码 9005 某个 Raft Group 不可用,如副本数目不足,出现在 TiKV 比较繁忙或者是 TiKV 节点停机的时候,请检查 TiKV Server 状态/监控/日志 9006 GC Life Time 间隔时间过短,长事务本应读到的数据可能被清理了,应增加GC Life Time 9500 单个事务过大,原因及解决方法请参考这里 故障诊断 参见故障诊断文档以及 FAQ。"}, {"url": "https://pingcap.com/docs-cn/op-guide/location-awareness/", "title": "集群拓扑信息配置", "content": " 集群拓扑信息配置 概述 PD 能够根据 TiKV 集群的拓扑结构进行调度,使得 TiKV 的容灾能力最大化。阅读本章前,请先确保阅读 Ansible 部署方案 和 Docker 部署方案。TiKV 上报拓扑信息 可以通过 TiKV 的启动参数或者配置文件来让 TiKV 上报拓扑信息给 PD。假设拓扑结构分为三级:zone > rack > host,可以通过 labels 来指定这些信息。启动参数:tikv-server --labels zone=<zone>,rack=<rack>,host=<host> 配置文件:[server] labels = "zone=<zone>,rack=<rack>,host=<host>" PD 理解 TiKV 拓扑结构 可以通过 PD 的配置文件让 PD 理解 TiKV 集群的拓扑结构。[replication] max-replicas = 3 location-labels = ["zone", "rack", "host"] 其中 location-labels 需要与 TiKV 的 labels 名字对应,这样 PD 才能知道这些 labels 代表了 TiKV 的拓扑结构。PD 基于 TiKV 拓扑结构进行调度 PD 能够根据我们提供的拓扑信息作出最优的调度,我们只需要关心什么样的拓扑结构能够达到我们想要的效果。假设我们使用三副本,并且希望一个数据中心挂掉的情况下,还能继续保持 TiDB 集群的高可用状态,我们至少需要四个数据中心。假设我们有四个数据中心 (zone),每个数据中心有两个机架 (rack),每个机架上有两个主机 (host)。 每个主机上面启动一个 TiKV 实例:# zone=z1 tikv-server --labels zone=z1,rack=r1,host=h1 tikv-server --labels zone=z1,rack=r1,host=h2 tikv-server --labels zone=z1,rack=r2,host=h1 tikv-server --labels zone=z1,rack=r2,host=h2 # zone=z2 tikv-server --labels zone=z2,rack=r1,host=h1 tikv-server --labels zone=z2,rack=r1,host=h2 tikv-server --labels zone=z2,rack=r2,host=h1 tikv-server --labels zone=z2,rack=r2,host=h2 # zone=z3 tikv-server --labels zone=z3,rack=r1,host=h1 tikv-server --labels zone=z3,rack=r1,host=h2 tikv-server --labels zone=z3,rack=r2,host=h1 tikv-server --labels zone=z3,rack=r2,host=h2 # zone=z4 tikv-server --labels zone=z4,rack=r1,host=h1 tikv-server --labels zone=z4,rack=r1,host=h2 tikv-server --labels zone=z4,rack=r2,host=h1 tikv-server --labels zone=z4,rack=r2,host=h2 也就是说,我们有 16 个 TiKV 实例,分布在 4 个不同的数据中心,8 个不同的机架,16 个不同的机器。在这种拓扑结构下,PD 会优先把每一份数据的不同副本调度到不同的数据中心。 这时候如果其中一个数据中心挂了,不会影响 TiDB 集群的高可用状态。 如果这个数据中心一段时间内恢复不了,PD 会把这个数据中心的副本迁移出去。总的来说,PD 能够根据当前的拓扑结构使得集群容灾能力最大化,所以如果我们希望达到某个级别的容灾能力, 就需要根据拓扑机构在不同的地理位置提供多于备份数 (max-replicas) 的机器。"}, {"url": "https://pingcap.com/", "title": "首页", "content": ""}, {"url": "https://pingcap.com/recruit-cn/business/olap-ops-engineer/", "title": "高级大数据平台工程师", "content": " 高级大数据平台工程师 岗位职责: 负责对客户进行 TiDB、TiSpark、列存引擎(theflash)的技术支持,包括配置管理、升级、扩容、备份、数据迁移等工作。 负责用户 TiDB、TiSpark、列存引擎(theflash)集群监控、故障响应、问题跟踪及性能分析处理。 研究 Hadoop、HBase、Hive、Impala、Spark(streaming) 等集群和大数据调度系统,提供高可用、高效的大数据存储和计算支撑。 任职要求: 2 年以上大数据工作经验(Hadoop、HBase、Hive、Impala、Spark、Clickhouse 等); 熟悉 Linux 操作系统,如常用命令、文件系统、系统配置等,具有较强的故障定位和问题解决能力,有丰富处理重大故障的经历; 熟悉一种常见的关系型数据库的使用,如 Oracle、MySQL 等; 高度的责任心、良好的沟通技巧和团队合作精神; 研究最新的大数据技术,参与公司大数据平台的设计和支持; 具有从 0 搭建数据仓库技术架构经验者优先; 研究过 Hadoop、Hive、Spark 等源码者优先。 待遇:10K - 35K,14薪 + 奖金,优秀者可面议工作地点:北京"}]